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