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