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