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