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