winuser.h: Add some missing virtual key symbols.
[wine] / tools / widl / typegen.c
1 /*
2  * Format String Generator for IDL Compiler
3  *
4  * Copyright 2005-2006 Eric Kohl
5  * Copyright 2005-2006 Robert Shearman
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #ifdef HAVE_UNISTD_H
28 # include <unistd.h>
29 #endif
30 #include <string.h>
31 #include <assert.h>
32 #include <ctype.h>
33 #include <signal.h>
34 #include <limits.h>
35
36 #include "widl.h"
37 #include "utils.h"
38 #include "parser.h"
39 #include "header.h"
40 #include "windef.h"
41 #include "wine/list.h"
42
43 #include "widl.h"
44 #include "typegen.h"
45
46 static const func_t *current_func;
47 static const type_t *current_structure;
48
49 /* name of the structure variable for structure callbacks */
50 #define STRUCT_EXPR_EVAL_VAR "pS"
51
52 static struct list expr_eval_routines = LIST_INIT(expr_eval_routines);
53
54 struct expr_eval_routine
55 {
56     struct list entry;
57     const type_t *structure;
58     size_t structure_size;
59     const expr_t *expr;
60 };
61
62 static size_t type_memsize(const type_t *t, int ptr_level, const expr_t *array);
63 static size_t fields_memsize(const var_t *v);
64
65 static int compare_expr(const expr_t *a, const expr_t *b)
66 {
67     int ret;
68
69     if (a->type != b->type)
70         return a->type - b->type;
71
72     switch (a->type)
73     {
74         case EXPR_NUM:
75         case EXPR_HEXNUM:
76             return a->u.lval - b->u.lval;
77         case EXPR_IDENTIFIER:
78             return strcmp(a->u.sval, b->u.sval);
79         case EXPR_COND:
80             ret = compare_expr(a->ref, b->ref);
81             if (ret != 0)
82                 return ret;
83             ret = compare_expr(a->u.ext, b->u.ext);
84             if (ret != 0)
85                 return ret;
86             return compare_expr(a->ext2, b->ext2);
87         case EXPR_OR:
88         case EXPR_AND:
89         case EXPR_ADD:
90         case EXPR_SUB:
91         case EXPR_MUL:
92         case EXPR_DIV:
93         case EXPR_SHL:
94         case EXPR_SHR:
95             ret = compare_expr(a->ref, b->ref);
96             if (ret != 0)
97                 return ret;
98             return compare_expr(a->u.ext, b->u.ext);
99         case EXPR_NOT:
100         case EXPR_NEG:
101         case EXPR_PPTR:
102         case EXPR_CAST:
103         case EXPR_SIZEOF:
104             return compare_expr(a->ref, b->ref);
105         case EXPR_VOID:
106             return 0;
107     }
108     return -1;
109 }
110
111 #define WRITE_FCTYPE(file, fctype, typestring_offset) \
112     do { \
113         if (file) \
114             fprintf(file, "/* %2u */\n", typestring_offset); \
115         print_file((file), 2, "0x%02x,    /* " #fctype " */\n", RPC_##fctype); \
116     } \
117     while (0)
118
119 static int print_file(FILE *file, int indent, const char *format, ...)
120 {
121     va_list va;
122     int i, r;
123
124     if (!file) return 0;
125
126     va_start(va, format);
127     for (i = 0; i < indent; i++)
128         fprintf(file, "    ");
129     r = vfprintf(file, format, va);
130     va_end(va);
131     return r;
132 }
133
134 static inline int type_has_ref(const type_t *type)
135 {
136     return (type->type == 0 && type->ref);
137 }
138
139 static inline int is_base_type(unsigned char type)
140 {
141     switch (type)
142     {
143     case RPC_FC_BYTE:
144     case RPC_FC_CHAR:
145     case RPC_FC_USMALL:
146     case RPC_FC_SMALL:
147     case RPC_FC_WCHAR:
148     case RPC_FC_USHORT:
149     case RPC_FC_SHORT:
150     case RPC_FC_ULONG:
151     case RPC_FC_LONG:
152     case RPC_FC_HYPER:
153     case RPC_FC_IGNORE:
154     case RPC_FC_FLOAT:
155     case RPC_FC_DOUBLE:
156     case RPC_FC_ENUM16:
157     case RPC_FC_ENUM32:
158     case RPC_FC_ERROR_STATUS_T:
159     case RPC_FC_BIND_PRIMITIVE:
160         return TRUE;
161
162     default:
163         return FALSE;
164     }
165 }
166
167 static size_t write_procformatstring_var(FILE *file, int indent,
168     const var_t *var, int is_return, unsigned int *type_offset)
169 {
170     size_t size;
171     int ptr_level = var->ptr_level;
172     const type_t *type = var->type;
173
174     int is_in = is_attr(var->attrs, ATTR_IN);
175     int is_out = is_attr(var->attrs, ATTR_OUT);
176
177     if (!is_in && !is_out) is_in = TRUE;
178
179     if (ptr_level == 0 && type_has_ref(type))
180         type = type->ref;
181
182     if (ptr_level == 0 && !var->array && is_base_type(type->type))
183     {
184         if (is_return)
185             print_file(file, indent, "0x53,    /* FC_RETURN_PARAM_BASETYPE */\n");
186         else
187             print_file(file, indent, "0x4e,    /* FC_IN_PARAM_BASETYPE */\n");
188
189         switch(type->type)
190         {
191 #define CASE_BASETYPE(fctype) \
192         case RPC_##fctype: \
193             print_file(file, indent, "0x%02x,    /* " #fctype " */\n", RPC_##fctype); \
194             size = 2; /* includes param type prefix */ \
195             break
196
197         CASE_BASETYPE(FC_BYTE);
198         CASE_BASETYPE(FC_CHAR);
199         CASE_BASETYPE(FC_WCHAR);
200         CASE_BASETYPE(FC_USHORT);
201         CASE_BASETYPE(FC_SHORT);
202         CASE_BASETYPE(FC_ULONG);
203         CASE_BASETYPE(FC_LONG);
204         CASE_BASETYPE(FC_HYPER);
205         CASE_BASETYPE(FC_IGNORE);
206         CASE_BASETYPE(FC_USMALL);
207         CASE_BASETYPE(FC_SMALL);
208         CASE_BASETYPE(FC_FLOAT);
209         CASE_BASETYPE(FC_DOUBLE);
210         CASE_BASETYPE(FC_ERROR_STATUS_T);
211 #undef CASE_BASETYPE
212
213         case RPC_FC_BIND_PRIMITIVE:
214             print_file(file, indent, "0x%02x,    /* FC_IGNORE */\n", RPC_FC_IGNORE);
215             size = 2; /* includes param type prefix */
216             break;
217
218         default:
219             error("Unknown/unsupported type: %s (0x%02x)\n", var->name, type->type);
220             size = 0;
221         }
222     }
223     else
224     {
225         if (is_return)
226             print_file(file, indent, "0x52,    /* FC_RETURN_PARAM */\n");
227         else if (is_in && is_out)
228             print_file(file, indent, "0x50,    /* FC_IN_OUT_PARAM */\n");
229         else if (is_out)
230             print_file(file, indent, "0x51,    /* FC_OUT_PARAM */\n");
231         else
232             print_file(file, indent, "0x4d,    /* FC_IN_PARAM */\n");
233
234         print_file(file, indent, "0x01,\n");
235         print_file(file, indent, "NdrFcShort(0x%x),\n", *type_offset);
236         size = 4; /* includes param type prefix */
237     }
238     *type_offset += get_size_typeformatstring_var(var);
239     return size;
240 }
241
242 void write_procformatstring(FILE *file, const ifref_t *ifaces)
243 {
244     const ifref_t *iface = ifaces;
245     int indent = 0;
246     var_t *var;
247     unsigned int type_offset = 2;
248
249     print_file(file, indent, "static const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString =\n");
250     print_file(file, indent, "{\n");
251     indent++;
252     print_file(file, indent, "0,\n");
253     print_file(file, indent, "{\n");
254     indent++;
255
256     END_OF_LIST(iface);
257
258     for (; iface; iface = PREV_LINK(iface))
259     {
260         if (is_object(iface->iface->attrs) || is_local(iface->iface->attrs))
261             continue;
262
263         if (iface->iface->funcs)
264         {
265             func_t *func = iface->iface->funcs;
266             while (NEXT_LINK(func)) func = NEXT_LINK(func);
267             for (; func; func = PREV_LINK(func))
268             {
269                 /* emit argument data */
270                 if (func->args)
271                 {
272                     var = func->args;
273                     while (NEXT_LINK(var)) var = NEXT_LINK(var);
274                     while (var)
275                     {
276                         write_procformatstring_var(file, indent, var, FALSE,
277                                                    &type_offset);
278
279                         var = PREV_LINK(var);
280                     }
281                 }
282
283                 /* emit return value data */
284                 var = func->def;
285                 if (is_void(var->type, NULL))
286                 {
287                     print_file(file, indent, "0x5b,    /* FC_END */\n");
288                     print_file(file, indent, "0x5c,    /* FC_PAD */\n");
289                 }
290                 else
291                     write_procformatstring_var(file, indent, var, TRUE,
292                                                &type_offset);
293             }
294         }
295     }
296
297     print_file(file, indent, "0x0\n");
298     indent--;
299     print_file(file, indent, "}\n");
300     indent--;
301     print_file(file, indent, "};\n");
302     print_file(file, indent, "\n");
303 }
304
305 /* write conformance / variance descriptor */
306 static size_t write_conf_or_var_desc(FILE *file, const func_t *func, const type_t *structure, const expr_t *expr)
307 {
308     unsigned char operator_type = 0;
309     const char *operator_string = "no operators";
310     const expr_t *subexpr = expr;
311     unsigned char correlation_type;
312
313     if (!file) return 4; /* optimisation for sizing pass */
314
315     if (expr->is_const)
316     {
317         if (expr->cval > UCHAR_MAX * (USHRT_MAX + 1) + USHRT_MAX)
318             error("write_conf_or_var_desc: constant value %ld is greater than "
319                   "the maximum constant size of %d\n", expr->cval,
320                   UCHAR_MAX * (USHRT_MAX + 1) + USHRT_MAX);
321
322         print_file(file, 2, "0x%x, /* Corr desc: constant, val = %ld */\n",
323                    RPC_FC_CONSTANT_CONFORMANCE, expr->cval);
324         print_file(file, 2, "0x%x,\n", expr->cval & ~USHRT_MAX);
325         print_file(file, 2, "NdrFcShort(0x%x),\n", expr->cval & USHRT_MAX);
326
327         return 4;
328     }
329
330     switch (subexpr->type)
331     {
332     case EXPR_PPTR:
333         subexpr = subexpr->ref;
334         operator_type = RPC_FC_DEREFERENCE;
335         operator_string = "FC_DEREFERENCE";
336         break;
337     case EXPR_DIV:
338         if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 2))
339         {
340             subexpr = subexpr->ref;
341             operator_type = RPC_FC_DIV_2;
342             operator_string = "FC_DIV_2";
343         }
344         break;
345     case EXPR_MUL:
346         if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 2))
347         {
348             subexpr = subexpr->ref;
349             operator_type = RPC_FC_MULT_2;
350             operator_string = "FC_MULT_2";
351         }
352         break;
353     case EXPR_SUB:
354         if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 1))
355         {
356             subexpr = subexpr->ref;
357             operator_type = RPC_FC_SUB_1;
358             operator_string = "FC_SUB_1";
359         }
360         break;
361     case EXPR_ADD:
362         if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 1))
363         {
364             subexpr = subexpr->ref;
365             operator_type = RPC_FC_ADD_1;
366             operator_string = "FC_ADD_1";
367         }
368         break;
369     default:
370         break;
371     }
372
373     if (subexpr->type == EXPR_IDENTIFIER)
374     {
375         const type_t *correlation_variable = NULL;
376         unsigned char param_type = 0;
377         const char *param_type_string = NULL;
378         size_t offset;
379
380         if (structure)
381         {
382             const var_t *var;
383
384             for (offset = 0, var = structure->fields; var; var = NEXT_LINK(var))
385             {
386                 offset -= type_memsize(var->type, var->ptr_level, var->array);
387                 if (!strcmp(var->name, subexpr->u.sval))
388                 {
389                     correlation_variable = var->type;
390                     break;
391                 }
392             }
393             if (!correlation_variable)
394                 error("write_conf_or_var_desc: couldn't find variable %s in structure\n",
395                       subexpr->u.sval);
396
397             correlation_type = RPC_FC_NORMAL_CONFORMANCE;
398         }
399         else
400         {
401             const var_t *var = func->args;
402
403             while (NEXT_LINK(var)) var = NEXT_LINK(var);
404             /* FIXME: not all stack variables are sizeof(void *) */
405             for (offset = 0; var; offset += sizeof(void *), var = PREV_LINK(var))
406             {
407                 if (!strcmp(var->name, subexpr->u.sval))
408                 {
409                     correlation_variable = var->type;
410                     break;
411                 }
412             }
413             if (!correlation_variable)
414                 error("write_conf_or_var_desc: couldn't find variable %s in function\n",
415                     subexpr->u.sval);
416
417             correlation_type = RPC_FC_TOP_LEVEL_CONFORMANCE;
418         }
419
420         while (type_has_ref(correlation_variable))
421             correlation_variable = correlation_variable->ref;
422
423         switch (correlation_variable->type)
424         {
425         case RPC_FC_CHAR:
426         case RPC_FC_SMALL:
427             param_type = RPC_FC_SMALL;
428             param_type_string = "FC_SMALL";
429             break;
430         case RPC_FC_BYTE:
431         case RPC_FC_USMALL:
432             param_type = RPC_FC_USMALL;
433             param_type_string = "FC_USMALL";
434             break;
435         case RPC_FC_WCHAR:
436         case RPC_FC_SHORT:
437             param_type = RPC_FC_SHORT;
438             param_type_string = "FC_SHORT";
439             break;
440         case RPC_FC_USHORT:
441             param_type = RPC_FC_USHORT;
442             param_type_string = "FC_USHORT";
443             break;
444         case RPC_FC_LONG:
445             param_type = RPC_FC_LONG;
446             param_type_string = "FC_LONG";
447             break;
448         case RPC_FC_ULONG:
449             param_type = RPC_FC_ULONG;
450             param_type_string = "FC_ULONG";
451             break;
452         default:
453             error("write_conf_or_var_desc: conformance variable type not supported 0x%x\n",
454                 correlation_variable->type);
455         }
456
457         print_file(file, 2, "0x%x, /* Corr desc: %s%s */\n",
458                 correlation_type | param_type,
459                 correlation_type == RPC_FC_TOP_LEVEL_CONFORMANCE ? "parameter, " : "",
460                 param_type_string);
461         print_file(file, 2, "0x%x, /* %s */\n", operator_type, operator_string);
462         print_file(file, 2, "NdrFcShort(0x%x), /* %soffset = %d */\n",
463                    offset,
464                    correlation_type == RPC_FC_TOP_LEVEL_CONFORMANCE ? "x86 stack size / " : "",
465                    offset);
466     }
467     else
468     {
469         unsigned int callback_offset = 0;
470
471         if (structure)
472         {
473             struct expr_eval_routine *eval;
474             int found = 0;
475
476             LIST_FOR_EACH_ENTRY(eval, &expr_eval_routines, struct expr_eval_routine, entry)
477             {
478                 if (!strcmp(eval->structure->name, structure->name) &&
479                     !compare_expr(eval->expr, expr))
480                 {
481                     found = 1;
482                     break;
483                 }
484                 callback_offset++;
485             }
486
487             if (!found)
488             {
489                 eval = xmalloc(sizeof(*eval));
490                 eval->structure = structure;
491                 eval->structure_size = fields_memsize(structure->fields);
492                 eval->expr = expr;
493                 list_add_tail(&expr_eval_routines, &eval->entry);
494             }
495
496             correlation_type = RPC_FC_NORMAL_CONFORMANCE;
497         }
498         else
499         {
500             error("write_conf_or_var_desc: top-level callback conformance unimplemented\n");
501             correlation_type = RPC_FC_TOP_LEVEL_CONFORMANCE;
502         }
503
504         if (callback_offset > USHRT_MAX)
505             error("Maximum number of callback routines reached\n");
506
507         print_file(file, 2, "0x%x, /* Corr desc: %s */\n",
508                    correlation_type,
509                    correlation_type == RPC_FC_TOP_LEVEL_CONFORMANCE ? "parameter" : "");
510         print_file(file, 2, "0x%x, /* %s */\n", RPC_FC_CALLBACK, "FC_CALLBACK");
511         print_file(file, 2, "NdrFcShort(0x%x), /* %u */\n", callback_offset, callback_offset);
512     }
513     return 4;
514 }
515
516 static size_t fields_memsize(const var_t *v)
517 {
518     size_t size = 0;
519     const var_t *first = v;
520     if (!v) return 0;
521     while (NEXT_LINK(v)) v = NEXT_LINK(v);
522     while (v) {
523         size += type_memsize(v->type, v->ptr_level, v->array);
524         if (v == first) break;
525         v = PREV_LINK(v);
526     }
527     return size;
528 }
529
530 static size_t type_memsize(const type_t *t, int ptr_level, const expr_t *array)
531 {
532     size_t size = 0;
533
534     if (ptr_level)
535         return sizeof(void *);
536
537     if (type_has_ref(t))
538         return type_memsize(t->ref, 0 /* FIXME */, NULL);
539
540     switch (t->type)
541     {
542     case RPC_FC_BYTE:
543     case RPC_FC_CHAR:
544     case RPC_FC_USMALL:
545     case RPC_FC_SMALL:
546         size = 1;
547         break;
548     case RPC_FC_WCHAR:
549     case RPC_FC_USHORT:
550     case RPC_FC_SHORT:
551     case RPC_FC_ENUM16:
552         size = 2;
553         break;
554     case RPC_FC_ULONG:
555     case RPC_FC_LONG:
556     case RPC_FC_ERROR_STATUS_T:
557     case RPC_FC_ENUM32:
558     case RPC_FC_FLOAT:
559         size = 4;
560         break;
561     case RPC_FC_HYPER:
562     case RPC_FC_DOUBLE:
563         size = 8;
564         break;
565     case RPC_FC_STRUCT:
566     case RPC_FC_CVSTRUCT:
567     case RPC_FC_CPSTRUCT:
568     case RPC_FC_CSTRUCT:
569     case RPC_FC_PSTRUCT:
570     case RPC_FC_BOGUS_STRUCT:
571     case RPC_FC_ENCAPSULATED_UNION:
572     case RPC_FC_NON_ENCAPSULATED_UNION:
573         size = fields_memsize(t->fields);
574         break;
575     default:
576         error("type_memsize: Unknown type %d\n", t->type);
577         size = 0;
578     }
579
580     if (array)
581     {
582         if (array->is_const)
583             size *= array->cval;
584         else
585             size = 0;
586     }
587
588     return size;
589 }
590
591 size_t get_type_memsize(const type_t *type)
592 {
593     return type_memsize(type, 0, NULL);
594 }
595
596 static int write_pointers(FILE *file, const attr_t *attrs,
597                           const type_t *type, int ptr_level,
598                           const expr_t *array, int level,
599                           unsigned int *typestring_offset)
600 {
601     int pointers_written = 0;
602     const var_t *v;
603
604     /* don't generate a pointer for first-level arrays since we want to
605     * descend into them to write their pointers, not stop here */
606     if ((level == 0 || ptr_level == 0) && is_array_type(attrs, ptr_level, array))
607     {
608         return write_pointers(file, NULL, type, 0, NULL, level + 1, typestring_offset);
609     }
610
611     if (ptr_level != 0)
612     {
613         /* FIXME: only general algorithm implemented, not the actual writing */
614         error("write_pointers: Writing type format string for pointer is unimplemented\n");
615         return 1;
616     }
617
618     /* FIXME: search through all refs for pointers too */
619     while(type_has_ref(type))
620         type = type->ref;
621
622     switch (type->type)
623     {
624         /* note: don't descend into complex structures or unions since these
625          * will always be generated as a separate type */
626         case RPC_FC_STRUCT:
627         case RPC_FC_CVSTRUCT:
628         case RPC_FC_CPSTRUCT:
629         case RPC_FC_CSTRUCT:
630         case RPC_FC_PSTRUCT:
631             v = type->fields;
632             if (!v) break;
633             while (NEXT_LINK(v)) v = NEXT_LINK(v);
634             for (; v; v = PREV_LINK(v))
635                 pointers_written += write_pointers(file, v->attrs, v->type,
636                                                    v->ptr_level, v->array,
637                                                    level + 1,
638                                                    typestring_offset);
639
640             break;
641
642         default:
643             /* nothing to do */
644             break;
645     }
646
647     return pointers_written;
648 }
649
650 static size_t write_pointer_description(FILE *file, const attr_t *attrs,
651                                         const type_t *type, int ptr_level,
652                                         const expr_t *array, int level,
653                                         size_t typestring_offset)
654 {
655     size_t size = 0;
656     const var_t *v;
657
658     /* don't generate a pointer for first-level arrays since we want to
659      * descend into them to write their pointers, not stop here */
660     if ((level == 0 || ptr_level == 0) && is_array_type(attrs, ptr_level, array))
661     {
662         return write_pointer_description(file, NULL, type, 0, NULL,
663                                          level + 1, typestring_offset);
664     }
665
666     if (ptr_level != 0)
667     {
668         /* FIXME: only general algorithm implemented, not the actual writing */
669         error("write_pointer_description: Writing pointer description is unimplemented\n");
670         return 0;
671     }
672
673     /* FIXME: search through all refs for pointers too */
674
675     switch (type->type)
676     {
677         /* note: don't descend into complex structures or unions since these
678          * will always be generated as a separate type */
679         case RPC_FC_STRUCT:
680         case RPC_FC_CVSTRUCT:
681         case RPC_FC_CPSTRUCT:
682         case RPC_FC_CSTRUCT:
683         case RPC_FC_PSTRUCT:
684             v = type->fields;
685             if (!v) break;
686             while (NEXT_LINK(v)) v = NEXT_LINK(v);
687             for (; v; v = PREV_LINK(v))
688                 size += write_pointer_description(file, v->attrs, v->type,
689                                                   v->ptr_level, v->array,
690                                                   level + 1,
691                                                   typestring_offset);
692
693             break;
694
695         default:
696             /* nothing to do */
697             break;
698     }
699
700     return size;
701 }
702
703 static size_t write_string_tfs(FILE *file, const attr_t *attrs,
704                                const type_t *type, const expr_t *array,
705                                const char *name, unsigned int *typestring_offset)
706 {
707     const expr_t *size_is = get_attrp(attrs, ATTR_SIZEIS);
708     int has_size = size_is && (size_is->type != EXPR_VOID);
709     size_t start_offset = *typestring_offset;
710     unsigned char flags = 0;
711     int pointer_type = get_attrv(attrs, ATTR_POINTERTYPE);
712     if (!pointer_type)
713         pointer_type = RPC_FC_RP;
714
715     if (!get_attrp(attrs, ATTR_SIZEIS))
716         flags |= RPC_FC_P_SIMPLEPOINTER;
717
718     while (type_has_ref(type))
719         type = type->ref;
720
721     if ((type->type != RPC_FC_BYTE) && (type->type != RPC_FC_CHAR) && (type->type != RPC_FC_WCHAR))
722     {
723         error("write_string_tfs: Unimplemented for type 0x%x of name: %s\n", type->type, name);
724         return start_offset;
725     }
726
727     print_file(file, 2,"0x%x, 0x%x,    /* %s%s */\n",
728                pointer_type, flags,
729                pointer_type == RPC_FC_FP ? "FC_FP" : (pointer_type == RPC_FC_UP ? "FC_UP" : "FC_RP"),
730                (flags & RPC_FC_P_SIMPLEPOINTER) ? " [simple_pointer]" : "");
731     *typestring_offset += 2;
732
733     if (!(flags & RPC_FC_P_SIMPLEPOINTER))
734     {
735         print_file(file, 2, "NdrFcShort(0x2),\n");
736         *typestring_offset += 2;
737     }
738
739     if (array && array->is_const)
740     {
741         if (array->cval > USHRT_MAX)
742             error("array size for parameter %s exceeds %d bytes by %ld bytes\n",
743                   name, USHRT_MAX, array->cval - USHRT_MAX);
744
745         if (type->type == RPC_FC_CHAR)
746             WRITE_FCTYPE(file, FC_CSTRING, *typestring_offset);
747         else
748             WRITE_FCTYPE(file, FC_WSTRING, *typestring_offset);
749         print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
750         *typestring_offset += 2;
751
752         print_file(file, 2, "NdrFcShort(0x%x), /* %d */\n", array->cval, array->cval);
753         *typestring_offset += 2;
754
755         return start_offset;
756     }
757     else if (has_size)
758     {
759         if (type->type == RPC_FC_CHAR)
760             WRITE_FCTYPE(file, FC_C_CSTRING, *typestring_offset);
761         else
762             WRITE_FCTYPE(file, FC_C_WSTRING, *typestring_offset);
763         print_file(file, 2, "0x%x, /* FC_STRING_SIZED */\n", RPC_FC_STRING_SIZED);
764         *typestring_offset += 2;
765
766         *typestring_offset += write_conf_or_var_desc(file, current_func, NULL, size_is);
767
768         return start_offset;
769     }
770     else
771     {
772         if (type->type == RPC_FC_CHAR)
773             WRITE_FCTYPE(file, FC_C_CSTRING, *typestring_offset);
774         else
775             WRITE_FCTYPE(file, FC_C_WSTRING, *typestring_offset);
776         print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
777         *typestring_offset += 2;
778
779         return start_offset;
780     }
781 }
782
783 static size_t write_array_tfs(FILE *file, const attr_t *attrs,
784                               const type_t *type, const expr_t *array,
785                               const char *name, unsigned int *typestring_offset)
786 {
787     const expr_t *length_is = get_attrp(attrs, ATTR_LENGTHIS);
788     const expr_t *size_is = get_attrp(attrs, ATTR_SIZEIS);
789     int has_length = length_is && (length_is->type != EXPR_VOID);
790     int has_size = (size_is && (size_is->type != EXPR_VOID)) || !array->is_const;
791     size_t start_offset;
792     int pointer_type = get_attrv(attrs, ATTR_POINTERTYPE);
793     if (!pointer_type)
794         pointer_type = RPC_FC_RP;
795
796     print_file(file, 2, "0x%x, 0x00,    /* %s */\n",
797                pointer_type,
798                pointer_type == RPC_FC_FP ? "FC_FP" : (pointer_type == RPC_FC_UP ? "FC_UP" : "FC_RP"));
799     print_file(file, 2, "NdrFcShort(0x2),\n");
800     *typestring_offset += 4;
801
802     if (array && NEXT_LINK(array)) /* multi-dimensional array */
803     {
804         error("write_array_tfs: Multi-dimensional arrays not implemented yet (param %s)\n", name);
805         return 0;
806     }
807     else
808     {
809         size_t pointer_start_offset = *typestring_offset;
810         int has_pointer = 0;
811
812         if (write_pointers(file, attrs, type, 0, array, 0, typestring_offset) > 0)
813             has_pointer = 1;
814
815         start_offset = *typestring_offset;
816
817         if (!has_length && !has_size)
818         {
819             /* fixed array */
820             size_t size = type_memsize(type, 0, array);
821             if (size < USHRT_MAX)
822             {
823                 WRITE_FCTYPE(file, FC_SMFARRAY, *typestring_offset);
824                 /* alignment */
825                 print_file(file, 2, "0x%x, /* 0 */\n", 0);
826                 /* size */
827                 print_file(file, 2, "NdrFcShort(0x%x), /* %d */\n", size, size);
828                 *typestring_offset += 4;
829             }
830             else
831             {
832                 WRITE_FCTYPE(file, FC_LGFARRAY, *typestring_offset);
833                 /* alignment */
834                 print_file(file, 2, "0x%x, /* 0 */\n", 0);
835                 /* size */
836                 print_file(file, 2, "NdrFcLong(0x%x), /* %d */\n", size, size);
837                 *typestring_offset += 6;
838             }
839
840             if (has_pointer)
841             {
842                 print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
843                 print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
844                 *typestring_offset += 2;
845                 *typestring_offset = write_pointer_description(file, attrs,
846                     type, 0, array, 0, pointer_start_offset);
847                 print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
848                 *typestring_offset += 1;
849             }
850
851             print_file(file, 2, "0x0, /* FIXME: write out conversion data */\n");
852             print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
853             *typestring_offset += 2;
854
855             return start_offset;
856         }
857         else if (has_length && !has_size)
858         {
859             /* varying array */
860             size_t element_size = type_memsize(type, 0, NULL);
861             size_t elements = array->cval;
862             size_t total_size = element_size * elements;
863
864             if (total_size < USHRT_MAX)
865             {
866                 WRITE_FCTYPE(file, FC_SMVARRAY, *typestring_offset);
867                 /* alignment */
868                 print_file(file, 2, "0x%x, /* 0 */\n", 0);
869                 /* total size */
870                 print_file(file, 2, "NdrFcShort(0x%x), /* %d */\n", total_size, total_size);
871                 /* number of elements */
872                 print_file(file, 2, "NdrFcShort(0x%x), /* %d */\n", elements, elements);
873                 *typestring_offset += 6;
874             }
875             else
876             {
877                 WRITE_FCTYPE(file, FC_LGVARRAY, *typestring_offset);
878                 /* alignment */
879                 print_file(file, 2, "0x%x, /* 0 */\n", 0);
880                 /* total size */
881                 print_file(file, 2, "NdrFcLong(0x%x), /* %d */\n", total_size, total_size);
882                 /* number of elements */
883                 print_file(file, 2, "NdrFcLong(0x%x), /* %d */\n", elements, elements);
884                 *typestring_offset += 10;
885             }
886             /* element size */
887             print_file(file, 2, "NdrFcShort(0x%x), /* %d */\n", element_size, element_size);
888             *typestring_offset += 2;
889
890             *typestring_offset += write_conf_or_var_desc(file, current_func,
891                                                          current_structure,
892                                                          length_is);
893
894             if (has_pointer)
895             {
896                 print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
897                 print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
898                 *typestring_offset += 2;
899                 *typestring_offset += write_pointer_description(file, attrs,
900                     type, 0, array, 0, pointer_start_offset);
901                 print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
902                 *typestring_offset += 1;
903             }
904
905             print_file(file, 2, "0x0, /* FIXME: write out conversion data */\n");
906             print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
907             *typestring_offset += 2;
908
909             return start_offset;
910         }
911         else if (!has_length && has_size)
912         {
913             /* conformant array */
914             size_t element_size = type_memsize(type, 0, NULL);
915
916             WRITE_FCTYPE(file, FC_CARRAY, *typestring_offset);
917             /* alignment */
918             print_file(file, 2, "0x%x, /* 0 */\n", 0);
919             /* element size */
920             print_file(file, 2, "NdrFcShort(0x%x), /* %d */\n", element_size, element_size);
921             *typestring_offset += 4;
922
923             *typestring_offset += write_conf_or_var_desc(file, current_func,
924                                                          current_structure,
925                                                          size_is ? size_is : array);
926
927             if (has_pointer)
928             {
929                 print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
930                 print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
931                 *typestring_offset += 2;
932                 *typestring_offset += write_pointer_description(file, attrs,
933                     type, 0, array, 0, pointer_start_offset);
934                 print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
935                 *typestring_offset += 1;
936             }
937
938             print_file(file, 2, "0x%x, /* FIXME: write out conversion data */\n", type->type);
939             print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
940             *typestring_offset += 2;
941
942             return start_offset;
943         }
944         else
945         {
946             /* conformant varying array */
947             size_t element_size = type_memsize(type, 0, NULL);
948
949             WRITE_FCTYPE(file, FC_CVARRAY, *typestring_offset);
950             /* alignment */
951             print_file(file, 2, "0x%x, /* 0 */\n", 0);
952             /* element size */
953             print_file(file, 2, "NdrFcShort(0x%x), /* %d */\n", element_size, element_size);
954             *typestring_offset += 4;
955
956             *typestring_offset += write_conf_or_var_desc(file, current_func,
957                                                          current_structure,
958                                                          size_is ? size_is : array);
959             *typestring_offset += write_conf_or_var_desc(file, current_func,
960                                                          current_structure,
961                                                          length_is);
962
963             if (has_pointer)
964             {
965                 print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
966                 print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
967                 *typestring_offset += 2;
968                 *typestring_offset += write_pointer_description(file, attrs,
969                     type, 0, array, 0, pointer_start_offset);
970                 print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
971                 *typestring_offset += 1;
972             }
973
974             print_file(file, 2, "0x0, /* FIXME: write out conversion data */\n");
975             print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
976             *typestring_offset += 2;
977
978             return start_offset;
979         }
980     }
981 }
982
983 static const var_t *find_array_or_string_in_struct(const type_t *type)
984 {
985     /* last field is the first in the fields linked list */
986     const var_t *last_field = type->fields;
987     if (is_array_type(last_field->attrs, last_field->ptr_level, last_field->array))
988         return last_field;
989
990     assert((last_field->type->type == RPC_FC_CSTRUCT) ||
991            (last_field->type->type == RPC_FC_CPSTRUCT) ||
992            (last_field->type->type == RPC_FC_CVSTRUCT));
993
994     return find_array_or_string_in_struct(last_field->type);
995 }
996
997 static size_t write_struct_members(FILE *file, const type_t *type)
998 {
999     size_t typestring_size = 0;
1000     var_t *field;
1001
1002     field = type->fields;
1003     while (NEXT_LINK(field)) field = NEXT_LINK(field);
1004     for (; field; field = PREV_LINK(field))
1005     {
1006         if (is_base_type(field->type->type))
1007         {
1008             switch (field->type->type)
1009             {
1010 #define CASE_BASETYPE(fctype) \
1011             case RPC_##fctype: \
1012                 print_file(file, 2, "0x%02x,\t\t/* " #fctype " */\n", RPC_##fctype); \
1013                 typestring_size++; \
1014                 break;
1015             CASE_BASETYPE(FC_BYTE);
1016             CASE_BASETYPE(FC_CHAR);
1017             CASE_BASETYPE(FC_SMALL);
1018             CASE_BASETYPE(FC_USMALL);
1019             CASE_BASETYPE(FC_WCHAR);
1020             CASE_BASETYPE(FC_SHORT);
1021             CASE_BASETYPE(FC_USHORT);
1022             CASE_BASETYPE(FC_LONG);
1023             CASE_BASETYPE(FC_ULONG);
1024             CASE_BASETYPE(FC_FLOAT);
1025             CASE_BASETYPE(FC_HYPER);
1026             CASE_BASETYPE(FC_DOUBLE);
1027             CASE_BASETYPE(FC_ENUM16);
1028             CASE_BASETYPE(FC_ENUM32);
1029             CASE_BASETYPE(FC_IGNORE);
1030             CASE_BASETYPE(FC_ERROR_STATUS_T);
1031             default:
1032                 break;
1033 #undef CASE_BASETYPE
1034             }
1035         }
1036         else
1037             error("Unsupported member type 0x%x\n", field->type->type);
1038     }
1039
1040     if (typestring_size % 1)
1041     {
1042         print_file(file, 2, "0x%x,\t\t/* FC_PAD */\n", RPC_FC_PAD);
1043         typestring_size++;
1044     }
1045
1046     print_file(file, 2, "0x%x,\t\t/* FC_END */\n", RPC_FC_END);
1047     typestring_size++;
1048
1049     return typestring_size;
1050 }
1051
1052 static size_t write_struct_tfs(FILE *file, const type_t *type,
1053                                const char *name, unsigned int *typestring_offset)
1054 {
1055     unsigned int total_size;
1056     const var_t *array;
1057     size_t start_offset;
1058     size_t array_offset;
1059     size_t pointer_offset;
1060
1061     switch (type->type)
1062     {
1063     case RPC_FC_STRUCT:
1064     case RPC_FC_PSTRUCT:
1065         total_size = type_memsize(type, 0, NULL);
1066
1067         if (total_size > USHRT_MAX)
1068             error("structure size for parameter %s exceeds %d bytes by %d bytes\n",
1069                   name, USHRT_MAX, total_size - USHRT_MAX);
1070
1071         if (type->type == RPC_FC_PSTRUCT)
1072         {
1073             pointer_offset = *typestring_offset;
1074             write_pointers(file, NULL, type, 0, NULL, 0, typestring_offset);
1075         }
1076         else pointer_offset = 0; /* silence warning */
1077
1078         start_offset = *typestring_offset;
1079         if (type->type == RPC_FC_STRUCT)
1080             WRITE_FCTYPE(file, FC_STRUCT, *typestring_offset);
1081         else
1082             WRITE_FCTYPE(file, FC_PSTRUCT, *typestring_offset);
1083         /* alignment */
1084         print_file(file, 2, "0x3,\n"); /* FIXME */
1085         /* total size */
1086         print_file(file, 2, "NdrFcShort(0x%x), /* %u */\n", total_size, total_size);
1087         *typestring_offset += 4;
1088
1089         if (type->type == RPC_FC_PSTRUCT)
1090         {
1091             print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
1092             print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
1093             *typestring_offset += 2;
1094             *typestring_offset += write_pointer_description(file, NULL,
1095                 type, 0, NULL, 0, pointer_offset);
1096             print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
1097             *typestring_offset += 1;
1098         }
1099
1100         /* member layout */
1101         *typestring_offset += write_struct_members(file, type);
1102         return start_offset;
1103     case RPC_FC_CSTRUCT:
1104     case RPC_FC_CPSTRUCT:
1105         total_size = type_memsize(type, 0, NULL);
1106
1107         if (total_size > USHRT_MAX)
1108             error("structure size for parameter %s exceeds %d bytes by %d bytes\n",
1109                   name, USHRT_MAX, total_size - USHRT_MAX);
1110
1111         array = find_array_or_string_in_struct(type);
1112         current_structure = type;
1113         array_offset = write_array_tfs(file, array->attrs, array->type,
1114                                        array->array, array->name,
1115                                        typestring_offset);
1116         current_structure = NULL;
1117
1118         if (type->type == RPC_FC_CPSTRUCT)
1119         {
1120             pointer_offset = *typestring_offset;
1121             write_pointers(file, NULL, type, 0, NULL, 0, typestring_offset);
1122         }
1123         else pointer_offset = 0; /* silence warning */
1124
1125         start_offset = *typestring_offset;
1126         if (type->type == RPC_FC_CSTRUCT)
1127             WRITE_FCTYPE(file, FC_CSTRUCT, *typestring_offset);
1128         else
1129             WRITE_FCTYPE(file, FC_CPSTRUCT, *typestring_offset);
1130         /* alignment */
1131         print_file(file, 2, "0x0,\n");
1132         /* total size */
1133         print_file(file, 2, "NdrFcShort(0x%x), /* %u */\n", total_size, total_size);
1134         *typestring_offset += 4;
1135         print_file(file, 2, "NdrFcShort(0x%x), /* offset = %d (%u) */\n",
1136                    array_offset - *typestring_offset,
1137                    array_offset - *typestring_offset,
1138                    array_offset);
1139         *typestring_offset += 2;
1140
1141         if (type->type == RPC_FC_CPSTRUCT)
1142         {
1143             print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
1144             print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
1145             *typestring_offset += 2;
1146             *typestring_offset += write_pointer_description(file, NULL,
1147                 type, 0, NULL, 0, pointer_offset);
1148             print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
1149             *typestring_offset += 1;
1150         }
1151
1152         print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
1153         *typestring_offset += 1;
1154
1155         return start_offset;
1156     case RPC_FC_CVSTRUCT:
1157         total_size = type_memsize(type, 0, NULL);
1158
1159         if (total_size > USHRT_MAX)
1160             error("structure size for parameter %s exceeds %d bytes by %d bytes\n",
1161                   name, USHRT_MAX, total_size - USHRT_MAX);
1162
1163         array = find_array_or_string_in_struct(type);
1164         current_structure = type;
1165         if (is_attr(array->attrs, ATTR_STRING))
1166             array_offset = write_string_tfs(file, array->attrs, array->type,
1167                                             array->array, array->name,
1168                                             typestring_offset);
1169         else
1170             array_offset = write_array_tfs(file, array->attrs, array->type,
1171                                            array->array, array->name,
1172                                            typestring_offset);
1173         current_structure = NULL;
1174
1175         pointer_offset = *typestring_offset;
1176         if (!write_pointers(file, NULL, type, 0, NULL, 0, typestring_offset))
1177             pointer_offset = 0;
1178
1179         start_offset = *typestring_offset;
1180         WRITE_FCTYPE(file, FC_CVSTRUCT, *typestring_offset);
1181         /* alignment */
1182         print_file(file, 2, "0x0,\n");
1183         /* total size */
1184         print_file(file, 2, "NdrFcShort(0x%x), /* %u */\n", total_size, total_size);
1185         *typestring_offset += 4;
1186         print_file(file, 2, "NdrFcShort(0x%x), /* offset = %d (%u) */\n",
1187                    array_offset - *typestring_offset,
1188                    array_offset - *typestring_offset,
1189                    array_offset);
1190         *typestring_offset += 2;
1191
1192         if (pointer_offset != 0)
1193         {
1194             print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
1195             print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
1196             *typestring_offset += 2;
1197             *typestring_offset += write_pointer_description(file, NULL,
1198                 type, 0, NULL, 0, pointer_offset);
1199             print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
1200             *typestring_offset += 1;
1201         }
1202
1203         print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
1204         *typestring_offset += 1;
1205
1206         return start_offset;
1207     default:
1208         error("write_struct_tfs: Unimplemented for type 0x%x\n", type->type);
1209         return *typestring_offset;
1210     }
1211 }
1212
1213 static void write_pointer_only_tfs(FILE *file, const attr_t *attrs, size_t offset, unsigned int *typeformat_offset)
1214 {
1215     int in_attr, out_attr;
1216     unsigned char flags = 0;
1217     int pointer_type = get_attrv(attrs, ATTR_POINTERTYPE);
1218     if (!pointer_type) pointer_type = RPC_FC_RP;
1219     in_attr = is_attr(attrs, ATTR_IN);
1220     out_attr = is_attr(attrs, ATTR_OUT);
1221     if (!in_attr && !out_attr) in_attr = 1;
1222
1223     if (out_attr && !in_attr && pointer_type == RPC_FC_RP)
1224         flags |= 0x04;
1225
1226     print_file(file, 2, "0x%x, 0x%x,\t\t/* %s%s */\n",
1227                pointer_type,
1228                flags,
1229                pointer_type == RPC_FC_FP ? "FC_FP" : (pointer_type == RPC_FC_UP ? "FC_UP" : "FC_RP"),
1230                (flags & 0x04) ? " [allocated_on_stack]" : "");
1231     print_file(file, 2, "NdrFcShort(0x%x),    /* %d */\n", offset, offset);
1232     *typeformat_offset += 4;
1233 }
1234
1235 static size_t write_union_tfs(FILE *file, const attr_t *attrs,
1236                               const type_t *type, const char *name,
1237                               unsigned int *typeformat_offset)
1238 {
1239     error("write_union_tfs: Unimplemented\n");
1240     return *typeformat_offset;
1241 }
1242
1243 static size_t write_typeformatstring_var(FILE *file, int indent,
1244                                          const var_t *var, unsigned int *typeformat_offset)
1245 {
1246     const type_t *type = var->type;
1247     int ptr_level = var->ptr_level;
1248
1249     chat("write_typeformatstring_var: %s\n", var->name);
1250
1251     while (TRUE)
1252     {
1253         chat("write_typeformatstring: type->type = 0x%x, type->name = %s, ptr_level = %d\n", type->type, type->name, ptr_level);
1254
1255         if (is_string_type(var->attrs, ptr_level, var->array))
1256             return write_string_tfs(file, var->attrs, type, var->array, var->name, typeformat_offset);
1257
1258         if (is_array_type(var->attrs, ptr_level, var->array))
1259             return write_array_tfs(file, var->attrs, type, var->array, var->name, typeformat_offset);
1260
1261         if (ptr_level == 0)
1262         {
1263             /* follow reference if the type has one */
1264             if (type_has_ref(type))
1265             {
1266                 type = type->ref;
1267                 /* FIXME: get new ptr_level from type */
1268                 continue;
1269             }
1270
1271             /* basic types don't need a type format string */
1272             if (is_base_type(type->type))
1273                 return 0;
1274
1275             switch (type->type)
1276             {
1277             case RPC_FC_STRUCT:
1278             case RPC_FC_PSTRUCT:
1279             case RPC_FC_CSTRUCT:
1280             case RPC_FC_CPSTRUCT:
1281             case RPC_FC_CVSTRUCT:
1282             case RPC_FC_BOGUS_STRUCT:
1283                 return write_struct_tfs(file, type, var->name, typeformat_offset);
1284             case RPC_FC_ENCAPSULATED_UNION:
1285             case RPC_FC_NON_ENCAPSULATED_UNION:
1286                 return write_union_tfs(file, var->attrs, type, var->name, typeformat_offset);
1287             case RPC_FC_IGNORE:
1288             case RPC_FC_BIND_PRIMITIVE:
1289                 /* nothing to do */
1290                 return 0;
1291             default:
1292                 error("write_typeformatstring_var: Unsupported type 0x%x for variable %s\n", type->type, var->name);
1293             }
1294         }
1295         else if (ptr_level == 1 && !type_has_ref(type))
1296         {
1297             size_t start_offset = *typeformat_offset;
1298             int in_attr = is_attr(var->attrs, ATTR_IN);
1299             int out_attr = is_attr(var->attrs, ATTR_OUT);
1300             int pointer_type = get_attrv(var->attrs, ATTR_POINTERTYPE);
1301             if (!pointer_type) pointer_type = RPC_FC_RP;
1302
1303             /* special case for pointers to base types */
1304             switch (type->type)
1305             {
1306 #define CASE_BASETYPE(fctype) \
1307             case RPC_##fctype: \
1308                 print_file(file, indent, "0x%x, 0x%x,    /* %s %s[simple_pointer] */\n", \
1309                            pointer_type, \
1310                            (!in_attr && out_attr) ? 0x0C : 0x08, \
1311                            pointer_type == RPC_FC_FP ? "FC_FP" : (pointer_type == RPC_FC_UP ? "FC_UP" : "FC_RP"), \
1312                            (!in_attr && out_attr) ? "[allocated_on_stack] " : ""); \
1313                 print_file(file, indent, "0x%02x,    /* " #fctype " */\n", RPC_##fctype); \
1314                 print_file(file, indent, "0x5c,          /* FC_PAD */\n"); \
1315                 *typeformat_offset += 4; \
1316                 return start_offset
1317             CASE_BASETYPE(FC_BYTE);
1318             CASE_BASETYPE(FC_CHAR);
1319             CASE_BASETYPE(FC_SMALL);
1320             CASE_BASETYPE(FC_USMALL);
1321             CASE_BASETYPE(FC_WCHAR);
1322             CASE_BASETYPE(FC_SHORT);
1323             CASE_BASETYPE(FC_USHORT);
1324             CASE_BASETYPE(FC_LONG);
1325             CASE_BASETYPE(FC_ULONG);
1326             CASE_BASETYPE(FC_FLOAT);
1327             CASE_BASETYPE(FC_HYPER);
1328             CASE_BASETYPE(FC_DOUBLE);
1329             CASE_BASETYPE(FC_ENUM16);
1330             CASE_BASETYPE(FC_ENUM32);
1331             CASE_BASETYPE(FC_IGNORE);
1332             CASE_BASETYPE(FC_ERROR_STATUS_T);
1333             default:
1334                 break;
1335             }
1336         }
1337
1338         assert(ptr_level > 0);
1339
1340         if (file)
1341             fprintf(file, "/* %2u */\n", *typeformat_offset);
1342         write_pointer_only_tfs(file, var->attrs, 2, typeformat_offset);
1343
1344         ptr_level--;
1345     }
1346 }
1347
1348
1349 void write_typeformatstring(FILE *file, const ifref_t *ifaces)
1350 {
1351     int indent = 0;
1352     var_t *var;
1353     unsigned int typeformat_offset;
1354     const ifref_t *iface = ifaces;
1355
1356     print_file(file, indent, "static const MIDL_TYPE_FORMAT_STRING __MIDL_TypeFormatString =\n");
1357     print_file(file, indent, "{\n");
1358     indent++;
1359     print_file(file, indent, "0,\n");
1360     print_file(file, indent, "{\n");
1361     indent++;
1362     print_file(file, indent, "NdrFcShort(0x0),\n");
1363     typeformat_offset = 2;
1364
1365     END_OF_LIST(iface);
1366
1367     for (; iface; iface = PREV_LINK(iface))
1368     {
1369         if (is_object(iface->iface->attrs) || is_local(iface->iface->attrs))
1370             continue;
1371
1372         if (iface->iface->funcs)
1373         {
1374             func_t *func = iface->iface->funcs;
1375             while (NEXT_LINK(func)) func = NEXT_LINK(func);
1376             for (; func; func = PREV_LINK(func))
1377             {
1378                 current_func = func;
1379                 if (func->args)
1380                 {
1381                     var = func->args;
1382                     while (NEXT_LINK(var)) var = NEXT_LINK(var);
1383                     while (var)
1384                     {
1385                         write_typeformatstring_var(file, indent, var,
1386                                                    &typeformat_offset);
1387                         var = PREV_LINK(var);
1388                     }
1389                 }
1390             }
1391         }
1392     }
1393
1394     print_file(file, indent, "0x0\n");
1395     indent--;
1396     print_file(file, indent, "}\n");
1397     indent--;
1398     print_file(file, indent, "};\n");
1399     print_file(file, indent, "\n");
1400 }
1401
1402 static unsigned int get_required_buffer_size_type(
1403     const type_t *type, int ptr_level, const expr_t *array,
1404     const char *name, unsigned int *alignment)
1405 {
1406     *alignment = 0;
1407     if (ptr_level == 0 && !array && !type_has_ref(type))
1408     {
1409         switch (type->type)
1410         {
1411         case RPC_FC_BYTE:
1412         case RPC_FC_CHAR:
1413         case RPC_FC_USMALL:
1414         case RPC_FC_SMALL:
1415             *alignment = 4;
1416             return 1;
1417
1418         case RPC_FC_WCHAR:
1419         case RPC_FC_USHORT:
1420         case RPC_FC_SHORT:
1421             *alignment = 4;
1422             return 2;
1423
1424         case RPC_FC_ULONG:
1425         case RPC_FC_LONG:
1426         case RPC_FC_FLOAT:
1427         case RPC_FC_ERROR_STATUS_T:
1428             *alignment = 4;
1429             return 4;
1430
1431         case RPC_FC_HYPER:
1432         case RPC_FC_DOUBLE:
1433             *alignment = 8;
1434             return 8;
1435
1436         case RPC_FC_IGNORE:
1437         case RPC_FC_BIND_PRIMITIVE:
1438             return 0;
1439
1440         case RPC_FC_STRUCT:
1441         {
1442             size_t size = 0;
1443             const var_t *field;
1444             for (field = type->fields; field; field = NEXT_LINK(field))
1445             {
1446                 unsigned int alignment;
1447                 size += get_required_buffer_size_type(
1448                     field->type, field->ptr_level, field->array, field->name,
1449                     &alignment);
1450             }
1451             return size;
1452         }
1453
1454         default:
1455             error("get_required_buffer_size: Unknown/unsupported type: %s (0x%02x)\n", name, type->type);
1456             return 0;
1457         }
1458     }
1459     if (ptr_level == 0 && type_has_ref(type))
1460         return get_required_buffer_size_type(type->ref, 0 /* FIXME */, array, name, alignment);
1461     return 0;
1462 }
1463
1464 unsigned int get_required_buffer_size(const var_t *var, unsigned int *alignment, enum pass pass)
1465 {
1466     expr_t *size_is = get_attrp(var->attrs, ATTR_SIZEIS);
1467     int has_size = (size_is && (size_is->type != EXPR_VOID));
1468     int in_attr = is_attr(var->attrs, ATTR_IN);
1469     int out_attr = is_attr(var->attrs, ATTR_OUT);
1470
1471     if (!in_attr && !out_attr)
1472         in_attr = 1;
1473
1474     *alignment = 0;
1475
1476     if (pass == PASS_OUT)
1477     {
1478         if (out_attr && var->ptr_level > 0)
1479         {
1480             type_t *type = var->type;
1481             while (type->type == 0 && type->ref)
1482                 type = type->ref;
1483
1484             if (type->type == RPC_FC_STRUCT)
1485             {
1486                 const var_t *field;
1487                 unsigned int size = 36;
1488                 for (field = type->fields; field; field = NEXT_LINK(field))
1489                 {
1490                     unsigned int align;
1491                     size += get_required_buffer_size_type(
1492                         field->type, field->ptr_level, field->array, field->name,
1493                         &align);
1494                 }
1495                 return size;
1496             }
1497         }
1498         return 0;
1499     }
1500     else
1501     {
1502         if ((!out_attr || in_attr) && !has_size && !is_attr(var->attrs, ATTR_STRING) && !var->array)
1503         {
1504             if (var->ptr_level > 0 || (var->ptr_level == 0 && type_has_ref(var->type)))
1505             {
1506                 type_t *type = var->type;
1507                 while (type->type == 0 && type->ref)
1508                     type = type->ref;
1509
1510                 if (is_base_type(type->type))
1511                 {
1512                     return 25;
1513                 }
1514                 else if (type->type == RPC_FC_STRUCT)
1515                 {
1516                     unsigned int size = 36;
1517                     const var_t *field;
1518                     for (field = type->fields; field; field = NEXT_LINK(field))
1519                     {
1520                         unsigned int align;
1521                         size += get_required_buffer_size_type(
1522                             field->type, field->ptr_level, field->array, field->name,
1523                             &align);
1524                     }
1525                     return size;
1526                 }
1527             }
1528         }
1529
1530         return get_required_buffer_size_type(var->type, var->ptr_level, var->array, var->name, alignment);
1531     }
1532 }
1533
1534 static void print_phase_function(FILE *file, int indent, const char *type,
1535                                  enum remoting_phase phase,
1536                                  const char *varname, unsigned int type_offset)
1537 {
1538     const char *function;
1539     switch (phase)
1540     {
1541     case PHASE_BUFFERSIZE:
1542         function = "BufferSize";
1543         break;
1544     case PHASE_MARSHAL:
1545         function = "Marshall";
1546         break;
1547     case PHASE_UNMARSHAL:
1548         function = "Unmarshall";
1549         break;
1550     case PHASE_FREE:
1551         function = "Free";
1552         break;
1553     default:
1554         assert(0);
1555         return;
1556     }
1557
1558     print_file(file, indent, "Ndr%s%s(\n", type, function);
1559     indent++;
1560     print_file(file, indent, "&_StubMsg,\n");
1561     print_file(file, indent, "%s%s,\n",
1562                (phase == PHASE_UNMARSHAL) ? "(unsigned char **)&" : "(unsigned char *)",
1563                varname);
1564     print_file(file, indent, "(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%d]%s\n",
1565                type_offset, (phase == PHASE_UNMARSHAL) ? "," : ");");
1566     if (phase == PHASE_UNMARSHAL)
1567         print_file(file, indent, "0);\n");
1568     indent--;
1569 }
1570
1571 void print_phase_basetype(FILE *file, int indent, enum remoting_phase phase,
1572                           enum pass pass, const var_t *var,
1573                           const char *varname)
1574 {
1575     const type_t *type = var->type;
1576     unsigned int size;
1577     unsigned int alignment = 0;
1578
1579     /* no work to do for other phases, buffer sizing is done elsewhere */
1580     if (phase != PHASE_MARSHAL && phase != PHASE_UNMARSHAL)
1581         return;
1582
1583     while (type_has_ref(type))
1584         type = type->ref;
1585
1586     switch (type->type)
1587     {
1588         case RPC_FC_BYTE:
1589         case RPC_FC_CHAR:
1590         case RPC_FC_SMALL:
1591         case RPC_FC_USMALL:
1592             size = 1;
1593             alignment = 1;
1594             break;
1595
1596         case RPC_FC_WCHAR:
1597         case RPC_FC_USHORT:
1598         case RPC_FC_SHORT:
1599             size = 2;
1600             alignment = 2;
1601             break;
1602
1603         case RPC_FC_ULONG:
1604         case RPC_FC_LONG:
1605         case RPC_FC_FLOAT:
1606         case RPC_FC_ERROR_STATUS_T:
1607             size = 4;
1608             alignment = 4;
1609             break;
1610
1611         case RPC_FC_HYPER:
1612         case RPC_FC_DOUBLE:
1613             size = 8;
1614             alignment = 8;
1615             break;
1616
1617         case RPC_FC_IGNORE:
1618         case RPC_FC_BIND_PRIMITIVE:
1619             /* no marshalling needed */
1620             return;
1621
1622         default:
1623             error("print_phase_basetype: Unsupported type: %s (0x%02x, ptr_level: 0)\n", var->name, type->type);
1624             size = 0;
1625     }
1626
1627     print_file(file, indent, "_StubMsg.Buffer = (unsigned char *)(((long)_StubMsg.Buffer + %u) & ~0x%x);\n",
1628                 alignment - 1, alignment - 1);
1629
1630     if (phase == PHASE_MARSHAL)
1631     {
1632         print_file(file, indent, "*(");
1633         write_type(file, var->type, NULL, var->tname);
1634         if (var->ptr_level)
1635             fprintf(file, " *)_StubMsg.Buffer = *");
1636         else
1637             fprintf(file, " *)_StubMsg.Buffer = ");
1638         fprintf(file, varname);
1639         fprintf(file, ";\n");
1640     }
1641     else if (phase == PHASE_UNMARSHAL)
1642     {
1643         if (pass == PASS_IN || pass == PASS_RETURN)
1644             print_file(file, indent, "");
1645         else
1646             print_file(file, indent, "*");
1647         fprintf(file, varname);
1648         if (pass == PASS_IN && var->ptr_level)
1649             fprintf(file, " = (");
1650         else
1651             fprintf(file, " = *(");
1652         write_type(file, var->type, NULL, var->tname);
1653         fprintf(file, " *)_StubMsg.Buffer;\n");
1654     }
1655
1656     print_file(file, indent, "_StubMsg.Buffer += sizeof(");
1657     write_type(file, var->type, NULL, var->tname);
1658     fprintf(file, ");\n");
1659 }
1660
1661 /* returns whether the MaxCount, Offset or ActualCount members need to be
1662  * filled in for the specified phase */
1663 static inline int is_size_needed_for_phase(enum remoting_phase phase)
1664 {
1665     return (phase != PHASE_UNMARSHAL);
1666 }
1667
1668 void write_remoting_arguments(FILE *file, int indent, const func_t *func,
1669                               unsigned int *type_offset, enum pass pass,
1670                               enum remoting_phase phase)
1671 {
1672     const expr_t *length_is;
1673     const expr_t *size_is;
1674     int in_attr, out_attr, has_length, has_size, pointer_type;
1675     var_t *var;
1676
1677     if (!func->args)
1678         return;
1679
1680     var = func->args;
1681     while (NEXT_LINK(var)) var = NEXT_LINK(var);
1682     for (; var; *type_offset += get_size_typeformatstring_var(var), var = PREV_LINK(var))
1683     {
1684         const type_t *type = var->type;
1685         length_is = get_attrp(var->attrs, ATTR_LENGTHIS);
1686         size_is = get_attrp(var->attrs, ATTR_SIZEIS);
1687         has_length = length_is && (length_is->type != EXPR_VOID);
1688         has_size = (size_is && (size_is->type != EXPR_VOID)) || (var->array && !var->array->is_const);
1689
1690         pointer_type = get_attrv(var->attrs, ATTR_POINTERTYPE);
1691         if (!pointer_type)
1692             pointer_type = RPC_FC_RP;
1693
1694         in_attr = is_attr(var->attrs, ATTR_IN);
1695         out_attr = is_attr(var->attrs, ATTR_OUT);
1696         if (!in_attr && !out_attr)
1697             in_attr = 1;
1698
1699         switch (pass)
1700         {
1701         case PASS_IN:
1702             if (!in_attr)
1703                 continue;
1704             break;
1705         case PASS_OUT:
1706             if (!out_attr)
1707                 continue;
1708             break;
1709         case PASS_RETURN:
1710             break;
1711         }
1712
1713         while (type_has_ref(type))
1714             type = type->ref;
1715
1716         if (is_string_type(var->attrs, var->ptr_level, var->array))
1717         {
1718             if (var->array && var->array->is_const)
1719                 print_phase_function(file, indent, "NonConformantString", phase, var->name, *type_offset);
1720             else
1721             {
1722                 if (size_is && is_size_needed_for_phase(phase))
1723                 {
1724                     print_file(file, indent, "_StubMsg.MaxCount = (unsigned long)");
1725                     write_expr(file, size_is, 1);
1726                     fprintf(file, ";\n");
1727                 }
1728
1729                 if ((phase == PHASE_FREE) || (pointer_type == RPC_FC_UP))
1730                     print_phase_function(file, indent, "Pointer", phase, var->name, *type_offset);
1731                 else
1732                     print_phase_function(file, indent, "ConformantString", phase, var->name,
1733                                          *type_offset + (has_size ? 4 : 2));
1734             }
1735         }
1736         else if (is_array_type(var->attrs, var->ptr_level, var->array))
1737         {
1738             const char *array_type;
1739
1740             if (var->array && NEXT_LINK(var->array)) /* multi-dimensional array */
1741                 array_type = "ComplexArray";
1742             else
1743             {
1744                 if (!has_length && !has_size)
1745                     array_type = "FixedArray";
1746                 else if (has_length && !has_size)
1747                 {
1748                     if (is_size_needed_for_phase(phase))
1749                     {
1750                         print_file(file, indent, "_StubMsg.Offset = (unsigned long)0;\n"); /* FIXME */
1751                         print_file(file, indent, "_StubMsg.ActualCount = (unsigned long)");
1752                         write_expr(file, length_is, 1);
1753                         fprintf(file, ";\n\n");
1754                     }
1755                     array_type = "VaryingArray";
1756                 }
1757                 else if (!has_length && has_size)
1758                 {
1759                     if (is_size_needed_for_phase(phase) && phase != PHASE_FREE)
1760                     {
1761                         print_file(file, indent, "_StubMsg.MaxCount = (unsigned long)");
1762                         write_expr(file, size_is ? size_is : var->array, 1);
1763                         fprintf(file, ";\n\n");
1764                     }
1765                     array_type = "ConformantArray";
1766                 }
1767                 else
1768                 {
1769                     if (is_size_needed_for_phase(phase))
1770                     {
1771                         print_file(file, indent, "_StubMsg.MaxCount = (unsigned long)");
1772                         write_expr(file, size_is ? size_is : var->array, 1);
1773                         fprintf(file, ";\n");
1774                         print_file(file, indent, "_StubMsg.Offset = (unsigned long)0;\n"); /* FIXME */
1775                         print_file(file, indent, "_StubMsg.ActualCount = (unsigned long)");
1776                         write_expr(file, length_is, 1);
1777                         fprintf(file, ";\n\n");
1778                     }
1779                     array_type = "ConformantVaryingArray";
1780                 }
1781             }
1782
1783             if (!in_attr && phase == PHASE_FREE)
1784             {
1785                 print_file(file, indent, "if (%s)\n", var->name);
1786                 indent++;
1787                 print_file(file, indent, "_StubMsg.pfnFree(%s);\n", var->name);
1788             }
1789             else if (phase != PHASE_FREE)
1790             {
1791                 if (pointer_type == RPC_FC_UP)
1792                     print_phase_function(file, indent, "Pointer", phase, var->name, *type_offset);
1793                 else
1794                     print_phase_function(file, indent, array_type, phase, var->name, *type_offset + 4);
1795             }
1796         }
1797         else if (var->ptr_level == 0 && is_base_type(type->type))
1798         {
1799             print_phase_basetype(file, indent, phase, pass, var, var->name);
1800         }
1801         else if (var->ptr_level == 0)
1802         {
1803             const char *ndrtype;
1804
1805             switch (type->type)
1806             {
1807             case RPC_FC_STRUCT:
1808                 ndrtype = "SimpleStruct";
1809                 break;
1810             case RPC_FC_CSTRUCT:
1811             case RPC_FC_CPSTRUCT:
1812                 ndrtype = "ConformantStruct";
1813                 break;
1814             case RPC_FC_CVSTRUCT:
1815                 ndrtype = "ConformantVaryingStruct";
1816                 break;
1817             case RPC_FC_BOGUS_STRUCT:
1818                 ndrtype = "ComplexStruct";
1819                 break;
1820             default:
1821                 error("write_remoting_arguments: Unsupported type: %s (0x%02x, ptr_level: %d)\n",
1822                     var->name, type->type, var->ptr_level);
1823                 ndrtype = NULL;
1824             }
1825
1826             print_phase_function(file, indent, ndrtype, phase, var->name, *type_offset);
1827         }
1828         else
1829         {
1830             if ((var->ptr_level == 1) && (pointer_type == RPC_FC_RP) && is_base_type(type->type))
1831             {
1832                 print_phase_basetype(file, indent, phase, pass, var, var->name);
1833             }
1834             else if ((var->ptr_level == 1) && (pointer_type == RPC_FC_RP) && (type->type == RPC_FC_STRUCT))
1835             {
1836                 if (phase != PHASE_BUFFERSIZE && phase != PHASE_FREE)
1837                     print_phase_function(file, indent, "SimpleStruct", phase, var->name, *type_offset + 4);
1838             }
1839             else
1840             {
1841                 print_phase_function(file, indent, "Pointer", phase, var->name, *type_offset);
1842             }
1843         }
1844         fprintf(file, "\n");
1845     }
1846 }
1847
1848
1849 size_t get_size_procformatstring_var(const var_t *var)
1850 {
1851     unsigned int type_offset = 2;
1852     return write_procformatstring_var(NULL, 0, var, FALSE, &type_offset);
1853 }
1854
1855
1856 size_t get_size_typeformatstring_var(const var_t *var)
1857 {
1858     unsigned int type_offset = 0;
1859     write_typeformatstring_var(NULL, 0, var, &type_offset);
1860     return type_offset;
1861 }
1862
1863 size_t get_size_procformatstring(const ifref_t *ifaces)
1864 {
1865     const ifref_t *iface = ifaces;
1866     size_t size = 1;
1867     func_t *func;
1868     var_t *var;
1869
1870     END_OF_LIST(iface);
1871
1872     for (; iface; iface = PREV_LINK(iface))
1873     {
1874         if (is_object(iface->iface->attrs) || is_local(iface->iface->attrs))
1875             continue;
1876
1877         if (iface->iface->funcs)
1878         {
1879             func = iface->iface->funcs;
1880             while (NEXT_LINK(func)) func = NEXT_LINK(func);
1881             while (func)
1882             {
1883                 /* argument list size */
1884                 if (func->args)
1885                 {
1886                     var = func->args;
1887                     while (NEXT_LINK(var)) var = NEXT_LINK(var);
1888                     while (var)
1889                     {
1890                         size += get_size_procformatstring_var(var);
1891                         var = PREV_LINK(var);
1892                     }
1893                 }
1894
1895                 var = func->def;
1896                 /* return value size */
1897                 if (is_void(var->type, NULL))
1898                     size += 2;
1899                 else
1900                     size += get_size_procformatstring_var(var);
1901
1902                 func = PREV_LINK(func);
1903             }
1904         }
1905     }
1906     return size;
1907 }
1908
1909 size_t get_size_typeformatstring(const ifref_t *ifaces)
1910 {
1911     const ifref_t *iface = ifaces;
1912     size_t size = 3;
1913     func_t *func;
1914     var_t *var;
1915
1916     END_OF_LIST(iface);
1917
1918     for (; iface; iface = PREV_LINK(iface))
1919     {
1920         if (is_object(iface->iface->attrs) || is_local(iface->iface->attrs))
1921             continue;
1922
1923         if (iface->iface->funcs)
1924         {
1925             func = iface->iface->funcs;
1926             while (NEXT_LINK(func)) func = NEXT_LINK(func);
1927             while (func)
1928             {
1929                 /* argument list size */
1930                 if (func->args)
1931                 {
1932                     var = func->args;
1933                     while (NEXT_LINK(var)) var = NEXT_LINK(var);
1934                     while (var)
1935                     {
1936                         size += get_size_typeformatstring_var(var);
1937                         var = PREV_LINK(var);
1938                     }
1939                 }
1940
1941                 func = PREV_LINK(func);
1942             }
1943         }
1944     }
1945     return size;
1946 }
1947
1948 static void write_struct_expr(FILE *h, const expr_t *e, int brackets,
1949                               const var_t *fields, const char *structvar)
1950 {
1951     switch (e->type) {
1952         case EXPR_VOID:
1953             break;
1954         case EXPR_NUM:
1955             fprintf(h, "%ld", e->u.lval);
1956             break;
1957         case EXPR_HEXNUM:
1958             fprintf(h, "0x%lx", e->u.lval);
1959             break;
1960         case EXPR_IDENTIFIER:
1961         {
1962             const var_t *field;
1963             for (field = fields; field; field = NEXT_LINK(field))
1964             {
1965                 if (!strcmp(e->u.sval, field->name))
1966                 {
1967                     fprintf(h, "%s->%s", structvar, e->u.sval);
1968                     break;
1969                 }
1970             }
1971             if (!field) error("no field found for identifier %s\n", e->u.sval);
1972             break;
1973         }
1974         case EXPR_NEG:
1975             fprintf(h, "-");
1976             write_struct_expr(h, e->ref, 1, fields, structvar);
1977             break;
1978         case EXPR_NOT:
1979             fprintf(h, "~");
1980             write_struct_expr(h, e->ref, 1, fields, structvar);
1981             break;
1982         case EXPR_PPTR:
1983             fprintf(h, "*");
1984             write_struct_expr(h, e->ref, 1, fields, structvar);
1985             break;
1986         case EXPR_CAST:
1987             fprintf(h, "(");
1988             write_type(h, e->u.tref->ref, NULL, e->u.tref->name);
1989             fprintf(h, ")");
1990             write_struct_expr(h, e->ref, 1, fields, structvar);
1991             break;
1992         case EXPR_SIZEOF:
1993             fprintf(h, "sizeof(");
1994             write_type(h, e->u.tref->ref, NULL, e->u.tref->name);
1995             fprintf(h, ")");
1996             break;
1997         case EXPR_SHL:
1998         case EXPR_SHR:
1999         case EXPR_MUL:
2000         case EXPR_DIV:
2001         case EXPR_ADD:
2002         case EXPR_SUB:
2003         case EXPR_AND:
2004         case EXPR_OR:
2005             if (brackets) fprintf(h, "(");
2006             write_struct_expr(h, e->ref, 1, fields, structvar);
2007             switch (e->type) {
2008                 case EXPR_SHL: fprintf(h, " << "); break;
2009                 case EXPR_SHR: fprintf(h, " >> "); break;
2010                 case EXPR_MUL: fprintf(h, " * "); break;
2011                 case EXPR_DIV: fprintf(h, " / "); break;
2012                 case EXPR_ADD: fprintf(h, " + "); break;
2013                 case EXPR_SUB: fprintf(h, " - "); break;
2014                 case EXPR_AND: fprintf(h, " & "); break;
2015                 case EXPR_OR:  fprintf(h, " | "); break;
2016                 default: break;
2017             }
2018             write_struct_expr(h, e->u.ext, 1, fields, structvar);
2019             if (brackets) fprintf(h, ")");
2020             break;
2021         case EXPR_COND:
2022             if (brackets) fprintf(h, "(");
2023             write_struct_expr(h, e->ref, 1, fields, structvar);
2024             fprintf(h, " ? ");
2025             write_struct_expr(h, e->u.ext, 1, fields, structvar);
2026             fprintf(h, " : ");
2027             write_struct_expr(h, e->ext2, 1, fields, structvar);
2028             if (brackets) fprintf(h, ")");
2029             break;
2030     }
2031 }
2032
2033 int write_expr_eval_routines(FILE *file, const char *iface)
2034 {
2035     int result = 0;
2036     struct expr_eval_routine *eval;
2037     unsigned short callback_offset = 0;
2038
2039     LIST_FOR_EACH_ENTRY(eval, &expr_eval_routines, struct expr_eval_routine, entry)
2040     {
2041         int indent = 0;
2042         result = 1;
2043         print_file(file, indent, "static void __RPC_USER %s_%sExprEval_%04u(PMIDL_STUB_MESSAGE pStubMsg)\n",
2044                   iface, eval->structure->name, callback_offset);
2045         print_file(file, indent, "{\n");
2046         indent++;
2047         print_file(file, indent, "struct %s *" STRUCT_EXPR_EVAL_VAR " = (struct %s *)(pStubMsg->StackTop - %u);\n",
2048                    eval->structure->name, eval->structure->name, eval->structure_size);
2049         fprintf(file, "\n");
2050         print_file(file, indent, "pStubMsg->Offset = 0;\n"); /* FIXME */
2051         print_file(file, indent, "pStubMsg->MaxCount = (unsigned long)");
2052         write_struct_expr(file, eval->expr, 1, eval->structure->fields, STRUCT_EXPR_EVAL_VAR);
2053         fprintf(file, ";\n");
2054         indent--;
2055         print_file(file, indent, "}\n\n");
2056         callback_offset++;
2057     }
2058     return result;
2059 }
2060
2061 void write_expr_eval_routine_list(FILE *file, const char *iface)
2062 {
2063     struct expr_eval_routine *eval;
2064     struct expr_eval_routine *cursor;
2065     unsigned short callback_offset = 0;
2066
2067     fprintf(file, "static const EXPR_EVAL ExprEvalRoutines[] =\n");
2068     fprintf(file, "{\n");
2069
2070     LIST_FOR_EACH_ENTRY_SAFE(eval, cursor, &expr_eval_routines, struct expr_eval_routine, entry)
2071     {
2072         print_file(file, 1, "%s_%sExprEval_%04u,\n",
2073                    iface, eval->structure->name, callback_offset);
2074
2075         callback_offset++;
2076         list_remove(&eval->entry);
2077         free(eval);
2078     }
2079
2080     fprintf(file, "};\n\n");
2081 }