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