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