1/*
2 * Copyright (c) 1999-2002, 2008 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23/*
24 * Mach Operating System
25 * Copyright (c) 1991,1990 Carnegie Mellon University
26 * All Rights Reserved.
27 *
28 * Permission to use, copy, modify and distribute this software and its
29 * documentation is hereby granted, provided that both the copyright
30 * notice and this permission notice appear in all copies of the
31 * software, derivative works or modified versions, and any portions
32 * thereof, and that both notices appear in supporting documentation.
33 *
34 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
35 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
36 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
37 *
38 * Carnegie Mellon requests users of this software to return to
39 *
40 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
41 *  School of Computer Science
42 *  Carnegie Mellon University
43 *  Pittsburgh PA 15213-3890
44 *
45 * any improvements or extensions that they make and grant Carnegie Mellon
46 * the rights to redistribute these changes.
47 */
48
49#include <mach/message.h>
50#include <stdarg.h>
51#include <stdlib.h>
52#include "routine.h"
53#include "write.h"
54#include "global.h"
55#include "utils.h"
56#include "error.h"
57
58extern char *MessFreeRoutine;
59
60void
61WriteIdentificationString(FILE *file)
62{
63  extern char * GenerationDate;
64
65  fprintf(file, "/*\n");
66  fprintf(file, " * IDENTIFICATION:\n");
67  fprintf(file, " * stub generated %s", GenerationDate);
68  fprintf(file, " * with a MiG generated by " MIG_VERSION "\n");
69  fprintf(file, " * OPTIONS: \n");
70  if (IsKernelUser)
71    fprintf(file, " *\tKernelUser\n");
72  if (IsKernelServer)
73    fprintf(file, " *\tKernelServer\n");
74  if (!UseMsgRPC)
75    fprintf(file, " *\t-R (no RPC calls)\n");
76  fprintf(file, " */\n");
77}
78
79void
80WriteMigExternal(FILE *file)
81{
82  fprintf(file, "#ifdef\tmig_external\n");
83  fprintf(file, "mig_external\n");
84  fprintf(file, "#else\n");
85  fprintf(file, "extern\n");
86  fprintf(file, "#endif\t/* mig_external */\n");
87}
88
89void
90WriteMigInternal(FILE *file)
91{
92  fprintf(file, "#ifdef\tmig_internal\n");
93  fprintf(file, "mig_internal\n");
94  fprintf(file, "#else\n");
95  fprintf(file, "static\n");
96  fprintf(file, "#endif\t/* mig_internal */\n");
97}
98
99void
100WriteImport(FILE *file, string_t filename)
101{
102  fprintf(file, "#include %s\n", filename);
103}
104
105void
106WriteImplImports(FILE *file, statement_t *stats, boolean_t isuser)
107{
108  register statement_t *stat;
109
110  for (stat = stats; stat != stNULL; stat = stat->stNext)
111    switch (stat->stKind) {
112
113      case skImport:
114      case skIImport:
115        WriteImport(file, stat->stFileName);
116        break;
117
118      case skSImport:
119        if (!isuser)
120          WriteImport(file, stat->stFileName);
121        break;
122
123      case skUImport:
124        if (isuser)
125          WriteImport(file, stat->stFileName);
126        break;
127
128      case skRoutine:
129      case skDImport:
130        break;
131
132      default:
133        fatal("WriteImplImport(): bad statement_kind_t (%d)", (int) stat->stKind);
134    }
135}
136
137void
138WriteRCSDecl(FILE *file, identifier_t name, string_t rcs)
139{
140  fprintf(file, "#ifndef\tlint\n");
141  fprintf(file, "#if\tUseExternRCSId\n");
142  fprintf(file, "%s char %s_rcsid[] = %s;\n", (BeAnsiC) ? "const" : "", name, rcs);
143  fprintf(file, "#else\t/* UseExternRCSId */\n");
144  fprintf(file, "static %s char rcsid[] = %s;\n", (BeAnsiC) ? "const" : "", rcs);
145  fprintf(file, "#endif\t/* UseExternRCSId */\n");
146  fprintf(file, "#endif\t/* lint */\n");
147  fprintf(file, "\n");
148}
149
150static void
151WriteOneApplDefault(FILE *file, char *word1, char *word2, char *word3)
152{
153  char buf[50];
154
155  sprintf(buf, "__%s%s%s", word1, word2, word3);
156  fprintf(file, "#ifndef\t%s\n", buf);
157  fprintf(file, "#define\t%s(_NUM_, _NAME_)\n", buf);
158  fprintf(file, "#endif\t/* %s */\n", buf);
159  fprintf(file, "\n");
160}
161
162void
163WriteApplDefaults(FILE *file, char *dir)
164{
165  WriteOneApplDefault(file, "Declare", dir, "Rpc");
166  WriteOneApplDefault(file, "Before", dir, "Rpc");
167  WriteOneApplDefault(file, "After", dir, "Rpc");
168  WriteOneApplDefault(file, "Declare", dir, "Simple");
169  WriteOneApplDefault(file, "Before", dir, "Simple");
170  WriteOneApplDefault(file, "After", dir, "Simple");
171}
172
173void
174WriteApplMacro(FILE *file, char *dir, char *when, routine_t *rt)
175{
176  char *what = (rt->rtOneWay) ? "Simple" : "Rpc";
177
178  fprintf(file, "\t__%s%s%s(%d, \"%s\")\n", when, dir, what, SubsystemBase + rt->rtNumber, rt->rtName);
179}
180
181
182void
183WriteBogusDefines(FILE *file)
184{
185  fprintf(file, "#ifndef\tmig_internal\n");
186  fprintf(file, "#define\tmig_internal\tstatic __inline__\n");
187  fprintf(file, "#endif\t/* mig_internal */\n");
188  fprintf(file, "\n");
189
190  fprintf(file, "#ifndef\tmig_external\n");
191  fprintf(file, "#define mig_external\n");
192  fprintf(file, "#endif\t/* mig_external */\n");
193  fprintf(file, "\n");
194
195  fprintf(file, "#if\t!defined(__MigTypeCheck) && defined(TypeCheck)\n");
196  fprintf(file, "#define\t__MigTypeCheck\t\tTypeCheck\t/* Legacy setting */\n");
197  fprintf(file, "#endif\t/* !defined(__MigTypeCheck) */\n");
198  fprintf(file, "\n");
199
200  fprintf(file, "#if\t!defined(__MigKernelSpecificCode) && defined(_MIG_KERNEL_SPECIFIC_CODE_)\n");
201  fprintf(file, "#define\t__MigKernelSpecificCode\t_MIG_KERNEL_SPECIFIC_CODE_\t/* Legacy setting */\n");
202  fprintf(file, "#endif\t/* !defined(__MigKernelSpecificCode) */\n");
203  fprintf(file, "\n");
204
205  fprintf(file, "#ifndef\tLimitCheck\n");
206  fprintf(file, "#define\tLimitCheck 0\n");
207  fprintf(file, "#endif\t/* LimitCheck */\n");
208  fprintf(file, "\n");
209
210  fprintf(file, "#ifndef\tmin\n");
211  fprintf(file, "#define\tmin(a,b)  ( ((a) < (b))? (a): (b) )\n");
212  fprintf(file, "#endif\t/* min */\n");
213  fprintf(file, "\n");
214
215  fprintf(file, "#if !defined(_WALIGN_)\n");
216  fprintf(file, "#define _WALIGN_(x) (((x) + %d) & ~%d)\n", (int)(itWordAlign - 1), (int)(itWordAlign - 1));
217  fprintf(file, "#endif /* !defined(_WALIGN_) */\n");
218  fprintf(file, "\n");
219
220  fprintf(file, "#if !defined(_WALIGNSZ_)\n");
221  fprintf(file, "#define _WALIGNSZ_(x) _WALIGN_(sizeof(x))\n");
222  fprintf(file, "#endif /* !defined(_WALIGNSZ_) */\n");
223  fprintf(file, "\n");
224
225  fprintf(file, "#ifndef\tUseStaticTemplates\n");
226  if (BeAnsiC) {
227    fprintf(file, "#define\tUseStaticTemplates\t0\n");
228  }
229  else {
230    fprintf(file, "#if\t%s\n", NewCDecl);
231    fprintf(file, "#define\tUseStaticTemplates\t0\n");
232    fprintf(file, "#endif\t/* %s */\n", NewCDecl);
233  }
234  fprintf(file, "#endif\t/* UseStaticTemplates */\n");
235  fprintf(file, "\n");
236
237}
238
239void
240WriteList(FILE *file, argument_t *args, void (*func)(), u_int mask, char *between, char *after)
241{
242  register argument_t *arg;
243  register boolean_t sawone = FALSE;
244
245  for (arg = args; arg != argNULL; arg = arg->argNext)
246    if (akCheckAll(arg->argKind, mask)) {
247      if (sawone)
248        fprintf(file, "%s", between);
249      sawone = TRUE;
250
251      (*func)(file, arg);
252    }
253
254  if (sawone)
255    fprintf(file, "%s", after);
256}
257
258
259static boolean_t
260WriteReverseListPrim(FILE *file, register argument_t *arg, void (*func)(), u_int mask, char *between)
261{
262  boolean_t sawone = FALSE;
263
264  if (arg != argNULL) {
265    sawone = WriteReverseListPrim(file, arg->argNext, func, mask, between);
266
267    if (akCheckAll(arg->argKind, mask)) {
268      if (sawone)
269        fprintf(file, "%s", between);
270      sawone = TRUE;
271
272      (*func)(file, arg);
273    }
274  }
275
276  return sawone;
277}
278
279void
280WriteReverseList(FILE *file, argument_t *args, void (*func)(), u_int mask, char *between, char *after)
281{
282  boolean_t sawone;
283
284  sawone = WriteReverseListPrim(file, args, func, mask, between);
285
286  if (sawone)
287    fprintf(file, "%s", after);
288}
289
290void
291WriteNameDecl(FILE *file, argument_t *arg)
292{
293  fprintf(file, "%s", arg->argVarName);
294}
295
296void
297WriteUserVarDecl(FILE *file, argument_t *arg)
298{
299  boolean_t pointer = (arg->argByReferenceUser ||arg->argType->itNativePointer);
300  char *ref = (pointer) ? "*" : "";
301  char *cnst = ((arg->argFlags & flConst) &&
302                (IS_VARIABLE_SIZED_UNTYPED(arg->argType) ||
303                 arg->argType->itNoOptArray || arg->argType->itString)) ? "const " : "";
304
305  fprintf(file, "\t%s%s %s%s", cnst, arg->argType->itUserType, ref, arg->argVarName);
306}
307
308void
309WriteServerVarDecl(FILE *file, argument_t *arg)
310{
311  char *ref = (arg->argByReferenceServer ||
312               arg->argType->itNativePointer) ? "*" : "";
313  char *cnst = ((arg->argFlags & flConst) &&
314                (IS_VARIABLE_SIZED_UNTYPED(arg->argType) ||
315                 arg->argType->itNoOptArray || arg->argType->itString)) ? "const " : "";
316
317  fprintf(file, "\t%s%s %s%s", cnst, arg->argType->itTransType, ref, arg->argVarName);
318}
319
320char *
321ReturnTypeStr(routine_t *rt)
322{
323  return rt->rtRetCode->argType->itUserType;
324}
325
326char *
327FetchUserType(ipc_type_t *it)
328{
329  return it->itUserType;
330}
331
332char *
333FetchServerType(ipc_type_t *it)
334{
335  return it->itServerType;
336}
337
338char *
339FetchKPDType(ipc_type_t *it)
340{
341  return it->itKPDType;
342}
343
344void
345WriteTrailerDecl(FILE *file, boolean_t trailer)
346{
347  if (trailer)
348    fprintf(file, "\t\tmach_msg_max_trailer_t trailer;\n");
349  else
350    fprintf(file, "\t\tmach_msg_trailer_t trailer;\n");
351}
352
353void
354WriteFieldDeclPrim(FILE *file, argument_t *arg, char *(*tfunc)())
355{
356  register ipc_type_t *it = arg->argType;
357
358  if (IS_VARIABLE_SIZED_UNTYPED(it) || it->itNoOptArray) {
359    register argument_t *count = arg->argCount;
360    register ipc_type_t *btype = it->itElement;
361
362    /*
363     * Build our own declaration for a varying array:
364     * use the element type and maximum size specified.
365     * Note arg->argCount->argMultiplier == btype->itNumber.
366     */
367    /*
368     * NDR encoded VarStrings requires the offset field.
369     * Since it is not used, it wasn't worthwhile to create an extra
370     * parameter
371     */
372    if (it->itString)
373      fprintf(file, "\t\t%s %sOffset; /* MiG doesn't use it */\n", (*tfunc)(count->argType), arg->argName);
374
375    if (!(arg->argFlags & flSameCount) && !it->itNoOptArray)
376    /* in these cases we would have a count, which we don't want */
377      fprintf(file, "\t\t%s %s;\n", (*tfunc)(count->argType), count->argMsgField);
378    fprintf(file, "\t\t%s %s[%d];", (*tfunc)(btype), arg->argMsgField, it->itNumber/btype->itNumber);
379  }
380  else if (IS_MULTIPLE_KPD(it))
381    fprintf(file, "\t\t%s %s[%d];", (*tfunc)(it), arg->argMsgField, it->itKPD_Number);
382  else if (IS_OPTIONAL_NATIVE(it)) {
383    fprintf(file, "\t\tboolean_t __Present__%s;\n",  arg->argMsgField);
384    fprintf(file, "\t\tunion {\n");
385    fprintf(file, "\t\t    %s __Real__%s;\n", (*tfunc)(it), arg->argMsgField);
386    fprintf(file, "\t\t    char __Phony__%s[_WALIGNSZ_(%s)];\n", arg->argMsgField, (*tfunc)(it));
387    fprintf(file, "\t\t} %s;", arg->argMsgField);
388  }
389  else  {
390    /* either simple KPD or simple in-line */
391    fprintf(file, "\t\t%s %s;", (*tfunc)(it), arg->argMsgField);
392  }
393
394  /* Kernel Processed Data has always PadSize = 0 */
395  if (it->itPadSize != 0)
396    fprintf(file, "\n\t\tchar %s[%d];", arg->argPadName, it->itPadSize);
397}
398
399void
400WriteKPDFieldDecl(FILE *file, argument_t *arg)
401{
402  if (akCheck(arg->argKind, akbSendKPD) ||
403      akCheck(arg->argKind, akbReturnKPD))
404    WriteFieldDeclPrim(file, arg, FetchKPDType);
405  else
406    WriteFieldDeclPrim(file, arg, FetchServerType);
407}
408
409void
410WriteStructDecl(
411    FILE *file,
412    argument_t *args,
413    void (*func)(),
414    u_int mask,
415    char *name,
416    boolean_t simple,
417    boolean_t trailer,
418    boolean_t trailer_t,
419    boolean_t template_only)
420{
421  fprintf(file, "\n#ifdef  __MigPackStructs\n#pragma pack(%lu)\n#endif\n",sizeof(natural_t));
422  fprintf(file, "\ttypedef struct {\n");
423  fprintf(file, "\t\tmach_msg_header_t Head;\n");
424  if (simple == FALSE) {
425    fprintf(file, "\t\t/* start of the kernel processed data */\n");
426    fprintf(file, "\t\tmach_msg_body_t msgh_body;\n");
427    if (mask == akbRequest)
428      WriteList(file, args, func, mask | akbSendKPD, "\n", "\n");
429    else
430      WriteList(file, args, func, mask | akbReturnKPD, "\n", "\n");
431    fprintf(file, "\t\t/* end of the kernel processed data */\n");
432  }
433  if (!template_only) {
434    if (mask == akbRequest)
435      WriteList(file, args, func, mask | akbSendBody, "\n", "\n");
436
437    else
438      WriteList(file, args, func, mask | akbReturnBody, "\n", "\n");
439    if (trailer)
440      WriteTrailerDecl(file, trailer_t);
441  }
442  fprintf(file, "\t} %s;\n", name);
443  fprintf(file, "#ifdef  __MigPackStructs\n#pragma pack()\n#endif\n");
444}
445
446void
447WriteTemplateDeclIn(FILE *file, register argument_t *arg)
448{
449  (*arg->argKPD_Template)(file, arg, TRUE);
450}
451
452void
453WriteTemplateDeclOut(FILE *file, register argument_t *arg)
454{
455  (*arg->argKPD_Template)(file, arg, FALSE);
456}
457
458void
459WriteTemplateKPD_port(FILE *file, argument_t *arg, boolean_t in)
460{
461  register ipc_type_t *it = arg->argType;
462
463  fprintf(file, "#if\tUseStaticTemplates\n");
464  fprintf(file, "\tconst static %s %s = {\n", it->itKPDType, arg->argTTName);
465
466  fprintf(file, "\t\t/* name = */\t\tMACH_PORT_NULL,\n");
467  fprintf(file, "\t\t/* pad1 = */\t\t0,\n");
468  fprintf(file, "\t\t/* pad2 = */\t\t0,\n");
469  fprintf(file, "\t\t/* disp = */\t\t%s,\n", in ? it->itInNameStr: it->itOutNameStr);
470  fprintf(file, "\t\t/* type = */\t\tMACH_MSG_PORT_DESCRIPTOR,\n");
471
472  fprintf(file, "\t};\n");
473  fprintf(file, "#endif\t/* UseStaticTemplates */\n");
474}
475
476void
477WriteTemplateKPD_ool(FILE *file, argument_t *arg, boolean_t in)
478{
479  register ipc_type_t *it = arg->argType;
480
481  fprintf(file, "#if\tUseStaticTemplates\n");
482  fprintf(file, "\tconst static %s %s = {\n", it->itKPDType, arg->argTTName);
483
484  if (IS_MULTIPLE_KPD(it))
485    it = it->itElement;
486
487  fprintf(file, "\t\t/* addr = */\t\t(void *)0,\n");
488  if (it->itVarArray)
489    fprintf(file, "\t\t/* size = */\t\t0,\n");
490  else
491    fprintf(file, "\t\t/* size = */\t\t%d,\n", (it->itNumber * it->itSize + 7)/8);
492  fprintf(file, "\t\t/* deal = */\t\t%s,\n", (arg->argDeallocate == d_YES) ? "TRUE" : "FALSE");
493  /* the d_MAYBE case will be fixed runtime */
494  fprintf(file, "\t\t/* copy = */\t\t%s,\n", (arg->argFlags & flPhysicalCopy) ? "MACH_MSG_PHYSICAL_COPY" : "MACH_MSG_VIRTUAL_COPY");
495  /* the PHYSICAL COPY flag has not been established yet */
496  fprintf(file, "\t\t/* pad2 = */\t\t0,\n");
497  fprintf(file, "\t\t/* type = */\t\tMACH_MSG_OOL_DESCRIPTOR,\n");
498
499  fprintf(file, "\t};\n");
500  fprintf(file, "#endif\t/* UseStaticTemplates */\n");
501}
502
503void
504WriteTemplateKPD_oolport(FILE *file, argument_t *arg, boolean_t in)
505{
506  register ipc_type_t *it = arg->argType;
507
508  fprintf(file, "#if\tUseStaticTemplates\n");
509  fprintf(file, "\tconst static %s %s = {\n", it->itKPDType, arg->argTTName);
510
511  if (IS_MULTIPLE_KPD(it))
512    it = it->itElement;
513
514  fprintf(file, "\t\t/* addr = */\t\t(void *)0,\n");
515  if (!it->itVarArray)
516    fprintf(file, "\t\t/* coun = */\t\t%d,\n", it->itNumber);
517  else
518    fprintf(file, "\t\t/* coun = */\t\t0,\n");
519  fprintf(file, "\t\t/* deal = */\t\t%s,\n", (arg->argDeallocate == d_YES) ? "TRUE" : "FALSE");
520  fprintf(file, "\t\t/* copy is meaningful only in overwrite mode */\n");
521  fprintf(file, "\t\t/* copy = */\t\tMACH_MSG_PHYSICAL_COPY,\n");
522  fprintf(file, "\t\t/* disp = */\t\t%s,\n", in ? it->itInNameStr: it->itOutNameStr);
523  fprintf(file, "\t\t/* type = */\t\tMACH_MSG_OOL_PORTS_DESCRIPTOR,\n");
524
525  fprintf(file, "\t};\n");
526  fprintf(file, "#endif\t/* UseStaticTemplates */\n");
527}
528
529void
530WriteReplyTypes(FILE *file, statement_t *stats)
531{
532  register statement_t *stat;
533
534  fprintf(file, "/* typedefs for all replies */\n\n");
535  fprintf(file, "#ifndef __Reply__%s_subsystem__defined\n", SubsystemName);
536  fprintf(file, "#define __Reply__%s_subsystem__defined\n", SubsystemName);
537  for (stat = stats; stat != stNULL; stat = stat->stNext) {
538    if (stat->stKind == skRoutine) {
539      register routine_t *rt;
540      char str[MAX_STR_LEN];
541
542      rt = stat->stRoutine;
543      sprintf(str, "__Reply__%s_t", rt->rtName);
544      WriteStructDecl(file, rt->rtArgs, WriteKPDFieldDecl, akbReply, str, rt->rtSimpleReply, FALSE, FALSE, FALSE);
545    }
546  }
547  fprintf(file, "#endif /* !__Reply__%s_subsystem__defined */\n", SubsystemName);
548  fprintf(file, "\n");
549}
550
551void
552WriteRequestTypes(FILE *file, statement_t *stats)
553{
554  register statement_t *stat;
555
556  fprintf(file, "/* typedefs for all requests */\n\n");
557  fprintf(file, "#ifndef __Request__%s_subsystem__defined\n", SubsystemName);
558  fprintf(file, "#define __Request__%s_subsystem__defined\n", SubsystemName);
559  for (stat = stats; stat != stNULL; stat = stat->stNext) {
560    if (stat->stKind == skRoutine) {
561      register routine_t *rt;
562      char str[MAX_STR_LEN];
563
564      rt = stat->stRoutine;
565      sprintf(str, "__Request__%s_t", rt->rtName);
566      WriteStructDecl(file, rt->rtArgs, WriteKPDFieldDecl, akbRequest, str, rt->rtSimpleRequest, FALSE, FALSE, FALSE);
567    }
568  }
569  fprintf(file, "#endif /* !__Request__%s_subsystem__defined */\n", SubsystemName);
570  fprintf(file, "\n");
571}
572
573void
574WriteNDRConvertArgDecl(FILE *file, argument_t *arg, char *convert, char *dir)
575{
576  argument_t *count = arg->argCount;
577  argument_t *parent = arg->argParent;
578  char *carg = (count) ? ", c" : "";
579  routine_t *rt = arg->argRoutine;
580  ipc_type_t *ptype = arg->argType;
581  ipc_type_t *btype;
582  int multi, array;
583  char domain[MAX_STR_LEN];
584
585  fprintf(file, "#ifndef __NDR_convert__%s__%s__%s_t__%s__defined\n#", convert, dir, rt->rtName, arg->argMsgField);
586
587  for (btype = ptype, multi = (!parent) ? arg->argMultiplier : 1, array = 0;
588       btype;
589       ptype = btype, array += ptype->itVarArray, btype = btype->itElement) {
590    char *bttype;
591
592    if (btype->itNumber < ptype->itNumber && !ptype->itVarArray && !parent) {
593      multi *= ptype->itNumber / btype->itNumber;
594      if (!btype->itString)
595        continue;
596    }
597    else if (array && ptype->itVarArray)
598      continue;
599    if (btype != ptype)
600      fprintf(file, "#el");
601
602    bttype = (multi > 1 && btype->itString) ? "string" : FetchServerType(btype);
603    sprintf(domain, "__%s", SubsystemName);
604    do {
605      fprintf(file, "if\tdefined(__NDR_convert__%s%s__%s__defined)\n", convert, domain, bttype);
606      fprintf(file, "#define\t__NDR_convert__%s__%s__%s_t__%s__defined\n", convert, dir, rt->rtName, arg->argMsgField);
607      fprintf(file, "#define\t__NDR_convert__%s__%s__%s_t__%s(a, f%s) \\\n\t", convert, dir, rt->rtName, arg->argMsgField, carg);
608      if (multi > 1) {
609        if (array) {
610          if (btype->itString)
611            fprintf(file, "__NDR_convert__2DARRAY((%s *)(a), f, %d, c, ", bttype, multi);
612          else
613            fprintf(file, "__NDR_convert__ARRAY((%s *)(a), f, %d * (c), ", bttype, multi);
614        }
615        else if (!btype->itString)
616          fprintf(file, "__NDR_convert__ARRAY((%s *)(a), f, %d, ", bttype, multi);
617      }
618      else if (array)
619        fprintf(file, "__NDR_convert__ARRAY((%s *)(a), f, c, ", bttype);
620      fprintf(file, "__NDR_convert__%s%s__%s", convert, domain, bttype);
621      if (multi > 1) {
622        if (!array && btype->itString)
623          fprintf(file, "(a, f, %d", multi);
624      }
625      else if (!array)
626        fprintf(file, "((%s *)(a), f%s", bttype, carg);
627      fprintf(file, ")\n");
628    } while (strcmp(domain, "") && (domain[0] = '\0', fprintf(file, "#el")));
629  }
630  fprintf(file, "#endif /* defined(__NDR_convert__*__defined) */\n");
631  fprintf(file, "#endif /* __NDR_convert__%s__%s__%s_t__%s__defined */\n\n", convert, dir, rt->rtName, arg->argMsgField);
632}
633
634/*
635 * Like vfprintf, but omits a leading comment in the format string
636 * and skips the items that would be printed by it.  Only %s, %d,
637 * and %f are recognized.
638 */
639void
640SkipVFPrintf(FILE *file, register char *fmt, va_list pvar)
641{
642  if (*fmt == 0)
643    return; /* degenerate case */
644
645  if (fmt[0] == '/' && fmt[1] == '*') {
646    /* Format string begins with C comment.  Scan format
647       string until end-comment delimiter, skipping the
648       items in pvar that the enclosed format items would
649       print. */
650
651    register int c;
652
653    fmt += 2;
654    for (;;) {
655      c = *fmt++;
656      if (c == 0)
657        return; /* nothing to format */
658      if (c == '*') {
659        if (*fmt == '/') {
660          break;
661        }
662      }
663      else if (c == '%') {
664        /* Field to skip */
665        c = *fmt++;
666        switch (c) {
667
668          case 's':
669            (void) va_arg(pvar, char *);
670            break;
671
672          case 'd':
673            (void) va_arg(pvar, int);
674            break;
675
676          case 'f':
677            (void) va_arg(pvar, double);
678            break;
679
680          case '\0':
681            return; /* error - fmt ends with '%' */
682
683          default:
684            break;
685        }
686      }
687    }
688    /* End of comment.  To be pretty, skip
689     the space that follows. */
690    fmt++;
691    if (*fmt == ' ')
692      fmt++;
693  }
694
695  /* Now format the string. */
696  (void) vfprintf(file, fmt, pvar);
697}
698
699static void
700vWriteCopyType(FILE *file, ipc_type_t *it, char *left, char *right, va_list pvar)
701{
702  va_list pvar2;
703  va_copy(pvar2, pvar);
704
705  if (it->itStruct) {
706
707    fprintf(file, "\t");
708    (void) SkipVFPrintf(file, left, pvar);
709    fprintf(file, " = ");
710    (void) SkipVFPrintf(file, right, pvar2);
711    fprintf(file, ";\n");
712  }
713  else if (it->itString) {
714    fprintf(file, "\t(void) mig_strncpy(");
715    (void) SkipVFPrintf(file, left, pvar);
716    fprintf(file, ", ");
717    (void) SkipVFPrintf(file, right, pvar2);
718    fprintf(file, ", %d);\n", it->itTypeSize);
719  }
720  else {
721    fprintf(file, "\t{   typedef struct { char data[%d]; } *sp;\n", it->itTypeSize);
722    fprintf(file, "\t    * (sp) ");
723    (void) SkipVFPrintf(file, left, pvar);
724    fprintf(file, " = * (sp) ");
725    (void) SkipVFPrintf(file, right, pvar2);
726    fprintf(file, ";\n\t}\n");
727  }
728
729  va_end(pvar2);
730}
731
732
733/*ARGSUSED*/
734/*VARARGS4*/
735void
736WriteCopyType(FILE *file, ipc_type_t *it, char *left, char *right, ...)
737{
738  va_list pvar;
739  va_start(pvar, right);
740
741  vWriteCopyType(file, it, left, right, pvar);
742
743  va_end(pvar);
744}
745
746
747/*ARGSUSED*/
748/*VARARGS4*/
749void
750WriteCopyArg(FILE *file, argument_t *arg, char *left, char *right, ...)
751{
752  va_list pvar;
753  va_start(pvar, right);
754
755  {
756    ipc_type_t *it = arg->argType;
757    if (it->itVarArray && !it->itString) {
758      fprintf(file, "\t    (void)memcpy(");
759      (void) SkipVFPrintf(file, left, pvar);
760      va_end(pvar);
761      fprintf(file, ", ");
762      va_start(pvar, right);
763      (void) SkipVFPrintf(file, right, pvar);
764      fprintf(file, ", %s);\n", arg->argCount->argVarName);
765    }
766    else
767      vWriteCopyType(file, it, left, right, pvar);
768  }
769
770  va_end(pvar);
771}
772
773
774/*
775 * Global KPD disciplines
776 */
777void
778KPD_error(FILE *file, argument_t *arg)
779{
780  printf("MiG internal error: argument is %s\n", arg->argVarName);
781  exit(1);
782}
783
784void
785KPD_noop(FILE *file, argument_t *arg)
786{
787  /* Nothing to see here, people. Move it along... */
788}
789
790static void
791WriteStringDynArgs(argument_t *args, u_int mask, string_t InPOutP, string_t *str_oolports, string_t *str_ool)
792{
793  argument_t *arg;
794  char loc[100], sub[20];
795  string_t tmp_str1 = "";
796  string_t tmp_str2 = "";
797  int cnt, multiplier = 1;
798  boolean_t test, complex = FALSE;
799
800  for (arg = args; arg != argNULL; arg = arg->argNext) {
801    ipc_type_t *it = arg->argType;
802
803    if (IS_MULTIPLE_KPD(it)) {
804      test = it->itVarArray || it->itElement->itVarArray;
805      if (test) {
806        multiplier = it->itKPD_Number;
807        it = it->itElement;
808        complex = TRUE;
809      }
810    }
811    else
812      test = it->itVarArray;
813
814    cnt = multiplier;
815    while (cnt) {
816      if (complex)
817        sprintf(sub, "[%d]", multiplier - cnt);
818      if (akCheck(arg->argKind, mask) &&
819          it->itPortType && !it->itInLine && test) {
820        sprintf(loc, " + %s->%s%s.count", InPOutP, arg->argMsgField, complex ? sub : "");
821        tmp_str1 = strconcat(tmp_str1, loc);
822      }
823      if (akCheck(arg->argKind, mask) &&
824          !it->itInLine && !it->itPortType && test) {
825        sprintf(loc, " + %s->%s%s.size", InPOutP, arg->argMsgField, complex ? sub : "");
826        tmp_str2 = strconcat(tmp_str2, loc);
827      }
828      cnt--;
829    }
830  }
831  *str_oolports = tmp_str1;
832  *str_ool = tmp_str2;
833}
834
835/*
836 * Utilities for Logging Events that happen at the stub level
837 */
838void
839WriteLogMsg(FILE *file, routine_t *rt, int where, int what)
840{
841  string_t ptr_str;
842  string_t StringOolPorts = strNULL;
843  string_t StringOOL = strNULL;
844  u_int ports, oolports, ool;
845  string_t event;
846
847  fprintf(file, "\n#if  MIG_DEBUG\n");
848  if (where == LOG_USER)
849    fprintf(file, "\tLOG_TRACE(MACH_MSG_LOG_USER,\n");
850  else
851    fprintf(file, "\tLOG_TRACE(MACH_MSG_LOG_SERVER,\n");
852  if (where == LOG_USER && what == LOG_REQUEST) {
853    ptr_str = "InP";
854    event = "MACH_MSG_REQUEST_BEING_SENT";
855  }
856  else if (where == LOG_USER && what == LOG_REPLY) {
857    ptr_str = "Out0P";
858    event = "MACH_MSG_REPLY_BEING_RCVD";
859  }
860  else if (where == LOG_SERVER && what == LOG_REQUEST) {
861    ptr_str = "In0P";
862    event = "MACH_MSG_REQUEST_BEING_RCVD";
863  }
864  else {
865    ptr_str = "OutP";
866    event = "MACH_MSG_REPLY_BEING_SENT";
867  }
868  WriteStringDynArgs(rt->rtArgs, (what == LOG_REQUEST) ? akbSendKPD : akbReturnKPD, ptr_str, &StringOolPorts, &StringOOL);
869  fprintf(file, "\t\t%s,\n", event);
870  fprintf(file, "\t\t%s->Head.msgh_id,\n", ptr_str);
871  if (where == LOG_USER && what == LOG_REQUEST) {
872    if (rt->rtNumRequestVar)
873      fprintf(file, "\t\tmsgh_size,\n");
874    else
875      fprintf(file, "\t\t(mach_msg_size_t)sizeof(Request),\n");
876  }
877  else
878    fprintf(file, "\t\t%s->Head.msgh_size,\n", ptr_str);
879  if ((what == LOG_REQUEST && rt->rtSimpleRequest == FALSE) ||
880      (what == LOG_REPLY && rt->rtSimpleReply == FALSE))
881    fprintf(file, "\t\t%s->msgh_body.msgh_descriptor_count,\n", ptr_str);
882  else
883    fprintf(file, "\t\t0, /* Kernel Proc. Data entries */\n");
884  if (what == LOG_REQUEST) {
885    fprintf(file, "\t\t0, /* RetCode */\n");
886    ports = rt->rtCountPortsIn;
887    oolports = rt->rtCountOolPortsIn;
888    ool = rt->rtCountOolIn;
889  }
890  else {
891    if (akCheck(rt->rtRetCode->argKind, akbReply))
892      fprintf(file, "\t\t%s->RetCode,\n", ptr_str);
893    else
894      fprintf(file, "\t\t0, /* RetCode */\n");
895    ports = rt->rtCountPortsOut;
896    oolports = rt->rtCountOolPortsOut;
897    ool = rt->rtCountOolOut;
898  }
899  fprintf(file, "\t\t/* Ports */\n");
900  fprintf(file, "\t\t%d,\n", ports);
901  fprintf(file, "\t\t/* Out-of-Line Ports */\n");
902  fprintf(file, "\t\t%d", oolports);
903  if (StringOolPorts != strNULL)
904    fprintf(file, "%s,\n", StringOolPorts);
905  else
906    fprintf(file, ",\n");
907  fprintf(file, "\t\t/* Out-of-Line Bytes */\n");
908  fprintf(file, "\t\t%d", ool);
909  if (StringOOL != strNULL)
910    fprintf(file, "%s,\n", StringOOL);
911  else
912    fprintf(file, ",\n");
913  fprintf(file, "\t\t__FILE__, __LINE__);\n");
914  fprintf(file, "#endif /* MIG_DEBUG */\n\n");
915}
916
917void
918WriteLogDefines(FILE *file, string_t who)
919{
920  fprintf(file, "#if  MIG_DEBUG\n");
921  fprintf(file, "#define LOG_W_E(X)\tLOG_ERRORS(%s, \\\n", who);
922  fprintf(file, "\t\t\tMACH_MSG_ERROR_WHILE_PARSING, (void *)(X), __FILE__, __LINE__)\n");
923  fprintf(file, "#else  /* MIG_DEBUG */\n");
924  fprintf(file, "#define LOG_W_E(X)\n");
925  fprintf(file, "#endif /* MIG_DEBUG */\n");
926  fprintf(file, "\n");
927}
928
929/* common utility to report errors */
930void
931WriteReturnMsgError(FILE *file, routine_t *rt, boolean_t isuser, argument_t *arg, string_t error)
932{
933  char space[MAX_STR_LEN];
934  string_t string = &space[0];
935
936  if (UseEventLogger && arg != argNULL)
937    sprintf(string, "LOG_W_E(\"%s\"); ", arg->argVarName);
938  else
939    string = "";
940
941  fprintf(file, "\t\t{ ");
942
943  if (isuser) {
944    if (! rtMessOnStack(rt))
945      fprintf(file, "%s((char *) Mess, (mach_msg_size_t)sizeof(*Mess)); ", MessFreeRoutine);
946
947    fprintf(file, "%sreturn %s; }\n", string, error);
948  }
949  else
950    fprintf(file, "%sMIG_RETURN_ERROR(OutP, %s); }\n", string, error);
951}
952
953/* executed iff elements are defined */
954void
955WriteCheckTrailerHead(FILE *file, routine_t *rt, boolean_t isuser)
956{
957  string_t who = (isuser) ? "Out0P" : "In0P";
958
959  fprintf(file, "\tTrailerP = (mach_msg_max_trailer_t *)((vm_offset_t)%s +\n", who);
960  fprintf(file, "\t\tround_msg(%s->Head.msgh_size));\n", who);
961  fprintf(file, "\tif (TrailerP->msgh_trailer_type != MACH_MSG_TRAILER_FORMAT_0)\n");
962  if (isuser)
963    fprintf(file, "\t\t{ return MIG_TRAILER_ERROR ; }\n");
964  else
965    fprintf(file, "\t\t{ MIG_RETURN_ERROR(%s, MIG_TRAILER_ERROR); }\n", who);
966
967  fprintf(file, "#if\t__MigTypeCheck\n");
968  fprintf(file, "\ttrailer_size = TrailerP->msgh_trailer_size -\n");
969  fprintf(file, "\t\t(mach_msg_size_t)(sizeof(mach_msg_trailer_type_t) - sizeof(mach_msg_trailer_size_t));\n");
970  fprintf(file, "#endif\t/* __MigTypeCheck */\n");
971}
972
973/* executed iff elements are defined */
974void
975WriteCheckTrailerSize(FILE *file, boolean_t isuser, register argument_t *arg)
976{
977  fprintf(file, "#if\t__MigTypeCheck\n");
978  if (akIdent(arg->argKind) == akeMsgSeqno) {
979    fprintf(file, "\tif (trailer_size < (mach_msg_size_t)sizeof(mach_port_seqno_t))\n");
980    if (isuser)
981      fprintf(file, "\t\t{ return MIG_TRAILER_ERROR ; }\n");
982    else
983      fprintf(file, "\t\t{ MIG_RETURN_ERROR(OutP, MIG_TRAILER_ERROR); }\n");
984    fprintf(file, "\ttrailer_size -= (mach_msg_size_t)sizeof(mach_port_seqno_t);\n");
985  }
986  else if (akIdent(arg->argKind) == akeSecToken) {
987    fprintf(file, "\tif (trailer_size < (mach_msg_size_t)sizeof(security_token_t))\n");
988    if (isuser)
989      fprintf(file, "\t\t{ return MIG_TRAILER_ERROR ; }\n");
990    else
991      fprintf(file, "\t\t{ MIG_RETURN_ERROR(OutP, MIG_TRAILER_ERROR); }\n");
992    fprintf(file, "\ttrailer_size -= (mach_msg_size_t)sizeof(security_token_t);\n");
993  }
994  else if (akIdent(arg->argKind) == akeAuditToken) {
995    fprintf(file, "\tif (trailer_size < (mach_msg_size_t)sizeof(audit_token_t))\n");
996    if (isuser)
997      fprintf(file, "\t\t{ return MIG_TRAILER_ERROR ; }\n");
998    else
999      fprintf(file, "\t\t{ MIG_RETURN_ERROR(OutP, MIG_TRAILER_ERROR); }\n");
1000    fprintf(file, "\ttrailer_size -= (mach_msg_size_t)sizeof(audit_token_t);\n");
1001  }
1002  else if (akIdent(arg->argKind) == akeContextToken) {
1003    fprintf(file, "\tif (trailer_size < (mach_msg_size_t)sizeof(mach_vm_address_t))\n");
1004    if (isuser)
1005      fprintf(file, "\t\t{ return MIG_TRAILER_ERROR ; }\n");
1006    else
1007      fprintf(file, "\t\t{ MIG_RETURN_ERROR(OutP, MIG_TRAILER_ERROR); }\n");
1008    fprintf(file, "\ttrailer_size -= (mach_msg_size_t)sizeof(mach_vm_address_t);\n");
1009  }
1010  fprintf(file, "#endif\t/* __MigTypeCheck */\n");
1011}
1012
1013