urlmon: Don't create stgmed_obj for binding to object.
[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 "wine/list.h"
41
42 #include "typegen.h"
43
44 static const func_t *current_func;
45 static const type_t *current_structure;
46 static const ifref_t *current_iface;
47
48 static struct list expr_eval_routines = LIST_INIT(expr_eval_routines);
49 struct expr_eval_routine
50 {
51     struct list entry;
52     const type_t *structure;
53     unsigned int baseoff;
54     const expr_t *expr;
55 };
56
57 static size_t fields_memsize(const var_list_t *fields, unsigned int *align);
58 static size_t write_struct_tfs(FILE *file, type_t *type, const char *name, unsigned int *tfsoff);
59 static int write_embedded_types(FILE *file, const attr_list_t *attrs, type_t *type,
60                                 const char *name, int write_ptr, unsigned int *tfsoff);
61 static const var_t *find_array_or_string_in_struct(const type_t *type);
62
63 const char *string_of_type(unsigned char type)
64 {
65     switch (type)
66     {
67     case RPC_FC_BYTE: return "FC_BYTE";
68     case RPC_FC_CHAR: return "FC_CHAR";
69     case RPC_FC_SMALL: return "FC_SMALL";
70     case RPC_FC_USMALL: return "FC_USMALL";
71     case RPC_FC_WCHAR: return "FC_WCHAR";
72     case RPC_FC_SHORT: return "FC_SHORT";
73     case RPC_FC_USHORT: return "FC_USHORT";
74     case RPC_FC_LONG: return "FC_LONG";
75     case RPC_FC_ULONG: return "FC_ULONG";
76     case RPC_FC_FLOAT: return "FC_FLOAT";
77     case RPC_FC_HYPER: return "FC_HYPER";
78     case RPC_FC_DOUBLE: return "FC_DOUBLE";
79     case RPC_FC_ENUM16: return "FC_ENUM16";
80     case RPC_FC_ENUM32: return "FC_ENUM32";
81     case RPC_FC_IGNORE: return "FC_IGNORE";
82     case RPC_FC_ERROR_STATUS_T: return "FC_ERROR_STATUS_T";
83     case RPC_FC_RP: return "FC_RP";
84     case RPC_FC_UP: return "FC_UP";
85     case RPC_FC_OP: return "FC_OP";
86     case RPC_FC_FP: return "FC_FP";
87     case RPC_FC_ENCAPSULATED_UNION: return "FC_ENCAPSULATED_UNION";
88     case RPC_FC_NON_ENCAPSULATED_UNION: return "FC_NON_ENCAPSULATED_UNION";
89     case RPC_FC_STRUCT: return "FC_STRUCT";
90     case RPC_FC_PSTRUCT: return "FC_PSTRUCT";
91     case RPC_FC_CSTRUCT: return "FC_CSTRUCT";
92     case RPC_FC_CPSTRUCT: return "FC_CPSTRUCT";
93     case RPC_FC_CVSTRUCT: return "FC_CVSTRUCT";
94     case RPC_FC_BOGUS_STRUCT: return "FC_BOGUS_STRUCT";
95     case RPC_FC_SMFARRAY: return "FC_SMFARRAY";
96     case RPC_FC_LGFARRAY: return "FC_LGFARRAY";
97     case RPC_FC_SMVARRAY: return "FC_SMVARRAY";
98     case RPC_FC_LGVARRAY: return "FC_LGVARRAY";
99     case RPC_FC_CARRAY: return "FC_CARRAY";
100     case RPC_FC_CVARRAY: return "FC_CVARRAY";
101     case RPC_FC_BOGUS_ARRAY: return "FC_BOGUS_ARRAY";
102     case RPC_FC_ALIGNM4: return "FC_ALIGNM4";
103     case RPC_FC_ALIGNM8: return "FC_ALIGNM8";
104     case RPC_FC_POINTER: return "FC_POINTER";
105     case RPC_FC_C_CSTRING: return "FC_C_CSTRING";
106     case RPC_FC_C_WSTRING: return "FC_C_WSTRING";
107     case RPC_FC_CSTRING: return "FC_CSTRING";
108     case RPC_FC_WSTRING: return "FC_WSTRING";
109     default:
110         error("string_of_type: unknown type 0x%02x\n", type);
111         return NULL;
112     }
113 }
114
115 int is_struct(unsigned char type)
116 {
117     switch (type)
118     {
119     case RPC_FC_STRUCT:
120     case RPC_FC_PSTRUCT:
121     case RPC_FC_CSTRUCT:
122     case RPC_FC_CPSTRUCT:
123     case RPC_FC_CVSTRUCT:
124     case RPC_FC_BOGUS_STRUCT:
125         return 1;
126     default:
127         return 0;
128     }
129 }
130
131 static int is_non_complex_struct(const type_t *type)
132 {
133     switch (type->type)
134     {
135     case RPC_FC_STRUCT:
136     case RPC_FC_PSTRUCT:
137     case RPC_FC_CSTRUCT:
138     case RPC_FC_CPSTRUCT:
139     case RPC_FC_CVSTRUCT:
140         return 1;
141     default:
142         return 0;
143     }
144 }
145
146 int is_union(unsigned char type)
147 {
148     switch (type)
149     {
150     case RPC_FC_ENCAPSULATED_UNION:
151     case RPC_FC_NON_ENCAPSULATED_UNION:
152         return 1;
153     default:
154         return 0;
155     }
156 }
157
158 static int type_has_pointers(const type_t *type)
159 {
160     if (is_user_type(type))
161         return FALSE;
162     else if (is_ptr(type))
163         return TRUE;
164     else if (is_array(type))
165         return type_has_pointers(type->ref);
166     else if (is_struct(type->type))
167     {
168         const var_t *field;
169         if (type->fields) LIST_FOR_EACH_ENTRY( field, type->fields, const var_t, entry )
170         {
171             if (type_has_pointers(field->type))
172                 return TRUE;
173         }
174     }
175     else if (is_union(type->type))
176     {
177         var_list_t *fields;
178         const var_t *field;
179         if (type->type == RPC_FC_ENCAPSULATED_UNION)
180         {
181             const var_t *uv = LIST_ENTRY(list_tail(type->fields), const var_t, entry);
182             fields = uv->type->fields;
183         }
184         else
185             fields = type->fields;
186         if (fields) LIST_FOR_EACH_ENTRY( field, fields, const var_t, entry )
187         {
188             if (field->type && type_has_pointers(field->type))
189                 return TRUE;
190         }
191     }
192
193     return FALSE;
194 }
195
196 static int type_has_full_pointer(const type_t *type)
197 {
198     if (is_user_type(type))
199         return FALSE;
200     else if (type->type == RPC_FC_FP)
201         return TRUE;
202     else if (is_ptr(type))
203         return FALSE;
204     else if (is_array(type))
205         return type_has_full_pointer(type->ref);
206     else if (is_struct(type->type))
207     {
208         const var_t *field;
209         if (type->fields) LIST_FOR_EACH_ENTRY( field, type->fields, const var_t, entry )
210         {
211             if (type_has_full_pointer(field->type))
212                 return TRUE;
213         }
214     }
215     else if (is_union(type->type))
216     {
217         var_list_t *fields;
218         const var_t *field;
219         if (type->type == RPC_FC_ENCAPSULATED_UNION)
220         {
221             const var_t *uv = LIST_ENTRY(list_tail(type->fields), const var_t, entry);
222             fields = uv->type->fields;
223         }
224         else
225             fields = type->fields;
226         if (fields) LIST_FOR_EACH_ENTRY( field, fields, const var_t, entry )
227         {
228             if (field->type && type_has_full_pointer(field->type))
229                 return TRUE;
230         }
231     }
232
233     return FALSE;
234 }
235
236 static unsigned short user_type_offset(const char *name)
237 {
238     user_type_t *ut;
239     unsigned short off = 0;
240     LIST_FOR_EACH_ENTRY(ut, &user_type_list, user_type_t, entry)
241     {
242         if (strcmp(name, ut->name) == 0)
243             return off;
244         ++off;
245     }
246     error("user_type_offset: couldn't find type (%s)\n", name);
247     return 0;
248 }
249
250 static void update_tfsoff(type_t *type, unsigned int offset, FILE *file)
251 {
252     type->typestring_offset = offset;
253     if (file) type->tfswrite = FALSE;
254 }
255
256 static void guard_rec(type_t *type)
257 {
258     /* types that contain references to themselves (like a linked list),
259        need to be shielded from infinite recursion when writing embedded
260        types  */
261     if (type->typestring_offset)
262         type->tfswrite = FALSE;
263     else
264         type->typestring_offset = 1;
265 }
266
267 static type_t *get_user_type(const type_t *t, const char **pname)
268 {
269     for (;;)
270     {
271         type_t *ut = get_attrp(t->attrs, ATTR_WIREMARSHAL);
272         if (ut)
273         {
274             if (pname)
275                 *pname = t->name;
276             return ut;
277         }
278
279         if (t->kind == TKIND_ALIAS)
280             t = t->orig;
281         else
282             return 0;
283     }
284 }
285
286 int is_user_type(const type_t *t)
287 {
288     return get_user_type(t, NULL) != NULL;
289 }
290
291 static int is_embedded_complex(const type_t *type)
292 {
293     unsigned char tc = type->type;
294     return is_struct(tc) || is_union(tc) || is_array(type) || is_user_type(type)
295         || (is_ptr(type) && type->ref->type == RPC_FC_IP);
296 }
297
298 static const char *get_context_handle_type_name(const type_t *type)
299 {
300     const type_t *t;
301     for (t = type; is_ptr(t); t = t->ref)
302         if (is_attr(t->attrs, ATTR_CONTEXTHANDLE))
303             return t->name;
304     assert(0);
305     return NULL;
306 }
307
308 /* This is actually fairly involved to implement precisely, due to the
309    effects attributes may have and things like that.  Right now this is
310    only used for optimization, so just check for a very small set of
311    criteria that guarantee the types are equivalent; assume every thing
312    else is different.   */
313 static int compare_type(const type_t *a, const type_t *b)
314 {
315     if (a == b
316         || (a->name
317             && b->name
318             && strcmp(a->name, b->name) == 0))
319         return 0;
320     /* Ordering doesn't need to be implemented yet.  */
321     return 1;
322 }
323
324 static int compare_expr(const expr_t *a, const expr_t *b)
325 {
326     int ret;
327
328     if (a->type != b->type)
329         return a->type - b->type;
330
331     switch (a->type)
332     {
333         case EXPR_NUM:
334         case EXPR_HEXNUM:
335         case EXPR_TRUEFALSE:
336             return a->u.lval - b->u.lval;
337         case EXPR_DOUBLE:
338             return a->u.dval - b->u.dval;
339         case EXPR_IDENTIFIER:
340             return strcmp(a->u.sval, b->u.sval);
341         case EXPR_COND:
342             ret = compare_expr(a->ref, b->ref);
343             if (ret != 0)
344                 return ret;
345             ret = compare_expr(a->u.ext, b->u.ext);
346             if (ret != 0)
347                 return ret;
348             return compare_expr(a->ext2, b->ext2);
349         case EXPR_OR:
350         case EXPR_AND:
351         case EXPR_ADD:
352         case EXPR_SUB:
353         case EXPR_MUL:
354         case EXPR_DIV:
355         case EXPR_SHL:
356         case EXPR_SHR:
357             ret = compare_expr(a->ref, b->ref);
358             if (ret != 0)
359                 return ret;
360             return compare_expr(a->u.ext, b->u.ext);
361         case EXPR_CAST:
362             ret = compare_type(a->u.tref, b->u.tref);
363             if (ret != 0)
364                 return ret;
365             /* Fall through.  */
366         case EXPR_NOT:
367         case EXPR_NEG:
368         case EXPR_PPTR:
369         case EXPR_ADDRESSOF:
370             return compare_expr(a->ref, b->ref);
371         case EXPR_SIZEOF:
372             return compare_type(a->u.tref, b->u.tref);
373         case EXPR_VOID:
374             return 0;
375     }
376     return -1;
377 }
378
379 #define WRITE_FCTYPE(file, fctype, typestring_offset) \
380     do { \
381         if (file) \
382             fprintf(file, "/* %2u */\n", typestring_offset); \
383         print_file((file), 2, "0x%02x,    /* " #fctype " */\n", RPC_##fctype); \
384     } \
385     while (0)
386
387 static void print_file(FILE *file, int indent, const char *format, ...)
388 {
389     va_list va;
390     va_start(va, format);
391     print(file, indent, format, va);
392     va_end(va);
393 }
394
395 void print(FILE *file, int indent, const char *format, va_list va)
396 {
397     if (file)
398     {
399         if (format[0] != '\n')
400             while (0 < indent--)
401                 fprintf(file, "    ");
402         vfprintf(file, format, va);
403     }
404 }
405
406
407 static void write_var_init(FILE *file, int indent, const type_t *t, const char *n)
408 {
409     if (decl_indirect(t))
410         print_file(file, indent, "MIDL_memset(&%s, 0, sizeof(%s));\n", n, n);
411     else if (is_ptr(t) || is_array(t))
412         print_file(file, indent, "%s = 0;\n", n);
413 }
414
415 void write_parameters_init(FILE *file, int indent, const func_t *func)
416 {
417     const var_t *var;
418
419     if (!is_void(func->def->type))
420         write_var_init(file, indent, func->def->type, "_RetVal");
421
422     if (!func->args)
423         return;
424
425     LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
426         write_var_init(file, indent, var->type, var->name);
427
428     fprintf(file, "\n");
429 }
430
431 static void write_formatdesc(FILE *f, int indent, const char *str)
432 {
433     print_file(f, indent, "typedef struct _MIDL_%s_FORMAT_STRING\n", str);
434     print_file(f, indent, "{\n");
435     print_file(f, indent + 1, "short Pad;\n");
436     print_file(f, indent + 1, "unsigned char Format[%s_FORMAT_STRING_SIZE];\n", str);
437     print_file(f, indent, "} MIDL_%s_FORMAT_STRING;\n", str);
438     print_file(f, indent, "\n");
439 }
440
441 void write_formatstringsdecl(FILE *f, int indent, ifref_list_t *ifaces, type_pred_t pred)
442 {
443     print_file(f, indent, "#define TYPE_FORMAT_STRING_SIZE %d\n",
444                get_size_typeformatstring(ifaces, pred));
445
446     print_file(f, indent, "#define PROC_FORMAT_STRING_SIZE %d\n",
447                get_size_procformatstring(ifaces, pred));
448
449     fprintf(f, "\n");
450     write_formatdesc(f, indent, "TYPE");
451     write_formatdesc(f, indent, "PROC");
452     fprintf(f, "\n");
453     print_file(f, indent, "static const MIDL_TYPE_FORMAT_STRING __MIDL_TypeFormatString;\n");
454     print_file(f, indent, "static const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString;\n");
455     print_file(f, indent, "\n");
456 }
457
458 static inline int is_base_type(unsigned char type)
459 {
460     switch (type)
461     {
462     case RPC_FC_BYTE:
463     case RPC_FC_CHAR:
464     case RPC_FC_USMALL:
465     case RPC_FC_SMALL:
466     case RPC_FC_WCHAR:
467     case RPC_FC_USHORT:
468     case RPC_FC_SHORT:
469     case RPC_FC_ULONG:
470     case RPC_FC_LONG:
471     case RPC_FC_HYPER:
472     case RPC_FC_IGNORE:
473     case RPC_FC_FLOAT:
474     case RPC_FC_DOUBLE:
475     case RPC_FC_ENUM16:
476     case RPC_FC_ENUM32:
477     case RPC_FC_ERROR_STATUS_T:
478     case RPC_FC_BIND_PRIMITIVE:
479         return TRUE;
480
481     default:
482         return FALSE;
483     }
484 }
485
486 int decl_indirect(const type_t *t)
487 {
488     return is_user_type(t)
489         || (!is_base_type(t->type)
490             && !is_ptr(t)
491             && !is_array(t));
492 }
493
494 static size_t write_procformatstring_var(FILE *file, int indent,
495                                          const var_t *var, int is_return)
496 {
497     size_t size;
498     const type_t *type = var->type;
499
500     int is_in = is_attr(var->attrs, ATTR_IN);
501     int is_out = is_attr(var->attrs, ATTR_OUT);
502
503     if (!is_in && !is_out) is_in = TRUE;
504
505     if (!type->declarray && is_base_type(type->type))
506     {
507         if (is_return)
508             print_file(file, indent, "0x53,    /* FC_RETURN_PARAM_BASETYPE */\n");
509         else
510             print_file(file, indent, "0x4e,    /* FC_IN_PARAM_BASETYPE */\n");
511
512         if (type->type == RPC_FC_BIND_PRIMITIVE)
513         {
514             print_file(file, indent, "0x%02x,    /* FC_IGNORE */\n", RPC_FC_IGNORE);
515             size = 2; /* includes param type prefix */
516         }
517         else if (is_base_type(type->type))
518         {
519             print_file(file, indent, "0x%02x,    /* %s */\n", type->type, string_of_type(type->type));
520             size = 2; /* includes param type prefix */
521         }
522         else
523         {
524             error("Unknown/unsupported type: %s (0x%02x)\n", var->name, type->type);
525             size = 0;
526         }
527     }
528     else
529     {
530         if (is_return)
531             print_file(file, indent, "0x52,    /* FC_RETURN_PARAM */\n");
532         else if (is_in && is_out)
533             print_file(file, indent, "0x50,    /* FC_IN_OUT_PARAM */\n");
534         else if (is_out)
535             print_file(file, indent, "0x51,    /* FC_OUT_PARAM */\n");
536         else
537             print_file(file, indent, "0x4d,    /* FC_IN_PARAM */\n");
538
539         print_file(file, indent, "0x01,\n");
540         print_file(file, indent, "NdrFcShort(0x%x),\n", type->typestring_offset);
541         size = 4; /* includes param type prefix */
542     }
543     return size;
544 }
545
546 void write_procformatstring(FILE *file, const ifref_list_t *ifaces, type_pred_t pred)
547 {
548     const ifref_t *iface;
549     int indent = 0;
550     const var_t *var;
551
552     print_file(file, indent, "static const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString =\n");
553     print_file(file, indent, "{\n");
554     indent++;
555     print_file(file, indent, "0,\n");
556     print_file(file, indent, "{\n");
557     indent++;
558
559     if (ifaces) LIST_FOR_EACH_ENTRY( iface, ifaces, const ifref_t, entry )
560     {
561         if (!pred(iface->iface))
562             continue;
563
564         if (iface->iface->funcs)
565         {
566             const func_t *func;
567             LIST_FOR_EACH_ENTRY( func, iface->iface->funcs, const func_t, entry )
568             {
569                 if (is_local(func->def->attrs)) continue;
570                 /* emit argument data */
571                 if (func->args)
572                 {
573                     LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
574                         write_procformatstring_var(file, indent, var, FALSE);
575                 }
576
577                 /* emit return value data */
578                 var = func->def;
579                 if (is_void(var->type))
580                 {
581                     print_file(file, indent, "0x5b,    /* FC_END */\n");
582                     print_file(file, indent, "0x5c,    /* FC_PAD */\n");
583                 }
584                 else
585                     write_procformatstring_var(file, indent, var, TRUE);
586             }
587         }
588     }
589
590     print_file(file, indent, "0x0\n");
591     indent--;
592     print_file(file, indent, "}\n");
593     indent--;
594     print_file(file, indent, "};\n");
595     print_file(file, indent, "\n");
596 }
597
598 static int write_base_type(FILE *file, const type_t *type, unsigned int *typestring_offset)
599 {
600     if (is_base_type(type->type))
601     {
602         print_file(file, 2, "0x%02x,\t/* %s */\n", type->type, string_of_type(type->type));
603         *typestring_offset += 1;
604         return 1;
605     }
606
607     return 0;
608 }
609
610 /* write conformance / variance descriptor */
611 static size_t write_conf_or_var_desc(FILE *file, const type_t *structure,
612                                      unsigned int baseoff, const type_t *type,
613                                      const expr_t *expr)
614 {
615     unsigned char operator_type = 0;
616     unsigned char conftype = RPC_FC_NORMAL_CONFORMANCE;
617     const char *conftype_string = "";
618     const char *operator_string = "no operators";
619     const expr_t *subexpr;
620
621     if (!expr)
622     {
623         print_file(file, 2, "NdrFcLong(0xffffffff),\t/* -1 */\n");
624         return 4;
625     }
626
627     if (!structure)
628     {
629         /* Top-level conformance calculations are done inline.  */
630         print_file (file, 2, "0x%x,\t/* Corr desc: parameter */\n",
631                     RPC_FC_TOP_LEVEL_CONFORMANCE);
632         print_file (file, 2, "0x0,\n");
633         print_file (file, 2, "NdrFcShort(0x0),\n");
634         return 4;
635     }
636
637     if (expr->is_const)
638     {
639         if (expr->cval > UCHAR_MAX * (USHRT_MAX + 1) + USHRT_MAX)
640             error("write_conf_or_var_desc: constant value %ld is greater than "
641                   "the maximum constant size of %d\n", expr->cval,
642                   UCHAR_MAX * (USHRT_MAX + 1) + USHRT_MAX);
643
644         print_file(file, 2, "0x%x, /* Corr desc: constant, val = %ld */\n",
645                    RPC_FC_CONSTANT_CONFORMANCE, expr->cval);
646         print_file(file, 2, "0x%x,\n", expr->cval & ~USHRT_MAX);
647         print_file(file, 2, "NdrFcShort(0x%x),\n", expr->cval & USHRT_MAX);
648
649         return 4;
650     }
651
652     if (is_ptr(type) || (is_array(type) && !type->declarray))
653     {
654         conftype = RPC_FC_POINTER_CONFORMANCE;
655         conftype_string = "field pointer, ";
656     }
657
658     subexpr = expr;
659     switch (subexpr->type)
660     {
661     case EXPR_PPTR:
662         subexpr = subexpr->ref;
663         operator_type = RPC_FC_DEREFERENCE;
664         operator_string = "FC_DEREFERENCE";
665         break;
666     case EXPR_DIV:
667         if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 2))
668         {
669             subexpr = subexpr->ref;
670             operator_type = RPC_FC_DIV_2;
671             operator_string = "FC_DIV_2";
672         }
673         break;
674     case EXPR_MUL:
675         if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 2))
676         {
677             subexpr = subexpr->ref;
678             operator_type = RPC_FC_MULT_2;
679             operator_string = "FC_MULT_2";
680         }
681         break;
682     case EXPR_SUB:
683         if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 1))
684         {
685             subexpr = subexpr->ref;
686             operator_type = RPC_FC_SUB_1;
687             operator_string = "FC_SUB_1";
688         }
689         break;
690     case EXPR_ADD:
691         if (subexpr->u.ext->is_const && (subexpr->u.ext->cval == 1))
692         {
693             subexpr = subexpr->ref;
694             operator_type = RPC_FC_ADD_1;
695             operator_string = "FC_ADD_1";
696         }
697         break;
698     default:
699         break;
700     }
701
702     if (subexpr->type == EXPR_IDENTIFIER)
703     {
704         const type_t *correlation_variable = NULL;
705         unsigned char correlation_variable_type;
706         unsigned char param_type = 0;
707         size_t offset = 0;
708         const var_t *var;
709
710         if (structure->fields) LIST_FOR_EACH_ENTRY( var, structure->fields, const var_t, entry )
711         {
712             unsigned int align = 0;
713             /* FIXME: take alignment into account */
714             if (var->name && !strcmp(var->name, subexpr->u.sval))
715             {
716                 correlation_variable = var->type;
717                 break;
718             }
719             offset += type_memsize(var->type, &align);
720         }
721         if (!correlation_variable)
722             error("write_conf_or_var_desc: couldn't find variable %s in structure\n",
723                   subexpr->u.sval);
724
725         offset -= baseoff;
726         correlation_variable_type = correlation_variable->type;
727
728         switch (correlation_variable_type)
729         {
730         case RPC_FC_CHAR:
731         case RPC_FC_SMALL:
732             param_type = RPC_FC_SMALL;
733             break;
734         case RPC_FC_BYTE:
735         case RPC_FC_USMALL:
736             param_type = RPC_FC_USMALL;
737             break;
738         case RPC_FC_WCHAR:
739         case RPC_FC_SHORT:
740         case RPC_FC_ENUM16:
741             param_type = RPC_FC_SHORT;
742             break;
743         case RPC_FC_USHORT:
744             param_type = RPC_FC_USHORT;
745             break;
746         case RPC_FC_LONG:
747         case RPC_FC_ENUM32:
748             param_type = RPC_FC_LONG;
749             break;
750         case RPC_FC_ULONG:
751             param_type = RPC_FC_ULONG;
752             break;
753         case RPC_FC_RP:
754         case RPC_FC_UP:
755         case RPC_FC_OP:
756         case RPC_FC_FP:
757             if (sizeof(void *) == 4)  /* FIXME */
758                 param_type = RPC_FC_LONG;
759             else
760                 param_type = RPC_FC_HYPER;
761             break;
762         default:
763             error("write_conf_or_var_desc: conformance variable type not supported 0x%x\n",
764                 correlation_variable_type);
765         }
766
767         print_file(file, 2, "0x%x, /* Corr desc: %s%s */\n",
768                    conftype | param_type, conftype_string, string_of_type(param_type));
769         print_file(file, 2, "0x%x, /* %s */\n", operator_type, operator_string);
770         print_file(file, 2, "NdrFcShort(0x%x), /* offset = %d */\n",
771                    offset, offset);
772     }
773     else
774     {
775         unsigned int callback_offset = 0;
776         struct expr_eval_routine *eval;
777         int found = 0;
778
779         LIST_FOR_EACH_ENTRY(eval, &expr_eval_routines, struct expr_eval_routine, entry)
780         {
781             if (!strcmp (eval->structure->name, structure->name)
782                 && !compare_expr (eval->expr, expr))
783             {
784                 found = 1;
785                 break;
786             }
787             callback_offset++;
788         }
789
790         if (!found)
791         {
792             eval = xmalloc (sizeof(*eval));
793             eval->structure = structure;
794             eval->baseoff = baseoff;
795             eval->expr = expr;
796             list_add_tail (&expr_eval_routines, &eval->entry);
797         }
798
799         if (callback_offset > USHRT_MAX)
800             error("Maximum number of callback routines reached\n");
801
802         print_file(file, 2, "0x%x, /* Corr desc: %s */\n", conftype, conftype_string);
803         print_file(file, 2, "0x%x, /* %s */\n", RPC_FC_CALLBACK, "FC_CALLBACK");
804         print_file(file, 2, "NdrFcShort(0x%x), /* %u */\n", callback_offset, callback_offset);
805     }
806     return 4;
807 }
808
809 static size_t fields_memsize(const var_list_t *fields, unsigned int *align)
810 {
811     int have_align = FALSE;
812     size_t size = 0;
813     const var_t *v;
814
815     if (!fields) return 0;
816     LIST_FOR_EACH_ENTRY( v, fields, const var_t, entry )
817     {
818         unsigned int falign = 0;
819         size_t fsize = type_memsize(v->type, &falign);
820         if (!have_align)
821         {
822             *align = falign;
823             have_align = TRUE;
824         }
825         size = (size + (falign - 1)) & ~(falign - 1);
826         size += fsize;
827     }
828
829     size = (size + (*align - 1)) & ~(*align - 1);
830     return size;
831 }
832
833 static size_t union_memsize(const var_list_t *fields, unsigned int *pmaxa)
834 {
835     size_t size, maxs = 0;
836     unsigned int align = *pmaxa;
837     const var_t *v;
838
839     if (fields) LIST_FOR_EACH_ENTRY( v, fields, const var_t, entry )
840     {
841         /* we could have an empty default field with NULL type */
842         if (v->type)
843         {
844             size = type_memsize(v->type, &align);
845             if (maxs < size) maxs = size;
846             if (*pmaxa < align) *pmaxa = align;
847         }
848     }
849
850     return maxs;
851 }
852
853 int get_padding(const var_list_t *fields)
854 {
855     unsigned short offset = 0;
856     int salign = -1;
857     const var_t *f;
858
859     if (!fields)
860         return 0;
861
862     LIST_FOR_EACH_ENTRY(f, fields, const var_t, entry)
863     {
864         type_t *ft = f->type;
865         unsigned int align = 0;
866         size_t size = type_memsize(ft, &align);
867         if (salign == -1)
868             salign = align;
869         offset = (offset + (align - 1)) & ~(align - 1);
870         offset += size;
871     }
872
873     return ((offset + (salign - 1)) & ~(salign - 1)) - offset;
874 }
875
876 size_t type_memsize(const type_t *t, unsigned int *align)
877 {
878     size_t size = 0;
879
880     if (t->declarray && is_conformant_array(t))
881     {
882         type_memsize(t->ref, align);
883         size = 0;
884     }
885     else if (is_ptr(t) || is_conformant_array(t))
886     {
887         size = sizeof(void *);
888         if (size > *align) *align = size;
889     }
890     else switch (t->type)
891     {
892     case RPC_FC_BYTE:
893     case RPC_FC_CHAR:
894     case RPC_FC_USMALL:
895     case RPC_FC_SMALL:
896         size = 1;
897         if (size > *align) *align = size;
898         break;
899     case RPC_FC_WCHAR:
900     case RPC_FC_USHORT:
901     case RPC_FC_SHORT:
902     case RPC_FC_ENUM16:
903         size = 2;
904         if (size > *align) *align = size;
905         break;
906     case RPC_FC_ULONG:
907     case RPC_FC_LONG:
908     case RPC_FC_ERROR_STATUS_T:
909     case RPC_FC_ENUM32:
910     case RPC_FC_FLOAT:
911         size = 4;
912         if (size > *align) *align = size;
913         break;
914     case RPC_FC_HYPER:
915     case RPC_FC_DOUBLE:
916         size = 8;
917         if (size > *align) *align = size;
918         break;
919     case RPC_FC_STRUCT:
920     case RPC_FC_CVSTRUCT:
921     case RPC_FC_CPSTRUCT:
922     case RPC_FC_CSTRUCT:
923     case RPC_FC_PSTRUCT:
924     case RPC_FC_BOGUS_STRUCT:
925         size = fields_memsize(t->fields, align);
926         break;
927     case RPC_FC_ENCAPSULATED_UNION:
928     case RPC_FC_NON_ENCAPSULATED_UNION:
929         size = union_memsize(t->fields, align);
930         break;
931     case RPC_FC_SMFARRAY:
932     case RPC_FC_LGFARRAY:
933     case RPC_FC_SMVARRAY:
934     case RPC_FC_LGVARRAY:
935     case RPC_FC_BOGUS_ARRAY:
936         size = t->dim * type_memsize(t->ref, align);
937         break;
938     default:
939         error("type_memsize: Unknown type %d\n", t->type);
940         size = 0;
941     }
942
943     return size;
944 }
945
946 int is_full_pointer_function(const func_t *func)
947 {
948     const var_t *var;
949     if (type_has_full_pointer(func->def->type))
950         return TRUE;
951     if (!func->args)
952         return FALSE;
953     LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
954         if (type_has_full_pointer( var->type ))
955             return TRUE;
956     return FALSE;
957 }
958
959 void write_full_pointer_init(FILE *file, int indent, const func_t *func, int is_server)
960 {
961     print_file(file, indent, "_StubMsg.FullPtrXlatTables = NdrFullPointerXlatInit(0,%s);\n",
962                    is_server ? "XLAT_SERVER" : "XLAT_CLIENT");
963     fprintf(file, "\n");
964 }
965
966 void write_full_pointer_free(FILE *file, int indent, const func_t *func)
967 {
968     print_file(file, indent, "NdrFullPointerXlatFree(_StubMsg.FullPtrXlatTables);\n");
969     fprintf(file, "\n");
970 }
971
972 static unsigned int write_nonsimple_pointer(FILE *file, const type_t *type, size_t offset)
973 {
974     short absoff = type->ref->typestring_offset;
975     short reloff = absoff - (offset + 2);
976     int ptr_attr = is_ptr(type->ref) ? 0x10 : 0x0;
977
978     print_file(file, 2, "0x%02x, 0x%x,\t/* %s */\n",
979                type->type, ptr_attr, string_of_type(type->type));
980     print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%hd) */\n",
981                reloff, reloff, absoff);
982     return 4;
983 }
984
985 static unsigned char conf_string_type_of_char_type(unsigned char t)
986 {
987     switch (t)
988     {
989     case RPC_FC_BYTE:
990     case RPC_FC_CHAR:
991         return RPC_FC_C_CSTRING;
992     case RPC_FC_WCHAR:
993         return RPC_FC_C_WSTRING;
994     }
995
996     error("string_type_of_char_type: unrecognized type %d\n", t);
997     return 0;
998 }
999
1000 static unsigned int write_simple_pointer(FILE *file, const type_t *type)
1001 {
1002     unsigned char fc
1003         = is_string_type(type->attrs, type)
1004         ? conf_string_type_of_char_type(type->ref->type)
1005         : type->ref->type;
1006     print_file(file, 2, "0x%02x, 0x8,\t/* %s [simple_pointer] */\n",
1007                type->type, string_of_type(type->type));
1008     print_file(file, 2, "0x%02x,\t/* %s */\n", fc, string_of_type(fc));
1009     print_file(file, 2, "0x5c,\t/* FC_PAD */\n");
1010     return 4;
1011 }
1012
1013 static void print_start_tfs_comment(FILE *file, type_t *t, unsigned int tfsoff)
1014 {
1015     print_file(file, 0, "/* %u (", tfsoff);
1016     write_type_decl(file, t, NULL);
1017     print_file(file, 0, ") */\n");
1018 }
1019
1020 static size_t write_pointer_tfs(FILE *file, type_t *type, unsigned int *typestring_offset)
1021 {
1022     unsigned int offset = *typestring_offset;
1023
1024     print_start_tfs_comment(file, type, offset);
1025     update_tfsoff(type, offset, file);
1026
1027     if (type->ref->typestring_offset)
1028         *typestring_offset += write_nonsimple_pointer(file, type, offset);
1029     else if (is_base_type(type->ref->type))
1030         *typestring_offset += write_simple_pointer(file, type);
1031
1032     return offset;
1033 }
1034
1035 static int processed(const type_t *type)
1036 {
1037     return type->typestring_offset && !type->tfswrite;
1038 }
1039
1040 static int user_type_has_variable_size(const type_t *t)
1041 {
1042     if (is_ptr(t))
1043         return TRUE;
1044     else
1045         switch (t->type)
1046         {
1047         case RPC_FC_PSTRUCT:
1048         case RPC_FC_CSTRUCT:
1049         case RPC_FC_CPSTRUCT:
1050         case RPC_FC_CVSTRUCT:
1051             return TRUE;
1052         }
1053     /* Note: Since this only applies to user types, we can't have a conformant
1054        array here, and strings should get filed under pointer in this case.  */
1055     return FALSE;
1056 }
1057
1058 static void write_user_tfs(FILE *file, type_t *type, unsigned int *tfsoff)
1059 {
1060     unsigned int start, absoff, flags;
1061     unsigned int align = 0, ualign = 0;
1062     const char *name;
1063     type_t *utype = get_user_type(type, &name);
1064     size_t usize = user_type_has_variable_size(utype) ? 0 : type_memsize(utype, &ualign);
1065     size_t size = type_memsize(type, &align);
1066     unsigned short funoff = user_type_offset(name);
1067     short reloff;
1068
1069     guard_rec(type);
1070
1071     if (is_base_type(utype->type))
1072     {
1073         absoff = *tfsoff;
1074         print_start_tfs_comment(file, utype, absoff);
1075         print_file(file, 2, "0x%x,\t/* %s */\n", utype->type, string_of_type(utype->type));
1076         print_file(file, 2, "0x5c,\t/* FC_PAD */\n");
1077         *tfsoff += 2;
1078     }
1079     else
1080     {
1081         if (!processed(utype))
1082             write_embedded_types(file, NULL, utype, utype->name, TRUE, tfsoff);
1083         absoff = utype->typestring_offset;
1084     }
1085
1086     if (utype->type == RPC_FC_RP)
1087         flags = 0x40;
1088     else if (utype->type == RPC_FC_UP)
1089         flags = 0x80;
1090     else
1091         flags = 0;
1092
1093     start = *tfsoff;
1094     update_tfsoff(type, start, file);
1095     print_start_tfs_comment(file, type, start);
1096     print_file(file, 2, "0x%x,\t/* FC_USER_MARSHAL */\n", RPC_FC_USER_MARSHAL);
1097     print_file(file, 2, "0x%x,\t/* Alignment= %d, Flags= %02x */\n",
1098                flags | (align - 1), align - 1, flags);
1099     print_file(file, 2, "NdrFcShort(0x%hx),\t/* Function offset= %hu */\n", funoff, funoff);
1100     print_file(file, 2, "NdrFcShort(0x%lx),\t/* %lu */\n", size, size);
1101     print_file(file, 2, "NdrFcShort(0x%lx),\t/* %lu */\n", usize, usize);
1102     *tfsoff += 8;
1103     reloff = absoff - *tfsoff;
1104     print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%lu) */\n", reloff, reloff, absoff);
1105     *tfsoff += 2;
1106 }
1107
1108 static void write_member_type(FILE *file, const type_t *cont,
1109                               const attr_list_t *attrs, const type_t *type,
1110                               unsigned int *corroff, unsigned int *tfsoff)
1111 {
1112     if (is_embedded_complex(type) && !is_conformant_array(type))
1113     {
1114         size_t absoff;
1115         short reloff;
1116
1117         if (is_union(type->type) && is_attr(attrs, ATTR_SWITCHIS))
1118         {
1119             absoff = *corroff;
1120             *corroff += 8;
1121         }
1122         else
1123         {
1124             absoff = type->typestring_offset;
1125         }
1126         reloff = absoff - (*tfsoff + 2);
1127
1128         print_file(file, 2, "0x4c,\t/* FC_EMBEDDED_COMPLEX */\n");
1129         /* FIXME: actually compute necessary padding */
1130         print_file(file, 2, "0x0,\t/* FIXME: padding */\n");
1131         print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%lu) */\n",
1132                    reloff, reloff, absoff);
1133         *tfsoff += 4;
1134     }
1135     else if (is_ptr(type) || is_conformant_array(type))
1136     {
1137         unsigned char fc = (cont->type == RPC_FC_BOGUS_STRUCT
1138                             ? RPC_FC_POINTER
1139                             : RPC_FC_LONG);
1140         print_file(file, 2, "0x%x,\t/* %s */\n", fc, string_of_type(fc));
1141         *tfsoff += 1;
1142     }
1143     else if (!write_base_type(file, type, tfsoff))
1144         error("Unsupported member type 0x%x\n", type->type);
1145 }
1146
1147 static void write_end(FILE *file, unsigned int *tfsoff)
1148 {
1149     if (*tfsoff % 2 == 0)
1150     {
1151         print_file(file, 2, "0x%x,\t\t/* FC_PAD */\n", RPC_FC_PAD);
1152         *tfsoff += 1;
1153     }
1154     print_file(file, 2, "0x%x,\t\t/* FC_END */\n", RPC_FC_END);
1155     *tfsoff += 1;
1156 }
1157
1158 static void write_descriptors(FILE *file, type_t *type, unsigned int *tfsoff)
1159 {
1160     unsigned int offset = 0;
1161     var_list_t *fs = type->fields;
1162     var_t *f;
1163
1164     if (fs) LIST_FOR_EACH_ENTRY(f, fs, var_t, entry)
1165     {
1166         unsigned int align = 0;
1167         type_t *ft = f->type;
1168         if (is_union(ft->type) && is_attr(f->attrs, ATTR_SWITCHIS))
1169         {
1170             unsigned int absoff = ft->typestring_offset;
1171             short reloff = absoff - (*tfsoff + 6);
1172             print_file(file, 0, "/* %d */\n", *tfsoff);
1173             print_file(file, 2, "0x%x,\t/* %s */\n", ft->type, string_of_type(ft->type));
1174             print_file(file, 2, "0x%x,\t/* FIXME: always FC_LONG */\n", RPC_FC_LONG);
1175             write_conf_or_var_desc(file, current_structure, offset, ft,
1176                                    get_attrp(f->attrs, ATTR_SWITCHIS));
1177             print_file(file, 2, "NdrFcShort(%hd),\t/* Offset= %hd (%u) */\n",
1178                        reloff, reloff, absoff);
1179             *tfsoff += 8;
1180         }
1181
1182         /* FIXME: take alignment into account */
1183         offset += type_memsize(ft, &align);
1184     }
1185 }
1186
1187 static int write_no_repeat_pointer_descriptions(
1188     FILE *file, type_t *type,
1189     size_t *offset_in_memory, size_t *offset_in_buffer,
1190     unsigned int *typestring_offset)
1191 {
1192     int written = 0;
1193     unsigned int align;
1194
1195     if (is_ptr(type) || (!type->declarray && is_conformant_array(type)))
1196     {
1197         print_file(file, 2, "0x%02x, /* FC_NO_REPEAT */\n", RPC_FC_NO_REPEAT);
1198         print_file(file, 2, "0x%02x, /* FC_PAD */\n", RPC_FC_PAD);
1199
1200         /* pointer instance */
1201         print_file(file, 2, "NdrFcShort(0x%x), /* Memory offset = %d */\n", *offset_in_memory, *offset_in_memory);
1202         print_file(file, 2, "NdrFcShort(0x%x), /* Buffer offset = %d */\n", *offset_in_buffer, *offset_in_buffer);
1203         *typestring_offset += 6;
1204
1205         if (is_ptr(type))
1206             write_pointer_tfs(file, type, typestring_offset);
1207         else
1208         {
1209             unsigned absoff = type->typestring_offset;
1210             short reloff = absoff - (*typestring_offset + 2);
1211             /* FIXME: get pointer attributes from field */
1212             print_file(file, 2, "0x%02x, 0x0,\t/* %s */\n", RPC_FC_UP, "FC_UP");
1213             print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%u) */\n",
1214                        reloff, reloff, absoff);
1215             *typestring_offset += 4;
1216         }
1217
1218         align = 0;
1219         *offset_in_memory += type_memsize(type, &align);
1220         /* FIXME: is there a case where these two are different? */
1221         align = 0;
1222         *offset_in_buffer += type_memsize(type, &align);
1223
1224         return 1;
1225     }
1226
1227     if (is_non_complex_struct(type))
1228     {
1229         const var_t *v;
1230         LIST_FOR_EACH_ENTRY( v, type->fields, const var_t, entry )
1231             written += write_no_repeat_pointer_descriptions(
1232                 file, v->type,
1233                 offset_in_memory, offset_in_buffer, typestring_offset);
1234     }
1235     else
1236     {
1237         align = 0;
1238         *offset_in_memory += type_memsize(type, &align);
1239         /* FIXME: is there a case where these two are different? */
1240         align = 0;
1241         *offset_in_buffer += type_memsize(type, &align);
1242     }
1243
1244     return written;
1245 }
1246
1247 static int write_pointer_description_offsets(
1248     FILE *file, const attr_list_t *attrs, type_t *type,
1249     size_t *offset_in_memory, size_t *offset_in_buffer,
1250     unsigned int *typestring_offset)
1251 {
1252     int written = 0;
1253     unsigned int align;
1254
1255     if (is_ptr(type) && type->ref->type != RPC_FC_IP)
1256     {
1257         if (offset_in_memory && offset_in_buffer)
1258         {
1259             /* pointer instance */
1260             /* FIXME: sometimes from end of structure, sometimes from beginning */
1261             print_file(file, 2, "NdrFcShort(0x%x), /* Memory offset = %d */\n", *offset_in_memory, *offset_in_memory);
1262             print_file(file, 2, "NdrFcShort(0x%x), /* Buffer offset = %d */\n", *offset_in_buffer, *offset_in_buffer);
1263
1264             align = 0;
1265             *offset_in_memory += type_memsize(type, &align);
1266             /* FIXME: is there a case where these two are different? */
1267             align = 0;
1268             *offset_in_buffer += type_memsize(type, &align);
1269         }
1270         *typestring_offset += 4;
1271
1272         if (processed(type->ref) || is_base_type(type->ref->type))
1273             write_pointer_tfs(file, type, typestring_offset);
1274         else
1275             error("write_pointer_description_offsets: type format string unknown\n");
1276
1277         return 1;
1278     }
1279
1280     if (is_array(type))
1281     {
1282         return write_pointer_description_offsets(
1283             file, attrs, type->ref, offset_in_memory, offset_in_buffer,
1284                                                  typestring_offset);
1285     }
1286     else if (is_non_complex_struct(type))
1287     {
1288         /* otherwise search for interesting fields to parse */
1289         const var_t *v;
1290         LIST_FOR_EACH_ENTRY( v, type->fields, const var_t, entry )
1291         {
1292             written += write_pointer_description_offsets(
1293                 file, v->attrs, v->type, offset_in_memory, offset_in_buffer,
1294                 typestring_offset);
1295         }
1296     }
1297     else
1298     {
1299         align = 0;
1300         if (offset_in_memory)
1301             *offset_in_memory += type_memsize(type, &align);
1302         /* FIXME: is there a case where these two are different? */
1303         align = 0;
1304         if (offset_in_buffer)
1305             *offset_in_buffer += type_memsize(type, &align);
1306     }
1307
1308     return written;
1309 }
1310
1311 /* Note: if file is NULL return value is number of pointers to write, else
1312  * it is the number of type format characters written */
1313 static int write_fixed_array_pointer_descriptions(
1314     FILE *file, const attr_list_t *attrs, type_t *type,
1315     size_t *offset_in_memory, size_t *offset_in_buffer,
1316     unsigned int *typestring_offset)
1317 {
1318     unsigned int align;
1319     int pointer_count = 0;
1320
1321     if (type->type == RPC_FC_SMFARRAY || type->type == RPC_FC_LGFARRAY)
1322     {
1323         unsigned int temp = 0;
1324         /* unfortunately, this needs to be done in two passes to avoid
1325          * writing out redundant FC_FIXED_REPEAT descriptions */
1326         pointer_count = write_pointer_description_offsets(
1327             NULL, attrs, type->ref, NULL, NULL, &temp);
1328         if (pointer_count > 0)
1329         {
1330             unsigned int increment_size;
1331             size_t offset_of_array_pointer_mem = 0;
1332             size_t offset_of_array_pointer_buf = 0;
1333
1334             align = 0;
1335             increment_size = type_memsize(type->ref, &align);
1336
1337             print_file(file, 2, "0x%02x, /* FC_FIXED_REPEAT */\n", RPC_FC_FIXED_REPEAT);
1338             print_file(file, 2, "0x%02x, /* FC_PAD */\n", RPC_FC_PAD);
1339             print_file(file, 2, "NdrFcShort(0x%x), /* Iterations = %d */\n", type->dim, type->dim);
1340             print_file(file, 2, "NdrFcShort(0x%x), /* Increment = %d */\n", increment_size, increment_size);
1341             print_file(file, 2, "NdrFcShort(0x%x), /* Offset to array = %d */\n", *offset_in_memory, *offset_in_memory);
1342             print_file(file, 2, "NdrFcShort(0x%x), /* Number of pointers = %d */\n", pointer_count, pointer_count);
1343             *typestring_offset += 10;
1344
1345             pointer_count = write_pointer_description_offsets(
1346                 file, attrs, type, &offset_of_array_pointer_mem,
1347                 &offset_of_array_pointer_buf, typestring_offset);
1348         }
1349     }
1350     else if (is_struct(type->type))
1351     {
1352         const var_t *v;
1353         LIST_FOR_EACH_ENTRY( v, type->fields, const var_t, entry )
1354         {
1355             pointer_count += write_fixed_array_pointer_descriptions(
1356                 file, v->attrs, v->type, offset_in_memory, offset_in_buffer,
1357                 typestring_offset);
1358         }
1359     }
1360     else
1361     {
1362         align = 0;
1363         if (offset_in_memory)
1364             *offset_in_memory += type_memsize(type, &align);
1365         /* FIXME: is there a case where these two are different? */
1366         align = 0;
1367         if (offset_in_buffer)
1368             *offset_in_buffer += type_memsize(type, &align);
1369     }
1370
1371     return pointer_count;
1372 }
1373
1374 /* Note: if file is NULL return value is number of pointers to write, else
1375  * it is the number of type format characters written */
1376 static int write_conformant_array_pointer_descriptions(
1377     FILE *file, const attr_list_t *attrs, type_t *type,
1378     size_t offset_in_memory, unsigned int *typestring_offset)
1379 {
1380     unsigned int align;
1381     int pointer_count = 0;
1382
1383     if (is_conformant_array(type) && !type->length_is)
1384     {
1385         unsigned int temp = 0;
1386         /* unfortunately, this needs to be done in two passes to avoid
1387          * writing out redundant FC_VARIABLE_REPEAT descriptions */
1388         pointer_count = write_pointer_description_offsets(
1389             NULL, attrs, type->ref, NULL, NULL, &temp);
1390         if (pointer_count > 0)
1391         {
1392             unsigned int increment_size;
1393             size_t offset_of_array_pointer_mem = offset_in_memory;
1394             size_t offset_of_array_pointer_buf = offset_in_memory;
1395
1396             align = 0;
1397             increment_size = type_memsize(type->ref, &align);
1398
1399             if (increment_size > USHRT_MAX)
1400                 error("array size of %u bytes is too large\n", increment_size);
1401
1402             print_file(file, 2, "0x%02x, /* FC_VARIABLE_REPEAT */\n", RPC_FC_VARIABLE_REPEAT);
1403             print_file(file, 2, "0x%02x, /* FC_FIXED_OFFSET */\n", RPC_FC_FIXED_OFFSET);
1404             print_file(file, 2, "NdrFcShort(0x%x), /* Increment = %d */\n", increment_size, increment_size);
1405             print_file(file, 2, "NdrFcShort(0x%x), /* Offset to array = %d */\n", offset_in_memory, offset_in_memory);
1406             print_file(file, 2, "NdrFcShort(0x%x), /* Number of pointers = %d */\n", pointer_count, pointer_count);
1407             *typestring_offset += 8;
1408
1409             pointer_count = write_pointer_description_offsets(
1410                 file, attrs, type->ref, &offset_of_array_pointer_mem,
1411                 &offset_of_array_pointer_buf, typestring_offset);
1412         }
1413     }
1414
1415     return pointer_count;
1416 }
1417
1418 /* Note: if file is NULL return value is number of pointers to write, else
1419  * it is the number of type format characters written */
1420 static int write_varying_array_pointer_descriptions(
1421     FILE *file, const attr_list_t *attrs, type_t *type,
1422     size_t *offset_in_memory, size_t *offset_in_buffer,
1423     unsigned int *typestring_offset)
1424 {
1425     unsigned int align;
1426     int pointer_count = 0;
1427
1428     /* FIXME: do varying array searching here, but pointer searching in write_pointer_description_offsets */
1429
1430     if (is_array(type) && type->length_is)
1431     {
1432         unsigned int temp = 0;
1433         /* unfortunately, this needs to be done in two passes to avoid
1434          * writing out redundant FC_VARIABLE_REPEAT descriptions */
1435         pointer_count = write_pointer_description_offsets(
1436             NULL, attrs, type->ref, NULL, NULL, &temp);
1437         if (pointer_count > 0)
1438         {
1439             unsigned int increment_size;
1440             size_t offset_of_array_pointer_mem = 0;
1441             size_t offset_of_array_pointer_buf = 0;
1442
1443             align = 0;
1444             increment_size = type_memsize(type->ref, &align);
1445
1446             if (increment_size > USHRT_MAX)
1447                 error("array size of %u bytes is too large\n", increment_size);
1448
1449             print_file(file, 2, "0x%02x, /* FC_VARIABLE_REPEAT */\n", RPC_FC_VARIABLE_REPEAT);
1450             print_file(file, 2, "0x%02x, /* FC_VARIABLE_OFFSET */\n", RPC_FC_VARIABLE_OFFSET);
1451             print_file(file, 2, "NdrFcShort(0x%x), /* Increment = %d */\n", increment_size, increment_size);
1452             print_file(file, 2, "NdrFcShort(0x%x), /* Offset to array = %d */\n", *offset_in_memory, *offset_in_memory);
1453             print_file(file, 2, "NdrFcShort(0x%x), /* Number of pointers = %d */\n", pointer_count, pointer_count);
1454             *typestring_offset += 8;
1455
1456             pointer_count = write_pointer_description_offsets(
1457                 file, attrs, type, &offset_of_array_pointer_mem,
1458                 &offset_of_array_pointer_buf, typestring_offset);
1459         }
1460     }
1461     else if (is_struct(type->type))
1462     {
1463         const var_t *v;
1464         LIST_FOR_EACH_ENTRY( v, type->fields, const var_t, entry )
1465         {
1466             pointer_count += write_varying_array_pointer_descriptions(
1467                 file, v->attrs, v->type, offset_in_memory, offset_in_buffer,
1468                 typestring_offset);
1469         }
1470     }
1471     else
1472     {
1473         align = 0;
1474         if (offset_in_memory)
1475             *offset_in_memory += type_memsize(type, &align);
1476         /* FIXME: is there a case where these two are different? */
1477         align = 0;
1478         if (offset_in_buffer)
1479             *offset_in_buffer += type_memsize(type, &align);
1480     }
1481
1482     return pointer_count;
1483 }
1484
1485 static void write_pointer_description(FILE *file, type_t *type,
1486                                       unsigned int *typestring_offset)
1487 {
1488     size_t offset_in_buffer;
1489     size_t offset_in_memory;
1490
1491     /* pass 1: search for single instance of a pointer (i.e. don't descend
1492      * into arrays) */
1493     if (!is_array(type))
1494     {
1495         offset_in_memory = 0;
1496         offset_in_buffer = 0;
1497         write_no_repeat_pointer_descriptions(
1498             file, type,
1499             &offset_in_memory, &offset_in_buffer, typestring_offset);
1500     }
1501
1502     /* pass 2: search for pointers in fixed arrays */
1503     offset_in_memory = 0;
1504     offset_in_buffer = 0;
1505     write_fixed_array_pointer_descriptions(
1506         file, NULL, type,
1507         &offset_in_memory, &offset_in_buffer, typestring_offset);
1508
1509     /* pass 3: search for pointers in conformant only arrays (but don't descend
1510      * into conformant varying or varying arrays) */
1511     if ((!type->declarray || !current_structure) && is_conformant_array(type))
1512         write_conformant_array_pointer_descriptions(
1513             file, NULL, type, 0, typestring_offset);
1514     else if (type->type == RPC_FC_CPSTRUCT)
1515     {
1516         unsigned int align = 0;
1517         type_t *carray = find_array_or_string_in_struct(type)->type;
1518         write_conformant_array_pointer_descriptions(
1519             file, NULL, carray,
1520             type_memsize(type, &align),
1521             typestring_offset);
1522     }
1523
1524    /* pass 4: search for pointers in varying arrays */
1525     offset_in_memory = 0;
1526     offset_in_buffer = 0;
1527     write_varying_array_pointer_descriptions(
1528             file, NULL, type,
1529             &offset_in_memory, &offset_in_buffer, typestring_offset);
1530 }
1531
1532 int is_declptr(const type_t *t)
1533 {
1534   return is_ptr(t) || (is_conformant_array(t) && !t->declarray);
1535 }
1536
1537 static size_t write_string_tfs(FILE *file, const attr_list_t *attrs,
1538                                type_t *type,
1539                                const char *name, unsigned int *typestring_offset,
1540                                int toplevel)
1541 {
1542     size_t start_offset;
1543     unsigned char rtype;
1544
1545     if (toplevel && is_declptr(type))
1546     {
1547         unsigned char flag = is_conformant_array(type) ? 0 : RPC_FC_P_SIMPLEPOINTER;
1548         int pointer_type = is_ptr(type) ? type->type : get_attrv(attrs, ATTR_POINTERTYPE);
1549         if (!pointer_type)
1550             pointer_type = RPC_FC_RP;
1551         print_file(file, 2,"0x%x, 0x%x,\t/* %s%s */\n",
1552                    pointer_type, flag, string_of_type(pointer_type),
1553                    flag ? " [simple_pointer]" : "");
1554         *typestring_offset += 2;
1555         if (!flag)
1556         {
1557             print_file(file, 2, "NdrFcShort(0x2),\n");
1558             *typestring_offset += 2;
1559         }
1560     }
1561
1562     start_offset = *typestring_offset;
1563     update_tfsoff(type, start_offset, file);
1564
1565     rtype = type->ref->type;
1566
1567     if ((rtype != RPC_FC_BYTE) && (rtype != RPC_FC_CHAR) && (rtype != RPC_FC_WCHAR))
1568     {
1569         error("write_string_tfs: Unimplemented for type 0x%x of name: %s\n", rtype, name);
1570         return start_offset;
1571     }
1572
1573     if (type->declarray && !is_conformant_array(type))
1574     {
1575         /* FIXME: multi-dimensional array */
1576         if (0xffffuL < type->dim)
1577             error("array size for parameter %s exceeds %u bytes by %lu bytes\n",
1578                   name, 0xffffu, type->dim - 0xffffu);
1579
1580         if (rtype == RPC_FC_CHAR)
1581             WRITE_FCTYPE(file, FC_CSTRING, *typestring_offset);
1582         else
1583             WRITE_FCTYPE(file, FC_WSTRING, *typestring_offset);
1584         print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
1585         *typestring_offset += 2;
1586
1587         print_file(file, 2, "NdrFcShort(0x%x), /* %d */\n", type->dim, type->dim);
1588         *typestring_offset += 2;
1589
1590         return start_offset;
1591     }
1592     else if (type->size_is)
1593     {
1594         unsigned int align = 0;
1595
1596         if (rtype == RPC_FC_CHAR)
1597             WRITE_FCTYPE(file, FC_C_CSTRING, *typestring_offset);
1598         else
1599             WRITE_FCTYPE(file, FC_C_WSTRING, *typestring_offset);
1600         print_file(file, 2, "0x%x, /* FC_STRING_SIZED */\n", RPC_FC_STRING_SIZED);
1601         *typestring_offset += 2;
1602
1603         *typestring_offset += write_conf_or_var_desc(
1604             file, current_structure,
1605             (type->declarray && current_structure
1606              ? type_memsize(current_structure, &align)
1607              : 0),
1608             type, type->size_is);
1609
1610         return start_offset;
1611     }
1612     else
1613     {
1614         if (rtype == RPC_FC_WCHAR)
1615             WRITE_FCTYPE(file, FC_C_WSTRING, *typestring_offset);
1616         else
1617             WRITE_FCTYPE(file, FC_C_CSTRING, *typestring_offset);
1618         print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
1619         *typestring_offset += 2;
1620
1621         return start_offset;
1622     }
1623 }
1624
1625 static size_t write_array_tfs(FILE *file, const attr_list_t *attrs, type_t *type,
1626                               const char *name, unsigned int *typestring_offset)
1627 {
1628     const expr_t *length_is = type->length_is;
1629     const expr_t *size_is = type->size_is;
1630     unsigned int align = 0;
1631     size_t size;
1632     size_t start_offset;
1633     int has_pointer;
1634     int pointer_type = get_attrv(attrs, ATTR_POINTERTYPE);
1635     unsigned int baseoff
1636         = type->declarray && current_structure
1637         ? type_memsize(current_structure, &align)
1638         : 0;
1639
1640     if (!pointer_type)
1641         pointer_type = RPC_FC_RP;
1642
1643     if (write_embedded_types(file, attrs, type->ref, name, FALSE, typestring_offset))
1644         has_pointer = TRUE;
1645     else
1646         has_pointer = type_has_pointers(type->ref);
1647
1648     align = 0;
1649     size = type_memsize((is_conformant_array(type) ? type->ref : type), &align);
1650
1651     start_offset = *typestring_offset;
1652     update_tfsoff(type, start_offset, file);
1653     print_start_tfs_comment(file, type, start_offset);
1654     print_file(file, 2, "0x%02x,\t/* %s */\n", type->type, string_of_type(type->type));
1655     print_file(file, 2, "0x%x,\t/* %d */\n", align - 1, align - 1);
1656     *typestring_offset += 2;
1657
1658     align = 0;
1659     if (type->type != RPC_FC_BOGUS_ARRAY)
1660     {
1661         unsigned char tc = type->type;
1662
1663         if (tc == RPC_FC_LGFARRAY || tc == RPC_FC_LGVARRAY)
1664         {
1665             print_file(file, 2, "NdrFcLong(0x%x),\t/* %lu */\n", size, size);
1666             *typestring_offset += 4;
1667         }
1668         else
1669         {
1670             print_file(file, 2, "NdrFcShort(0x%x),\t/* %lu */\n", size, size);
1671             *typestring_offset += 2;
1672         }
1673
1674         if (is_conformant_array(type))
1675             *typestring_offset
1676                 += write_conf_or_var_desc(file, current_structure, baseoff,
1677                                           type, size_is);
1678
1679         if (type->type == RPC_FC_SMVARRAY || type->type == RPC_FC_LGVARRAY)
1680         {
1681             unsigned int elalign = 0;
1682             size_t elsize = type_memsize(type->ref, &elalign);
1683
1684             if (type->type == RPC_FC_LGVARRAY)
1685             {
1686                 print_file(file, 2, "NdrFcLong(0x%x),\t/* %lu */\n", type->dim, type->dim);
1687                 *typestring_offset += 4;
1688             }
1689             else
1690             {
1691                 print_file(file, 2, "NdrFcShort(0x%x),\t/* %lu */\n", type->dim, type->dim);
1692                 *typestring_offset += 2;
1693             }
1694
1695             print_file(file, 2, "NdrFcShort(0x%x),\t/* %lu */\n", elsize, elsize);
1696             *typestring_offset += 2;
1697         }
1698
1699         if (length_is)
1700             *typestring_offset
1701                 += write_conf_or_var_desc(file, current_structure, baseoff,
1702                                           type, length_is);
1703
1704         if (has_pointer && (!type->declarray || !current_structure))
1705         {
1706             print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
1707             print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
1708             *typestring_offset += 2;
1709             write_pointer_description(file, type, typestring_offset);
1710             print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
1711             *typestring_offset += 1;
1712         }
1713
1714         write_member_type(file, type, NULL, type->ref, NULL, typestring_offset);
1715         write_end(file, typestring_offset);
1716     }
1717     else
1718     {
1719         unsigned int dim = size_is ? 0 : type->dim;
1720         print_file(file, 2, "NdrFcShort(0x%x),\t/* %u */\n", dim, dim);
1721         *typestring_offset += 2;
1722         *typestring_offset
1723             += write_conf_or_var_desc(file, current_structure, baseoff,
1724                                       type, size_is);
1725         *typestring_offset
1726             += write_conf_or_var_desc(file, current_structure, baseoff,
1727                                       type, length_is);
1728         write_member_type(file, type, NULL, type->ref, NULL, typestring_offset);
1729         write_end(file, typestring_offset);
1730     }
1731
1732     return start_offset;
1733 }
1734
1735 static const var_t *find_array_or_string_in_struct(const type_t *type)
1736 {
1737     const var_t *last_field = LIST_ENTRY( list_tail(type->fields), const var_t, entry );
1738     const type_t *ft = last_field->type;
1739
1740     if (ft->declarray && is_conformant_array(ft))
1741         return last_field;
1742
1743     if (ft->type == RPC_FC_CSTRUCT || ft->type == RPC_FC_CPSTRUCT || ft->type == RPC_FC_CVSTRUCT)
1744         return find_array_or_string_in_struct(last_field->type);
1745     else
1746         return NULL;
1747 }
1748
1749 static void write_struct_members(FILE *file, const type_t *type,
1750                                  unsigned int *corroff, unsigned int *typestring_offset)
1751 {
1752     const var_t *field;
1753     unsigned short offset = 0;
1754     int salign = -1;
1755     int padding;
1756
1757     if (type->fields) LIST_FOR_EACH_ENTRY( field, type->fields, const var_t, entry )
1758     {
1759         type_t *ft = field->type;
1760         if (!ft->declarray || !is_conformant_array(ft))
1761         {
1762             unsigned int align = 0;
1763             size_t size = type_memsize(ft, &align);
1764             if (salign == -1)
1765                 salign = align;
1766             if ((align - 1) & offset)
1767             {
1768                 unsigned char fc = 0;
1769                 switch (align)
1770                 {
1771                 case 4:
1772                     fc = RPC_FC_ALIGNM4;
1773                     break;
1774                 case 8:
1775                     fc = RPC_FC_ALIGNM8;
1776                     break;
1777                 default:
1778                     error("write_struct_members: cannot align type %d\n", ft->type);
1779                 }
1780                 print_file(file, 2, "0x%x,\t/* %s */\n", fc, string_of_type(fc));
1781                 offset = (offset + (align - 1)) & ~(align - 1);
1782                 *typestring_offset += 1;
1783             }
1784             write_member_type(file, type, field->attrs, field->type, corroff,
1785                               typestring_offset);
1786             offset += size;
1787         }
1788     }
1789
1790     padding = ((offset + (salign - 1)) & ~(salign - 1)) - offset;
1791     if (padding)
1792     {
1793         print_file(file, 2, "0x%x,\t/* FC_STRUCTPAD%d */\n",
1794                    RPC_FC_STRUCTPAD1 + padding - 1,
1795                    padding);
1796         *typestring_offset += 1;
1797     }
1798
1799     write_end(file, typestring_offset);
1800 }
1801
1802 static size_t write_struct_tfs(FILE *file, type_t *type,
1803                                const char *name, unsigned int *tfsoff)
1804 {
1805     const type_t *save_current_structure = current_structure;
1806     unsigned int total_size;
1807     const var_t *array;
1808     size_t start_offset;
1809     size_t array_offset;
1810     int has_pointers = 0;
1811     unsigned int align = 0;
1812     unsigned int corroff;
1813     var_t *f;
1814
1815     guard_rec(type);
1816     current_structure = type;
1817
1818     total_size = type_memsize(type, &align);
1819     if (total_size > USHRT_MAX)
1820         error("structure size for %s exceeds %d bytes by %d bytes\n",
1821               name, USHRT_MAX, total_size - USHRT_MAX);
1822
1823     if (type->fields) LIST_FOR_EACH_ENTRY(f, type->fields, var_t, entry)
1824         has_pointers |= write_embedded_types(file, f->attrs, f->type, f->name,
1825                                              FALSE, tfsoff);
1826     if (!has_pointers) has_pointers = type_has_pointers(type);
1827
1828     array = find_array_or_string_in_struct(type);
1829     if (array && !processed(array->type))
1830         array_offset
1831             = is_attr(array->attrs, ATTR_STRING)
1832             ? write_string_tfs(file, array->attrs, array->type, array->name, tfsoff, FALSE)
1833             : write_array_tfs(file, array->attrs, array->type, array->name, tfsoff);
1834
1835     corroff = *tfsoff;
1836     write_descriptors(file, type, tfsoff);
1837
1838     start_offset = *tfsoff;
1839     update_tfsoff(type, start_offset, file);
1840     print_start_tfs_comment(file, type, start_offset);
1841     print_file(file, 2, "0x%x,\t/* %s */\n", type->type, string_of_type(type->type));
1842     print_file(file, 2, "0x%x,\t/* %d */\n", align - 1, align - 1);
1843     print_file(file, 2, "NdrFcShort(0x%x),\t/* %d */\n", total_size, total_size);
1844     *tfsoff += 4;
1845
1846     if (array)
1847     {
1848         unsigned int absoff = array->type->typestring_offset;
1849         short reloff = absoff - *tfsoff;
1850         print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%lu) */\n",
1851                    reloff, reloff, absoff);
1852         *tfsoff += 2;
1853     }
1854     else if (type->type == RPC_FC_BOGUS_STRUCT)
1855     {
1856         print_file(file, 2, "NdrFcShort(0x0),\n");
1857         *tfsoff += 2;
1858     }
1859
1860     if (type->type == RPC_FC_BOGUS_STRUCT)
1861     {
1862         /* On the sizing pass, type->ptrdesc may be zero, but it's ok as
1863            nothing is written to file yet.  On the actual writing pass,
1864            this will have been updated.  */
1865         unsigned int absoff = type->ptrdesc ? type->ptrdesc : *tfsoff;
1866         short reloff = absoff - *tfsoff;
1867         print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%u) */\n",
1868                    reloff, reloff, absoff);
1869         *tfsoff += 2;
1870     }
1871     else if ((type->type == RPC_FC_PSTRUCT) ||
1872              (type->type == RPC_FC_CPSTRUCT) ||
1873              (type->type == RPC_FC_CVSTRUCT && has_pointers))
1874     {
1875         print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
1876         print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
1877         *tfsoff += 2;
1878         write_pointer_description(file, type, tfsoff);
1879         print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
1880         *tfsoff += 1;
1881     }
1882
1883     write_struct_members(file, type, &corroff, tfsoff);
1884
1885     if (type->type == RPC_FC_BOGUS_STRUCT)
1886     {
1887         const var_list_t *fs = type->fields;
1888         const var_t *f;
1889
1890         type->ptrdesc = *tfsoff;
1891         if (fs) LIST_FOR_EACH_ENTRY(f, fs, const var_t, entry)
1892         {
1893             type_t *ft = f->type;
1894             if (is_ptr(ft))
1895                 write_pointer_tfs(file, ft, tfsoff);
1896             else if (!ft->declarray && is_conformant_array(ft))
1897             {
1898                 unsigned int absoff = ft->typestring_offset;
1899                 short reloff = absoff - (*tfsoff + 2);
1900                 int ptr_type = get_attrv(f->attrs, ATTR_POINTERTYPE);
1901                 /* FIXME: We need to store pointer attributes for arrays
1902                    so we don't lose pointer_default info.  */
1903                 if (ptr_type == 0)
1904                     ptr_type = RPC_FC_UP;
1905                 print_file(file, 0, "/* %d */\n", *tfsoff);
1906                 print_file(file, 2, "0x%x, 0x0,\t/* %s */\n", ptr_type,
1907                            string_of_type(ptr_type));
1908                 print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%u) */\n",
1909                            reloff, reloff, absoff);
1910                 *tfsoff += 4;
1911             }
1912         }
1913         if (type->ptrdesc == *tfsoff)
1914             type->ptrdesc = 0;
1915     }
1916
1917     current_structure = save_current_structure;
1918     return start_offset;
1919 }
1920
1921 static size_t write_pointer_only_tfs(FILE *file, const attr_list_t *attrs, int pointer_type,
1922                                      unsigned char flags, size_t offset,
1923                                      unsigned int *typeformat_offset)
1924 {
1925     size_t start_offset = *typeformat_offset;
1926     short reloff = offset - (*typeformat_offset + 2);
1927     int in_attr, out_attr;
1928     in_attr = is_attr(attrs, ATTR_IN);
1929     out_attr = is_attr(attrs, ATTR_OUT);
1930     if (!in_attr && !out_attr) in_attr = 1;
1931
1932     if (out_attr && !in_attr && pointer_type == RPC_FC_RP)
1933         flags |= 0x04;
1934
1935     print_file(file, 2, "0x%x, 0x%x,\t\t/* %s",
1936                pointer_type,
1937                flags,
1938                string_of_type(pointer_type));
1939     if (file)
1940     {
1941         if (flags & 0x04)
1942             fprintf(file, " [allocated_on_stack]");
1943         if (flags & 0x10)
1944             fprintf(file, " [pointer_deref]");
1945         fprintf(file, " */\n");
1946     }
1947
1948     print_file(file, 2, "NdrFcShort(0x%x),\t/* %d */\n", reloff, offset);
1949     *typeformat_offset += 4;
1950
1951     return start_offset;
1952 }
1953
1954 static void write_branch_type(FILE *file, const type_t *t, unsigned int *tfsoff)
1955 {
1956     if (t == NULL)
1957     {
1958         print_file(file, 2, "NdrFcShort(0x0),\t/* No type */\n");
1959     }
1960     else if (is_base_type(t->type))
1961     {
1962         print_file(file, 2, "NdrFcShort(0x80%02x),\t/* Simple arm type: %s */\n",
1963                    t->type, string_of_type(t->type));
1964     }
1965     else if (t->typestring_offset)
1966     {
1967         short reloff = t->typestring_offset - *tfsoff;
1968         print_file(file, 2, "NdrFcShort(0x%x),\t/* Offset= %d (%d) */\n",
1969                    reloff, reloff, t->typestring_offset);
1970     }
1971     else
1972         error("write_branch_type: type unimplemented (0x%x)\n", t->type);
1973
1974     *tfsoff += 2;
1975 }
1976
1977 static size_t write_union_tfs(FILE *file, type_t *type, unsigned int *tfsoff)
1978 {
1979     unsigned int align = 0;
1980     unsigned int start_offset;
1981     size_t size = type_memsize(type, &align);
1982     var_list_t *fields;
1983     size_t nbranch = 0;
1984     type_t *deftype = NULL;
1985     short nodeftype = 0xffff;
1986     var_t *f;
1987
1988     guard_rec(type);
1989
1990     if (type->type == RPC_FC_ENCAPSULATED_UNION)
1991     {
1992         const var_t *uv = LIST_ENTRY(list_tail(type->fields), const var_t, entry);
1993         fields = uv->type->fields;
1994     }
1995     else
1996         fields = type->fields;
1997
1998     if (fields) LIST_FOR_EACH_ENTRY(f, fields, var_t, entry)
1999     {
2000         expr_list_t *cases = get_attrp(f->attrs, ATTR_CASE);
2001         if (cases)
2002             nbranch += list_count(cases);
2003         if (f->type)
2004             write_embedded_types(file, f->attrs, f->type, f->name, TRUE, tfsoff);
2005     }
2006
2007     start_offset = *tfsoff;
2008     update_tfsoff(type, start_offset, file);
2009     print_start_tfs_comment(file, type, start_offset);
2010     if (type->type == RPC_FC_ENCAPSULATED_UNION)
2011     {
2012         const var_t *sv = LIST_ENTRY(list_head(type->fields), const var_t, entry);
2013         const type_t *st = sv->type;
2014
2015         switch (st->type)
2016         {
2017         case RPC_FC_CHAR:
2018         case RPC_FC_SMALL:
2019         case RPC_FC_USMALL:
2020         case RPC_FC_SHORT:
2021         case RPC_FC_USHORT:
2022         case RPC_FC_LONG:
2023         case RPC_FC_ULONG:
2024         case RPC_FC_ENUM16:
2025         case RPC_FC_ENUM32:
2026             print_file(file, 2, "0x%x,\t/* %s */\n", type->type, string_of_type(type->type));
2027             print_file(file, 2, "0x%x,\t/* Switch type= %s */\n",
2028                        0x40 | st->type, string_of_type(st->type));
2029             *tfsoff += 2;
2030             break;
2031         default:
2032             error("union switch type must be an integer, char, or enum\n");
2033         }
2034     }
2035     print_file(file, 2, "NdrFcShort(0x%x),\t/* %d */\n", size, size);
2036     print_file(file, 2, "NdrFcShort(0x%x),\t/* %d */\n", nbranch, nbranch);
2037     *tfsoff += 4;
2038
2039     if (fields) LIST_FOR_EACH_ENTRY(f, fields, var_t, entry)
2040     {
2041         type_t *ft = f->type;
2042         expr_list_t *cases = get_attrp(f->attrs, ATTR_CASE);
2043         int deflt = is_attr(f->attrs, ATTR_DEFAULT);
2044         expr_t *c;
2045
2046         if (cases == NULL && !deflt)
2047             error("union field %s with neither case nor default attribute\n", f->name);
2048
2049         if (cases) LIST_FOR_EACH_ENTRY(c, cases, expr_t, entry)
2050         {
2051             /* MIDL doesn't check for duplicate cases, even though that seems
2052                like a reasonable thing to do, it just dumps them to the TFS
2053                like we're going to do here.  */
2054             print_file(file, 2, "NdrFcLong(0x%x),\t/* %d */\n", c->cval, c->cval);
2055             *tfsoff += 4;
2056             write_branch_type(file, ft, tfsoff);
2057         }
2058
2059         /* MIDL allows multiple default branches, even though that seems
2060            illogical, it just chooses the last one, which is what we will
2061            do.  */
2062         if (deflt)
2063         {
2064             deftype = ft;
2065             nodeftype = 0;
2066         }
2067     }
2068
2069     if (deftype)
2070     {
2071         write_branch_type(file, deftype, tfsoff);
2072     }
2073     else
2074     {
2075         print_file(file, 2, "NdrFcShort(0x%x),\n", nodeftype);
2076         *tfsoff += 2;
2077     }
2078
2079     return start_offset;
2080 }
2081
2082 static size_t write_ip_tfs(FILE *file, const attr_list_t *attrs, type_t *type,
2083                            unsigned int *typeformat_offset)
2084 {
2085     size_t i;
2086     size_t start_offset = *typeformat_offset;
2087     expr_t *iid = get_attrp(attrs, ATTR_IIDIS);
2088
2089     if (iid)
2090     {
2091         print_file(file, 2, "0x2f,  /* FC_IP */\n");
2092         print_file(file, 2, "0x5c,  /* FC_PAD */\n");
2093         *typeformat_offset
2094             += write_conf_or_var_desc(file, NULL, 0, type, iid) + 2;
2095     }
2096     else
2097     {
2098         const type_t *base = is_ptr(type) ? type->ref : type;
2099         const UUID *uuid = get_attrp(base->attrs, ATTR_UUID);
2100
2101         if (! uuid)
2102             error("%s: interface %s missing UUID\n", __FUNCTION__, base->name);
2103
2104         update_tfsoff(type, start_offset, file);
2105         print_start_tfs_comment(file, type, start_offset);
2106         print_file(file, 2, "0x2f,\t/* FC_IP */\n");
2107         print_file(file, 2, "0x5a,\t/* FC_CONSTANT_IID */\n");
2108         print_file(file, 2, "NdrFcLong(0x%08lx),\n", uuid->Data1);
2109         print_file(file, 2, "NdrFcShort(0x%04x),\n", uuid->Data2);
2110         print_file(file, 2, "NdrFcShort(0x%04x),\n", uuid->Data3);
2111         for (i = 0; i < 8; ++i)
2112             print_file(file, 2, "0x%02x,\n", uuid->Data4[i]);
2113
2114         if (file)
2115             fprintf(file, "\n");
2116
2117         *typeformat_offset += 18;
2118     }
2119     return start_offset;
2120 }
2121
2122 static size_t write_contexthandle_tfs(FILE *file, const type_t *type,
2123                                       const var_t *var,
2124                                       unsigned int *typeformat_offset)
2125 {
2126     size_t start_offset = *typeformat_offset;
2127     unsigned char flags = 0;
2128
2129     if (is_attr(current_iface->attrs, ATTR_STRICTCONTEXTHANDLE))
2130         flags |= NDR_STRICT_CONTEXT_HANDLE;
2131
2132     if (is_ptr(type))
2133         flags |= 0x80;
2134     if (is_attr(var->attrs, ATTR_IN))
2135     {
2136         flags |= 0x40;
2137         if (!is_attr(var->attrs, ATTR_OUT))
2138             flags |= NDR_CONTEXT_HANDLE_CANNOT_BE_NULL;
2139     }
2140     if (is_attr(var->attrs, ATTR_OUT))
2141         flags |= 0x20;
2142
2143     WRITE_FCTYPE(file, FC_BIND_CONTEXT, *typeformat_offset);
2144     print_file(file, 2, "0x%x,\t/* Context flags: ", flags);
2145     /* return and can't be null values overlap */
2146     if (((flags & 0x21) != 0x21) && (flags & NDR_CONTEXT_HANDLE_CANNOT_BE_NULL))
2147         print_file(file, 0, "can't be null, ");
2148     if (flags & NDR_CONTEXT_HANDLE_SERIALIZE)
2149         print_file(file, 0, "serialize, ");
2150     if (flags & NDR_CONTEXT_HANDLE_NO_SERIALIZE)
2151         print_file(file, 0, "no serialize, ");
2152     if (flags & NDR_STRICT_CONTEXT_HANDLE)
2153         print_file(file, 0, "strict, ");
2154     if ((flags & 0x21) == 0x20)
2155         print_file(file, 0, "out, ");
2156     if ((flags & 0x21) == 0x21)
2157         print_file(file, 0, "return, ");
2158     if (flags & 0x40)
2159         print_file(file, 0, "in, ");
2160     if (flags & 0x80)
2161         print_file(file, 0, "via ptr, ");
2162     print_file(file, 0, "*/\n");
2163     print_file(file, 2, "0, /* FIXME: rundown routine index*/\n");
2164     print_file(file, 2, "0, /* FIXME: param num */\n");
2165     *typeformat_offset += 4;
2166
2167     return start_offset;
2168 }
2169
2170 static size_t write_typeformatstring_var(FILE *file, int indent, const func_t *func,
2171                                          type_t *type, const var_t *var,
2172                                          unsigned int *typeformat_offset)
2173 {
2174     size_t offset;
2175
2176     if (is_context_handle(type))
2177         return write_contexthandle_tfs(file, type, var, typeformat_offset);
2178
2179     if (is_user_type(type))
2180     {
2181         write_user_tfs(file, type, typeformat_offset);
2182         return type->typestring_offset;
2183     }
2184
2185     if ((last_ptr(type) || last_array(type)) && is_ptrchain_attr(var, ATTR_STRING))
2186         return write_string_tfs(file, var->attrs, type, var->name, typeformat_offset, TRUE);
2187
2188     if (is_array(type))
2189     {
2190         int ptr_type;
2191         size_t off;
2192         off = write_array_tfs(file, var->attrs, type, var->name, typeformat_offset);
2193         ptr_type = get_attrv(var->attrs, ATTR_POINTERTYPE);
2194         /* Top level pointers to conformant arrays may be handled specially
2195            since we can bypass the pointer, but if the array is buried
2196            beneath another pointer (e.g., "[size_is(,n)] int **p" then we
2197            always need to write the pointer.  */
2198         if (!ptr_type && var->type != type)
2199           /* FIXME:  This should use pointer_default, but the information
2200              isn't kept around for arrays.  */
2201           ptr_type = RPC_FC_UP;
2202         if (ptr_type && ptr_type != RPC_FC_RP)
2203         {
2204             unsigned int absoff = type->typestring_offset;
2205             short reloff = absoff - (*typeformat_offset + 2);
2206             off = *typeformat_offset;
2207             print_file(file, 0, "/* %d */\n", off);
2208             print_file(file, 2, "0x%x, 0x0,\t/* %s */\n", ptr_type,
2209                        string_of_type(ptr_type));
2210             print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%u) */\n",
2211                        reloff, reloff, absoff);
2212             *typeformat_offset += 4;
2213         }
2214         return off;
2215     }
2216
2217     if (!is_ptr(type))
2218     {
2219         /* basic types don't need a type format string */
2220         if (is_base_type(type->type))
2221             return 0;
2222
2223         switch (type->type)
2224         {
2225         case RPC_FC_STRUCT:
2226         case RPC_FC_PSTRUCT:
2227         case RPC_FC_CSTRUCT:
2228         case RPC_FC_CPSTRUCT:
2229         case RPC_FC_CVSTRUCT:
2230         case RPC_FC_BOGUS_STRUCT:
2231             return write_struct_tfs(file, type, var->name, typeformat_offset);
2232         case RPC_FC_ENCAPSULATED_UNION:
2233         case RPC_FC_NON_ENCAPSULATED_UNION:
2234             return write_union_tfs(file, type, typeformat_offset);
2235         case RPC_FC_IGNORE:
2236         case RPC_FC_BIND_PRIMITIVE:
2237             /* nothing to do */
2238             return 0;
2239         default:
2240             error("write_typeformatstring_var: Unsupported type 0x%x for variable %s\n", type->type, var->name);
2241         }
2242     }
2243     else if (last_ptr(type))
2244     {
2245         size_t start_offset = *typeformat_offset;
2246         int in_attr = is_attr(var->attrs, ATTR_IN);
2247         int out_attr = is_attr(var->attrs, ATTR_OUT);
2248         const type_t *base = type->ref;
2249
2250         if (base->type == RPC_FC_IP
2251             || (base->type == 0
2252                 && is_attr(var->attrs, ATTR_IIDIS)))
2253         {
2254             return write_ip_tfs(file, var->attrs, type, typeformat_offset);
2255         }
2256
2257         /* special case for pointers to base types */
2258         if (is_base_type(base->type))
2259         {
2260             print_file(file, indent, "0x%x, 0x%x,    /* %s %s[simple_pointer] */\n",
2261                        type->type, (!in_attr && out_attr) ? 0x0C : 0x08,
2262                        string_of_type(type->type),
2263                        (!in_attr && out_attr) ? "[allocated_on_stack] " : "");
2264             print_file(file, indent, "0x%02x,    /* %s */\n", base->type, string_of_type(base->type));
2265             print_file(file, indent, "0x5c,          /* FC_PAD */\n");
2266             *typeformat_offset += 4;
2267             return start_offset;
2268         }
2269     }
2270
2271     assert(is_ptr(type));
2272
2273     offset = write_typeformatstring_var(file, indent, func, type->ref, var, typeformat_offset);
2274     if (file)
2275         fprintf(file, "/* %2u */\n", *typeformat_offset);
2276     return write_pointer_only_tfs(file, var->attrs, type->type,
2277                            !last_ptr(type) ? 0x10 : 0,
2278                            offset, typeformat_offset);
2279 }
2280
2281 static int write_embedded_types(FILE *file, const attr_list_t *attrs, type_t *type,
2282                                 const char *name, int write_ptr, unsigned int *tfsoff)
2283 {
2284     int retmask = 0;
2285
2286     if (is_user_type(type))
2287     {
2288         write_user_tfs(file, type, tfsoff);
2289     }
2290     else if (is_ptr(type))
2291     {
2292         type_t *ref = type->ref;
2293
2294         if (ref->type == RPC_FC_IP
2295             || (ref->type == 0
2296                 && is_attr(attrs, ATTR_IIDIS)))
2297         {
2298             write_ip_tfs(file, attrs, type, tfsoff);
2299         }
2300         else
2301         {
2302             if (!processed(ref) && !is_base_type(ref->type))
2303                 retmask |= write_embedded_types(file, NULL, ref, name, TRUE, tfsoff);
2304
2305             if (write_ptr)
2306                 write_pointer_tfs(file, type, tfsoff);
2307
2308             retmask |= 1;
2309         }
2310     }
2311     else if (last_array(type) && is_attr(attrs, ATTR_STRING))
2312     {
2313         write_string_tfs(file, attrs, type, name, tfsoff, FALSE);
2314     }
2315     else if (type->declarray && is_conformant_array(type))
2316         ;    /* conformant arrays and strings are handled specially */
2317     else if (is_array(type))
2318     {
2319         write_array_tfs(file, attrs, type, name, tfsoff);
2320         if (is_conformant_array(type))
2321             retmask |= 1;
2322     }
2323     else if (is_struct(type->type))
2324     {
2325         if (!processed(type))
2326             write_struct_tfs(file, type, name, tfsoff);
2327     }
2328     else if (is_union(type->type))
2329     {
2330         if (!processed(type))
2331             write_union_tfs(file, type, tfsoff);
2332     }
2333     else if (!is_base_type(type->type))
2334         error("write_embedded_types: unknown embedded type for %s (0x%x)\n",
2335               name, type->type);
2336
2337     return retmask;
2338 }
2339
2340 static size_t process_tfs(FILE *file, const ifref_list_t *ifaces, type_pred_t pred)
2341 {
2342     const var_t *var;
2343     const ifref_t *iface;
2344     unsigned int typeformat_offset = 2;
2345
2346     if (ifaces) LIST_FOR_EACH_ENTRY( iface, ifaces, const ifref_t, entry )
2347     {
2348         if (!pred(iface->iface))
2349             continue;
2350
2351         if (iface->iface->funcs)
2352         {
2353             const func_t *func;
2354             current_iface = iface;
2355             LIST_FOR_EACH_ENTRY( func, iface->iface->funcs, const func_t, entry )
2356             {
2357                 if (is_local(func->def->attrs)) continue;
2358
2359                 current_func = func;
2360                 if (func->args)
2361                     LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
2362                         update_tfsoff(
2363                             var->type,
2364                             write_typeformatstring_var(
2365                                 file, 2, func, var->type, var,
2366                                 &typeformat_offset),
2367                             file);
2368             }
2369         }
2370     }
2371
2372     return typeformat_offset + 1;
2373 }
2374
2375
2376 void write_typeformatstring(FILE *file, const ifref_list_t *ifaces, type_pred_t pred)
2377 {
2378     int indent = 0;
2379
2380     print_file(file, indent, "static const MIDL_TYPE_FORMAT_STRING __MIDL_TypeFormatString =\n");
2381     print_file(file, indent, "{\n");
2382     indent++;
2383     print_file(file, indent, "0,\n");
2384     print_file(file, indent, "{\n");
2385     indent++;
2386     print_file(file, indent, "NdrFcShort(0x0),\n");
2387
2388     set_all_tfswrite(TRUE);
2389     process_tfs(file, ifaces, pred);
2390
2391     print_file(file, indent, "0x0\n");
2392     indent--;
2393     print_file(file, indent, "}\n");
2394     indent--;
2395     print_file(file, indent, "};\n");
2396     print_file(file, indent, "\n");
2397 }
2398
2399 static unsigned int get_required_buffer_size_type(
2400     const type_t *type, const char *name, unsigned int *alignment)
2401 {
2402     *alignment = 0;
2403     if (is_user_type(type))
2404     {
2405         const char *uname;
2406         const type_t *utype = get_user_type(type, &uname);
2407         return get_required_buffer_size_type(utype, uname, alignment);
2408     }
2409     else
2410     {
2411         switch (type->type)
2412         {
2413         case RPC_FC_BYTE:
2414         case RPC_FC_CHAR:
2415         case RPC_FC_USMALL:
2416         case RPC_FC_SMALL:
2417             *alignment = 4;
2418             return 1;
2419
2420         case RPC_FC_WCHAR:
2421         case RPC_FC_USHORT:
2422         case RPC_FC_SHORT:
2423         case RPC_FC_ENUM16:
2424             *alignment = 4;
2425             return 2;
2426
2427         case RPC_FC_ULONG:
2428         case RPC_FC_LONG:
2429         case RPC_FC_ENUM32:
2430         case RPC_FC_FLOAT:
2431         case RPC_FC_ERROR_STATUS_T:
2432             *alignment = 4;
2433             return 4;
2434
2435         case RPC_FC_HYPER:
2436         case RPC_FC_DOUBLE:
2437             *alignment = 8;
2438             return 8;
2439
2440         case RPC_FC_IGNORE:
2441         case RPC_FC_BIND_PRIMITIVE:
2442             return 0;
2443
2444         case RPC_FC_STRUCT:
2445         case RPC_FC_PSTRUCT:
2446         {
2447             size_t size = 0;
2448             const var_t *field;
2449             if (!type->fields) return 0;
2450             LIST_FOR_EACH_ENTRY( field, type->fields, const var_t, entry )
2451             {
2452                 unsigned int alignment;
2453                 size += get_required_buffer_size_type(field->type, field->name,
2454                                                       &alignment);
2455             }
2456             return size;
2457         }
2458
2459         case RPC_FC_RP:
2460             return
2461                 is_base_type( type->ref->type ) || type->ref->type == RPC_FC_STRUCT
2462                 ? get_required_buffer_size_type( type->ref, name, alignment )
2463                 : 0;
2464
2465         case RPC_FC_SMFARRAY:
2466         case RPC_FC_LGFARRAY:
2467             return type->dim * get_required_buffer_size_type(type->ref, name, alignment);
2468
2469         default:
2470             return 0;
2471         }
2472     }
2473 }
2474
2475 static unsigned int get_required_buffer_size(const var_t *var, unsigned int *alignment, enum pass pass)
2476 {
2477     int in_attr = is_attr(var->attrs, ATTR_IN);
2478     int out_attr = is_attr(var->attrs, ATTR_OUT);
2479     const type_t *t;
2480
2481     if (!in_attr && !out_attr)
2482         in_attr = 1;
2483
2484     *alignment = 0;
2485
2486     for (t = var->type; is_ptr(t); t = t->ref)
2487         if (is_attr(t->attrs, ATTR_CONTEXTHANDLE))
2488         {
2489             *alignment = 4;
2490             return 20;
2491         }
2492
2493     if (pass == PASS_OUT)
2494     {
2495         if (out_attr && is_ptr(var->type))
2496         {
2497             type_t *type = var->type;
2498
2499             if (type->type == RPC_FC_STRUCT)
2500             {
2501                 const var_t *field;
2502                 unsigned int size = 36;
2503
2504                 if (!type->fields) return size;
2505                 LIST_FOR_EACH_ENTRY( field, type->fields, const var_t, entry )
2506                 {
2507                     unsigned int align;
2508                     size += get_required_buffer_size_type(
2509                         field->type, field->name, &align);
2510                 }
2511                 return size;
2512             }
2513         }
2514         return 0;
2515     }
2516     else
2517     {
2518         if ((!out_attr || in_attr) && !var->type->size_is
2519             && !is_attr(var->attrs, ATTR_STRING) && !var->type->declarray)
2520         {
2521             if (is_ptr(var->type))
2522             {
2523                 type_t *type = var->type;
2524
2525                 if (is_base_type(type->type))
2526                 {
2527                     return 25;
2528                 }
2529                 else if (type->type == RPC_FC_STRUCT)
2530                 {
2531                     unsigned int size = 36;
2532                     const var_t *field;
2533
2534                     if (!type->fields) return size;
2535                     LIST_FOR_EACH_ENTRY( field, type->fields, const var_t, entry )
2536                     {
2537                         unsigned int align;
2538                         size += get_required_buffer_size_type(
2539                             field->type, field->name, &align);
2540                     }
2541                     return size;
2542                 }
2543             }
2544         }
2545
2546         return get_required_buffer_size_type(var->type, var->name, alignment);
2547     }
2548 }
2549
2550 static unsigned int get_function_buffer_size( const func_t *func, enum pass pass )
2551 {
2552     const var_t *var;
2553     unsigned int total_size = 0, alignment;
2554
2555     if (func->args)
2556     {
2557         LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
2558         {
2559             total_size += get_required_buffer_size(var, &alignment, pass);
2560             total_size += alignment;
2561         }
2562     }
2563
2564     if (pass == PASS_OUT && !is_void(func->def->type))
2565     {
2566         total_size += get_required_buffer_size(func->def, &alignment, PASS_RETURN);
2567         total_size += alignment;
2568     }
2569     return total_size;
2570 }
2571
2572 static void print_phase_function(FILE *file, int indent, const char *type,
2573                                  enum remoting_phase phase,
2574                                  const var_t *var, unsigned int type_offset)
2575 {
2576     const char *function;
2577     switch (phase)
2578     {
2579     case PHASE_BUFFERSIZE:
2580         function = "BufferSize";
2581         break;
2582     case PHASE_MARSHAL:
2583         function = "Marshall";
2584         break;
2585     case PHASE_UNMARSHAL:
2586         function = "Unmarshall";
2587         break;
2588     case PHASE_FREE:
2589         function = "Free";
2590         break;
2591     default:
2592         assert(0);
2593         return;
2594     }
2595
2596     print_file(file, indent, "Ndr%s%s(\n", type, function);
2597     indent++;
2598     print_file(file, indent, "&_StubMsg,\n");
2599     print_file(file, indent, "%s%s%s%s,\n",
2600                (phase == PHASE_UNMARSHAL) ? "(unsigned char **)" : "(unsigned char *)",
2601                (phase == PHASE_UNMARSHAL || decl_indirect(var->type)) ? "&" : "",
2602                (phase == PHASE_UNMARSHAL && decl_indirect(var->type)) ? "_p_" : "",
2603                var->name);
2604     print_file(file, indent, "(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%d]%s\n",
2605                type_offset, (phase == PHASE_UNMARSHAL) ? "," : ");");
2606     if (phase == PHASE_UNMARSHAL)
2607         print_file(file, indent, "0);\n");
2608     indent--;
2609 }
2610
2611 void print_phase_basetype(FILE *file, int indent, enum remoting_phase phase,
2612                           enum pass pass, const var_t *var,
2613                           const char *varname)
2614 {
2615     type_t *type = var->type;
2616     unsigned int size;
2617     unsigned int alignment = 0;
2618     unsigned char rtype;
2619
2620     /* no work to do for other phases, buffer sizing is done elsewhere */
2621     if (phase != PHASE_MARSHAL && phase != PHASE_UNMARSHAL)
2622         return;
2623
2624     rtype = is_ptr(type) ? type->ref->type : type->type;
2625
2626     switch (rtype)
2627     {
2628         case RPC_FC_BYTE:
2629         case RPC_FC_CHAR:
2630         case RPC_FC_SMALL:
2631         case RPC_FC_USMALL:
2632             size = 1;
2633             alignment = 1;
2634             break;
2635
2636         case RPC_FC_WCHAR:
2637         case RPC_FC_USHORT:
2638         case RPC_FC_SHORT:
2639         case RPC_FC_ENUM16:
2640             size = 2;
2641             alignment = 2;
2642             break;
2643
2644         case RPC_FC_ULONG:
2645         case RPC_FC_LONG:
2646         case RPC_FC_ENUM32:
2647         case RPC_FC_FLOAT:
2648         case RPC_FC_ERROR_STATUS_T:
2649             size = 4;
2650             alignment = 4;
2651             break;
2652
2653         case RPC_FC_HYPER:
2654         case RPC_FC_DOUBLE:
2655             size = 8;
2656             alignment = 8;
2657             break;
2658
2659         case RPC_FC_IGNORE:
2660         case RPC_FC_BIND_PRIMITIVE:
2661             /* no marshalling needed */
2662             return;
2663
2664         default:
2665             error("print_phase_basetype: Unsupported type: %s (0x%02x, ptr_level: 0)\n", var->name, rtype);
2666             size = 0;
2667     }
2668
2669     if (phase == PHASE_MARSHAL)
2670         print_file(file, indent, "MIDL_memset(_StubMsg.Buffer, 0, (0x%x - (long)_StubMsg.Buffer) & 0x%x);\n", alignment, alignment - 1);
2671     print_file(file, indent, "_StubMsg.Buffer = (unsigned char *)(((long)_StubMsg.Buffer + %u) & ~0x%x);\n",
2672                 alignment - 1, alignment - 1);
2673
2674     if (phase == PHASE_MARSHAL)
2675     {
2676         print_file(file, indent, "*(");
2677         write_type_decl(file, is_ptr(type) ? type->ref : type, NULL);
2678         if (is_ptr(type))
2679             fprintf(file, " *)_StubMsg.Buffer = *");
2680         else
2681             fprintf(file, " *)_StubMsg.Buffer = ");
2682         fprintf(file, "%s", varname);
2683         fprintf(file, ";\n");
2684     }
2685     else if (phase == PHASE_UNMARSHAL)
2686     {
2687         print_file(file, indent, "if (_StubMsg.Buffer + sizeof(");
2688         write_type_decl(file, is_ptr(type) ? type->ref : type, NULL);
2689         fprintf(file, ") > _StubMsg.BufferEnd)\n");
2690         print_file(file, indent, "{\n");
2691         print_file(file, indent + 1, "RpcRaiseException(RPC_X_BAD_STUB_DATA);\n");
2692         print_file(file, indent, "}\n");
2693         if (pass == PASS_IN || pass == PASS_RETURN)
2694             print_file(file, indent, "");
2695         else
2696             print_file(file, indent, "*");
2697         fprintf(file, "%s", varname);
2698         if (pass == PASS_IN && is_ptr(type))
2699             fprintf(file, " = (");
2700         else
2701             fprintf(file, " = *(");
2702         write_type_decl(file, is_ptr(type) ? type->ref : type, NULL);
2703         fprintf(file, " *)_StubMsg.Buffer;\n");
2704     }
2705
2706     print_file(file, indent, "_StubMsg.Buffer += sizeof(");
2707     write_type_decl(file, var->type, NULL);
2708     fprintf(file, ");\n");
2709 }
2710
2711 /* returns whether the MaxCount, Offset or ActualCount members need to be
2712  * filled in for the specified phase */
2713 static inline int is_size_needed_for_phase(enum remoting_phase phase)
2714 {
2715     return (phase != PHASE_UNMARSHAL);
2716 }
2717
2718 expr_t *get_size_is_expr(const type_t *t, const char *name)
2719 {
2720     expr_t *x = NULL;
2721
2722     for ( ; is_ptr(t) || is_array(t); t = t->ref)
2723         if (t->size_is)
2724         {
2725             if (!x)
2726                 x = t->size_is;
2727             else
2728                 error("%s: multidimensional conformant"
2729                       " arrays not supported at the top level\n",
2730                       name);
2731         }
2732
2733     return x;
2734 }
2735
2736 static void write_remoting_arg(FILE *file, int indent, const func_t *func,
2737                               enum pass pass, enum remoting_phase phase,
2738                               const var_t *var)
2739 {
2740     int in_attr, out_attr, pointer_type;
2741     const type_t *type = var->type;
2742     unsigned char rtype;
2743     size_t start_offset = type->typestring_offset;
2744
2745     pointer_type = get_attrv(var->attrs, ATTR_POINTERTYPE);
2746     if (!pointer_type)
2747         pointer_type = RPC_FC_RP;
2748
2749     in_attr = is_attr(var->attrs, ATTR_IN);
2750     out_attr = is_attr(var->attrs, ATTR_OUT);
2751     if (!in_attr && !out_attr)
2752         in_attr = 1;
2753
2754     if (phase != PHASE_FREE)
2755         switch (pass)
2756         {
2757         case PASS_IN:
2758             if (!in_attr) return;
2759             break;
2760         case PASS_OUT:
2761             if (!out_attr) return;
2762             break;
2763         case PASS_RETURN:
2764             break;
2765         }
2766
2767     rtype = type->type;
2768
2769     if (is_context_handle(type))
2770     {
2771         if (phase == PHASE_MARSHAL)
2772         {
2773             if (pass == PASS_IN)
2774             {
2775                 print_file(file, indent, "NdrClientContextMarshall(\n");
2776                 print_file(file, indent + 1, "&_StubMsg,\n");
2777                 print_file(file, indent + 1, "(NDR_CCONTEXT)%s%s,\n", is_ptr(type) ? "*" : "", var->name);
2778                 print_file(file, indent + 1, "%s);\n", in_attr && out_attr ? "1" : "0");
2779             }
2780             else
2781             {
2782                 print_file(file, indent, "NdrServerContextNewMarshall(\n");
2783                 print_file(file, indent + 1, "&_StubMsg,\n");
2784                 print_file(file, indent + 1, "(NDR_SCONTEXT)%s,\n", var->name);
2785                 print_file(file, indent + 1, "(NDR_RUNDOWN)%s_rundown,\n", get_context_handle_type_name(var->type));
2786                 print_file(file, indent + 1, "(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%d]);\n", start_offset);
2787             }
2788         }
2789         else if (phase == PHASE_UNMARSHAL)
2790         {
2791             if (pass == PASS_OUT)
2792             {
2793                 if (!in_attr)
2794                     print_file(file, indent, "*%s = 0;\n", var->name);
2795                 print_file(file, indent, "NdrClientContextUnmarshall(\n");
2796                 print_file(file, indent + 1, "&_StubMsg,\n");
2797                 print_file(file, indent + 1, "(NDR_CCONTEXT *)%s,\n", var->name);
2798                 print_file(file, indent + 1, "_Handle);\n");
2799             }
2800             else
2801             {
2802                 print_file(file, indent, "%s = NdrServerContextNewUnmarshall(\n", var->name);
2803                 print_file(file, indent + 1, "&_StubMsg,\n");
2804                 print_file(file, indent + 1, "(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%d]);\n", start_offset);
2805             }
2806         }
2807     }
2808     else if (is_user_type(var->type))
2809     {
2810         print_phase_function(file, indent, "UserMarshal", phase, var, start_offset);
2811     }
2812     else if (is_string_type(var->attrs, var->type))
2813     {
2814         if (is_array(type) && !is_conformant_array(type))
2815             print_phase_function(file, indent, "NonConformantString", phase, var, start_offset);
2816         else
2817         {
2818             if (type->size_is && is_size_needed_for_phase(phase))
2819             {
2820                 print_file(file, indent, "_StubMsg.MaxCount = (unsigned long)");
2821                 write_expr(file, type->size_is, 1);
2822                 fprintf(file, ";\n");
2823             }
2824
2825             if ((phase == PHASE_FREE) || (pointer_type == RPC_FC_UP))
2826                 print_phase_function(file, indent, "Pointer", phase, var,
2827                                      start_offset - (type->size_is ? 4 : 2));
2828             else
2829                 print_phase_function(file, indent, "ConformantString", phase, var,
2830                                      start_offset);
2831         }
2832     }
2833     else if (is_array(type))
2834     {
2835         unsigned char tc = type->type;
2836         const char *array_type = "FixedArray";
2837
2838         /* We already have the size_is expression since it's at the
2839            top level, but do checks for multidimensional conformant
2840            arrays.  When we handle them, we'll need to extend this
2841            function to return a list, and then we'll actually use
2842            the return value.  */
2843         get_size_is_expr(type, var->name);
2844
2845         if (tc == RPC_FC_SMVARRAY || tc == RPC_FC_LGVARRAY)
2846         {
2847             if (is_size_needed_for_phase(phase))
2848             {
2849                 print_file(file, indent, "_StubMsg.Offset = (unsigned long)0;\n"); /* FIXME */
2850                 print_file(file, indent, "_StubMsg.ActualCount = (unsigned long)");
2851                 write_expr(file, type->length_is, 1);
2852                 fprintf(file, ";\n\n");
2853             }
2854             array_type = "VaryingArray";
2855         }
2856         else if (tc == RPC_FC_CARRAY)
2857         {
2858             if (is_size_needed_for_phase(phase))
2859             {
2860                 print_file(file, indent, "_StubMsg.MaxCount = (unsigned long)");
2861                 write_expr(file, type->size_is, 1);
2862                 fprintf(file, ";\n\n");
2863             }
2864             array_type = "ConformantArray";
2865         }
2866         else if (tc == RPC_FC_CVARRAY || tc == RPC_FC_BOGUS_ARRAY)
2867         {
2868             if (is_size_needed_for_phase(phase))
2869             {
2870                 if (type->size_is)
2871                 {
2872                     print_file(file, indent, "_StubMsg.MaxCount = (unsigned long)");
2873                     write_expr(file, type->size_is, 1);
2874                     fprintf(file, ";\n");
2875                 }
2876                 if (type->length_is)
2877                 {
2878                     print_file(file, indent, "_StubMsg.Offset = (unsigned long)0;\n"); /* FIXME */
2879                     print_file(file, indent, "_StubMsg.ActualCount = (unsigned long)");
2880                     write_expr(file, type->length_is, 1);
2881                     fprintf(file, ";\n\n");
2882                 }
2883             }
2884             array_type = (tc == RPC_FC_BOGUS_ARRAY
2885                           ? "ComplexArray"
2886                           : "ConformantVaryingArray");
2887         }
2888
2889         if (pointer_type != RPC_FC_RP) array_type = "Pointer";
2890         print_phase_function(file, indent, array_type, phase, var, start_offset);
2891         if (phase == PHASE_FREE && pointer_type == RPC_FC_RP)
2892         {
2893             /* these are all unmarshalled by allocating memory */
2894             if (type->type == RPC_FC_BOGUS_ARRAY ||
2895                 type->type == RPC_FC_CVARRAY ||
2896                 ((type->type == RPC_FC_SMVARRAY || type->type == RPC_FC_LGVARRAY) && in_attr) ||
2897                 (type->type == RPC_FC_CARRAY && !in_attr))
2898             {
2899                 print_file(file, indent, "if (%s)\n", var->name);
2900                 indent++;
2901                 print_file(file, indent, "_StubMsg.pfnFree(%s);\n", var->name);
2902             }
2903         }
2904     }
2905     else if (!is_ptr(var->type) && is_base_type(rtype))
2906     {
2907         if (phase != PHASE_FREE)
2908             print_phase_basetype(file, indent, phase, pass, var, var->name);
2909     }
2910     else if (!is_ptr(var->type))
2911     {
2912         switch (rtype)
2913         {
2914         case RPC_FC_STRUCT:
2915         case RPC_FC_PSTRUCT:
2916             print_phase_function(file, indent, "SimpleStruct", phase, var, start_offset);
2917             break;
2918         case RPC_FC_CSTRUCT:
2919         case RPC_FC_CPSTRUCT:
2920             print_phase_function(file, indent, "ConformantStruct", phase, var, start_offset);
2921             break;
2922         case RPC_FC_CVSTRUCT:
2923             print_phase_function(file, indent, "ConformantVaryingStruct", phase, var, start_offset);
2924             break;
2925         case RPC_FC_BOGUS_STRUCT:
2926             print_phase_function(file, indent, "ComplexStruct", phase, var, start_offset);
2927             break;
2928         case RPC_FC_RP:
2929             if (is_base_type( var->type->ref->type ))
2930             {
2931                 print_phase_basetype(file, indent, phase, pass, var, var->name);
2932             }
2933             else if (var->type->ref->type == RPC_FC_STRUCT)
2934             {
2935                 if (phase != PHASE_BUFFERSIZE && phase != PHASE_FREE)
2936                     print_phase_function(file, indent, "SimpleStruct", phase, var, start_offset + 4);
2937             }
2938             else
2939             {
2940                 expr_t *iid;
2941                 if ((iid = get_attrp( var->attrs, ATTR_IIDIS )))
2942                 {
2943                     print_file( file, indent, "_StubMsg.MaxCount = (unsigned long) " );
2944                     write_expr( file, iid, 1 );
2945                     fprintf( file, ";\n\n" );
2946                 }
2947                 print_phase_function(file, indent, "Pointer", phase, var, start_offset);
2948             }
2949             break;
2950         default:
2951             error("write_remoting_arguments: Unsupported type: %s (0x%02x)\n", var->name, rtype);
2952         }
2953     }
2954     else
2955     {
2956         if (last_ptr(var->type) && (pointer_type == RPC_FC_RP) && is_base_type(rtype))
2957         {
2958             if (phase != PHASE_FREE)
2959                 print_phase_basetype(file, indent, phase, pass, var, var->name);
2960         }
2961         else if (last_ptr(var->type) && (pointer_type == RPC_FC_RP) && (rtype == RPC_FC_STRUCT))
2962         {
2963             if (phase != PHASE_BUFFERSIZE && phase != PHASE_FREE)
2964                 print_phase_function(file, indent, "SimpleStruct", phase, var, start_offset + 4);
2965         }
2966         else
2967         {
2968             expr_t *iid;
2969             expr_t *sx = get_size_is_expr(type, var->name);
2970
2971             if ((iid = get_attrp( var->attrs, ATTR_IIDIS )))
2972             {
2973                 print_file( file, indent, "_StubMsg.MaxCount = (unsigned long) " );
2974                 write_expr( file, iid, 1 );
2975                 fprintf( file, ";\n\n" );
2976             }
2977             else if (sx)
2978             {
2979                 print_file(file, indent, "_StubMsg.MaxCount = (unsigned long) ");
2980                 write_expr(file, sx, 1);
2981                 fprintf(file, ";\n\n");
2982             }
2983             if (var->type->ref->type == RPC_FC_IP)
2984                 print_phase_function(file, indent, "InterfacePointer", phase, var, start_offset);
2985             else
2986                 print_phase_function(file, indent, "Pointer", phase, var, start_offset);
2987         }
2988     }
2989     fprintf(file, "\n");
2990 }
2991
2992 void write_remoting_arguments(FILE *file, int indent, const func_t *func,
2993                               enum pass pass, enum remoting_phase phase)
2994 {
2995     if (phase == PHASE_BUFFERSIZE && pass != PASS_RETURN)
2996     {
2997         unsigned int size = get_function_buffer_size( func, pass );
2998         print_file(file, indent, "_StubMsg.BufferLength = %u;\n", size);
2999     }
3000
3001     if (pass == PASS_RETURN)
3002     {
3003         var_t var;
3004         var = *func->def;
3005         var.name = xstrdup( "_RetVal" );
3006         write_remoting_arg( file, indent, func, pass, phase, &var );
3007         free( var.name );
3008     }
3009     else
3010     {
3011         const var_t *var;
3012         if (!func->args)
3013             return;
3014         LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
3015             write_remoting_arg( file, indent, func, pass, phase, var );
3016     }
3017 }
3018
3019
3020 size_t get_size_procformatstring_var(const var_t *var)
3021 {
3022     return write_procformatstring_var(NULL, 0, var, FALSE);
3023 }
3024
3025
3026 size_t get_size_procformatstring_func(const func_t *func)
3027 {
3028     const var_t *var;
3029     size_t size = 0;
3030
3031     /* argument list size */
3032     if (func->args)
3033         LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
3034             size += get_size_procformatstring_var(var);
3035
3036     /* return value size */
3037     if (is_void(func->def->type))
3038         size += 2; /* FC_END and FC_PAD */
3039     else
3040         size += get_size_procformatstring_var(func->def);
3041
3042     return size;
3043 }
3044
3045 size_t get_size_procformatstring(const ifref_list_t *ifaces, type_pred_t pred)
3046 {
3047     const ifref_t *iface;
3048     size_t size = 1;
3049     const func_t *func;
3050
3051     if (ifaces) LIST_FOR_EACH_ENTRY( iface, ifaces, const ifref_t, entry )
3052     {
3053         if (!pred(iface->iface))
3054             continue;
3055
3056         if (iface->iface->funcs)
3057             LIST_FOR_EACH_ENTRY( func, iface->iface->funcs, const func_t, entry )
3058                 if (!is_local(func->def->attrs))
3059                     size += get_size_procformatstring_func( func );
3060     }
3061     return size;
3062 }
3063
3064 size_t get_size_typeformatstring(const ifref_list_t *ifaces, type_pred_t pred)
3065 {
3066     set_all_tfswrite(FALSE);
3067     return process_tfs(NULL, ifaces, pred);
3068 }
3069
3070 static void write_struct_expr(FILE *h, const expr_t *e, int brackets,
3071                               const var_list_t *fields, const char *structvar)
3072 {
3073     switch (e->type) {
3074         case EXPR_VOID:
3075             break;
3076         case EXPR_NUM:
3077             fprintf(h, "%lu", e->u.lval);
3078             break;
3079         case EXPR_HEXNUM:
3080             fprintf(h, "0x%lx", e->u.lval);
3081             break;
3082         case EXPR_DOUBLE:
3083             fprintf(h, "%#.15g", e->u.dval);
3084             break;
3085         case EXPR_TRUEFALSE:
3086             if (e->u.lval == 0)
3087                 fprintf(h, "FALSE");
3088             else
3089                 fprintf(h, "TRUE");
3090             break;
3091         case EXPR_IDENTIFIER:
3092         {
3093             const var_t *field;
3094             LIST_FOR_EACH_ENTRY( field, fields, const var_t, entry )
3095                 if (!strcmp(e->u.sval, field->name))
3096                 {
3097                     fprintf(h, "%s->%s", structvar, e->u.sval);
3098                     break;
3099                 }
3100
3101             if (&field->entry == fields) error("no field found for identifier %s\n", e->u.sval);
3102             break;
3103         }
3104         case EXPR_NEG:
3105             fprintf(h, "-");
3106             write_struct_expr(h, e->ref, 1, fields, structvar);
3107             break;
3108         case EXPR_NOT:
3109             fprintf(h, "~");
3110             write_struct_expr(h, e->ref, 1, fields, structvar);
3111             break;
3112         case EXPR_PPTR:
3113             fprintf(h, "*");
3114             write_struct_expr(h, e->ref, 1, fields, structvar);
3115             break;
3116         case EXPR_CAST:
3117             fprintf(h, "(");
3118             write_type_decl(h, e->u.tref, NULL);
3119             fprintf(h, ")");
3120             write_struct_expr(h, e->ref, 1, fields, structvar);
3121             break;
3122         case EXPR_SIZEOF:
3123             fprintf(h, "sizeof(");
3124             write_type_decl(h, e->u.tref, NULL);
3125             fprintf(h, ")");
3126             break;
3127         case EXPR_SHL:
3128         case EXPR_SHR:
3129         case EXPR_MUL:
3130         case EXPR_DIV:
3131         case EXPR_ADD:
3132         case EXPR_SUB:
3133         case EXPR_AND:
3134         case EXPR_OR:
3135             if (brackets) fprintf(h, "(");
3136             write_struct_expr(h, e->ref, 1, fields, structvar);
3137             switch (e->type) {
3138                 case EXPR_SHL: fprintf(h, " << "); break;
3139                 case EXPR_SHR: fprintf(h, " >> "); break;
3140                 case EXPR_MUL: fprintf(h, " * "); break;
3141                 case EXPR_DIV: fprintf(h, " / "); break;
3142                 case EXPR_ADD: fprintf(h, " + "); break;
3143                 case EXPR_SUB: fprintf(h, " - "); break;
3144                 case EXPR_AND: fprintf(h, " & "); break;
3145                 case EXPR_OR:  fprintf(h, " | "); break;
3146                 default: break;
3147             }
3148             write_struct_expr(h, e->u.ext, 1, fields, structvar);
3149             if (brackets) fprintf(h, ")");
3150             break;
3151         case EXPR_COND:
3152             if (brackets) fprintf(h, "(");
3153             write_struct_expr(h, e->ref, 1, fields, structvar);
3154             fprintf(h, " ? ");
3155             write_struct_expr(h, e->u.ext, 1, fields, structvar);
3156             fprintf(h, " : ");
3157             write_struct_expr(h, e->ext2, 1, fields, structvar);
3158             if (brackets) fprintf(h, ")");
3159             break;
3160         case EXPR_ADDRESSOF:
3161             fprintf(h, "&");
3162             write_struct_expr(h, e->ref, 1, fields, structvar);
3163             break;
3164     }
3165 }
3166
3167
3168 void declare_stub_args( FILE *file, int indent, const func_t *func )
3169 {
3170     int in_attr, out_attr;
3171     int i = 0;
3172     const var_t *def = func->def;
3173     const var_t *var;
3174
3175     /* declare return value '_RetVal' */
3176     if (!is_void(def->type))
3177     {
3178         print_file(file, indent, "");
3179         write_type_decl_left(file, def->type);
3180         fprintf(file, " _RetVal;\n");
3181     }
3182
3183     if (!func->args)
3184         return;
3185
3186     LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
3187     {
3188         int is_string = is_attr(var->attrs, ATTR_STRING);
3189
3190         in_attr = is_attr(var->attrs, ATTR_IN);
3191         out_attr = is_attr(var->attrs, ATTR_OUT);
3192         if (!out_attr && !in_attr)
3193             in_attr = 1;
3194
3195         if (is_context_handle(var->type))
3196             print_file(file, indent, "NDR_SCONTEXT %s;\n", var->name);
3197         else
3198         {
3199             if (!in_attr && !var->type->size_is && !is_string)
3200             {
3201                 print_file(file, indent, "");
3202                 write_type_decl(file, var->type->declarray ? var->type : var->type->ref,
3203                                 "_W%u", i++);
3204                 fprintf(file, ";\n");
3205             }
3206
3207             print_file(file, indent, "");
3208             write_type_decl_left(file, var->type);
3209             fprintf(file, " ");
3210             if (var->type->declarray) {
3211                 fprintf(file, "( *");
3212                 write_name(file, var);
3213                 fprintf(file, " )");
3214             } else
3215                 write_name(file, var);
3216             write_type_right(file, var->type, FALSE);
3217             fprintf(file, ";\n");
3218
3219             if (decl_indirect(var->type))
3220                 print_file(file, indent, "void *_p_%s = &%s;\n",
3221                            var->name, var->name);
3222         }
3223     }
3224 }
3225
3226
3227 void assign_stub_out_args( FILE *file, int indent, const func_t *func )
3228 {
3229     int in_attr, out_attr;
3230     int i = 0, sep = 0;
3231     const var_t *var;
3232
3233     if (!func->args)
3234         return;
3235
3236     LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
3237     {
3238         int is_string = is_attr(var->attrs, ATTR_STRING);
3239         in_attr = is_attr(var->attrs, ATTR_IN);
3240         out_attr = is_attr(var->attrs, ATTR_OUT);
3241         if (!out_attr && !in_attr)
3242             in_attr = 1;
3243
3244         if (!in_attr)
3245         {
3246             print_file(file, indent, "");
3247             write_name(file, var);
3248
3249             if (is_context_handle(var->type))
3250             {
3251                 fprintf(file, " = NdrContextHandleInitialize(\n");
3252                 print_file(file, indent + 1, "&_StubMsg,\n");
3253                 print_file(file, indent + 1, "(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%d]);\n",
3254                            var->type->typestring_offset);
3255             }
3256             else if (var->type->size_is)
3257             {
3258                 unsigned int size, align = 0;
3259                 type_t *type = var->type;
3260
3261                 fprintf(file, " = NdrAllocate(&_StubMsg, ");
3262                 for ( ; type->size_is ; type = type->ref)
3263                 {
3264                     write_expr(file, type->size_is, TRUE);
3265                     fprintf(file, " * ");
3266                 }
3267                 size = type_memsize(type, &align);
3268                 fprintf(file, "%u);\n", size);
3269             }
3270             else if (!is_string)
3271             {
3272                 fprintf(file, " = &_W%u;\n", i);
3273                 if (is_ptr(var->type) && !last_ptr(var->type))
3274                     print_file(file, indent, "_W%u = 0;\n", i);
3275                 i++;
3276             }
3277
3278             sep = 1;
3279         }
3280     }
3281     if (sep)
3282         fprintf(file, "\n");
3283 }
3284
3285
3286 int write_expr_eval_routines(FILE *file, const char *iface)
3287 {
3288     static const char *var_name = "pS";
3289     int result = 0;
3290     struct expr_eval_routine *eval;
3291     unsigned short callback_offset = 0;
3292
3293     LIST_FOR_EACH_ENTRY(eval, &expr_eval_routines, struct expr_eval_routine, entry)
3294     {
3295         const char *name = eval->structure->name;
3296         const var_list_t *fields = eval->structure->fields;
3297         result = 1;
3298
3299         print_file(file, 0, "static void __RPC_USER %s_%sExprEval_%04u(PMIDL_STUB_MESSAGE pStubMsg)\n",
3300                    iface, name, callback_offset);
3301         print_file(file, 0, "{\n");
3302         print_file (file, 1, "%s *%s = (%s *)(pStubMsg->StackTop - %u);\n",
3303                     name, var_name, name, eval->baseoff);
3304         print_file(file, 1, "pStubMsg->Offset = 0;\n"); /* FIXME */
3305         print_file(file, 1, "pStubMsg->MaxCount = (unsigned long)");
3306         write_struct_expr(file, eval->expr, 1, fields, var_name);
3307         fprintf(file, ";\n");
3308         print_file(file, 0, "}\n\n");
3309         callback_offset++;
3310     }
3311     return result;
3312 }
3313
3314 void write_expr_eval_routine_list(FILE *file, const char *iface)
3315 {
3316     struct expr_eval_routine *eval;
3317     struct expr_eval_routine *cursor;
3318     unsigned short callback_offset = 0;
3319
3320     fprintf(file, "static const EXPR_EVAL ExprEvalRoutines[] =\n");
3321     fprintf(file, "{\n");
3322
3323     LIST_FOR_EACH_ENTRY_SAFE(eval, cursor, &expr_eval_routines, struct expr_eval_routine, entry)
3324     {
3325         const char *name = eval->structure->name;
3326         print_file(file, 1, "%s_%sExprEval_%04u,\n", iface, name, callback_offset);
3327         callback_offset++;
3328         list_remove(&eval->entry);
3329         free(eval);
3330     }
3331
3332     fprintf(file, "};\n\n");
3333 }
3334
3335 void write_user_quad_list(FILE *file)
3336 {
3337     user_type_t *ut;
3338
3339     if (list_empty(&user_type_list))
3340         return;
3341
3342     fprintf(file, "static const USER_MARSHAL_ROUTINE_QUADRUPLE UserMarshalRoutines[] =\n");
3343     fprintf(file, "{\n");
3344     LIST_FOR_EACH_ENTRY(ut, &user_type_list, user_type_t, entry)
3345     {
3346         const char *sep = &ut->entry == list_tail(&user_type_list) ? "" : ",";
3347         print_file(file, 1, "{\n");
3348         print_file(file, 2, "(USER_MARSHAL_SIZING_ROUTINE)%s_UserSize,\n", ut->name);
3349         print_file(file, 2, "(USER_MARSHAL_MARSHALLING_ROUTINE)%s_UserMarshal,\n", ut->name);
3350         print_file(file, 2, "(USER_MARSHAL_UNMARSHALLING_ROUTINE)%s_UserUnmarshal,\n", ut->name);
3351         print_file(file, 2, "(USER_MARSHAL_FREEING_ROUTINE)%s_UserFree\n", ut->name);
3352         print_file(file, 1, "}%s\n", sep);
3353     }
3354     fprintf(file, "};\n\n");
3355 }
3356
3357 void write_endpoints( FILE *f, const char *prefix, const str_list_t *list )
3358 {
3359     const struct str_list_entry_t *endpoint;
3360     const char *p;
3361
3362     /* this should be an array of RPC_PROTSEQ_ENDPOINT but we want const strings */
3363     print_file( f, 0, "static const unsigned char * %s__RpcProtseqEndpoint[][2] =\n{\n", prefix );
3364     LIST_FOR_EACH_ENTRY( endpoint, list, const struct str_list_entry_t, entry )
3365     {
3366         print_file( f, 1, "{ (const unsigned char *)\"" );
3367         for (p = endpoint->str; *p && *p != ':'; p++)
3368         {
3369             if (*p == '"' || *p == '\\') fputc( '\\', f );
3370             fputc( *p, f );
3371         }
3372         if (!*p) goto error;
3373         if (p[1] != '[') goto error;
3374
3375         fprintf( f, "\", (const unsigned char *)\"" );
3376         for (p += 2; *p && *p != ']'; p++)
3377         {
3378             if (*p == '"' || *p == '\\') fputc( '\\', f );
3379             fputc( *p, f );
3380         }
3381         if (*p != ']') goto error;
3382         fprintf( f, "\" },\n" );
3383     }
3384     print_file( f, 0, "};\n\n" );
3385     return;
3386
3387 error:
3388     error("Invalid endpoint syntax '%s'\n", endpoint->str);
3389 }