|
|
1.1 root 1: /*
2: * Mach Operating System
3: * Copyright (c) 1992,1991,1990 Carnegie Mellon University
4: * All Rights Reserved.
5: *
6: * Permission to use, copy, modify and distribute this software and its
7: * documentation is hereby granted, provided that both the copyright
8: * notice and this permission notice appear in all copies of the
9: * software, derivative works or modified versions, and any portions
10: * thereof, and that both notices appear in supporting documentation.
11: *
12: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
13: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15: *
16: * Carnegie Mellon requests users of this software to return to
17: *
18: * Software Distribution Coordinator or [email protected]
19: * School of Computer Science
20: * Carnegie Mellon University
21: * Pittsburgh PA 15213-3890
22: *
23: * any improvements or extensions that they make and grant Carnegie the
24: * rights to redistribute these changes.
25: */
26:
27: #include <assert.h>
28:
29: #include "write.h"
30: #include "error.h"
31: #include "utils.h"
32: #include "global.h"
33: #include "mig_string.h"
34: #include "cpu.h"
35:
36: /*************************************************************
37: * Writes the standard includes. The subsystem specific
38: * includes are in <SubsystemName>.h and writen by
39: * header:WriteHeader. Called by WriteProlog.
40: *************************************************************/
41: static void
42: WriteIncludes(FILE *file)
43: {
44: if (IsKernelServer)
45: {
46: /*
47: * We want to get the user-side definitions of types
48: * like task_t, ipc_space_t, etc. in mach/mach_types.h.
49: */
50:
51: fprintf(file, "#undef\tKERNEL\n");
52:
53: if (InternalHeaderFileName != strNULL)
54: {
55: register char *cp;
56:
57: /* Strip any leading path from InternalHeaderFileName. */
58: cp = strrchr(InternalHeaderFileName, '/');
59: if (cp == 0)
60: cp = InternalHeaderFileName;
61: else
62: cp++; /* skip '/' */
63: fprintf(file, "#include \"%s\"\n", cp);
64: }
65: }
66:
67: if (UserHeaderFileName != strNULL)
68: {
69: register char *cp;
70:
71: /* Strip any leading path from UserHeaderFileName. */
72: cp = strrchr(UserHeaderFileName, '/');
73: if (cp == 0)
74: cp = UserHeaderFileName;
75: else
76: cp++; /* skip '/' */
77: fprintf(file, "#include \"%s\"\n", cp);
78: }
79:
80: fprintf(file, "#define EXPORT_BOOLEAN\n");
81: fprintf(file, "#include <mach/boolean.h>\n");
82: fprintf(file, "#include <mach/kern_return.h>\n");
83: fprintf(file, "#include <mach/message.h>\n");
84: fprintf(file, "#include <mach/notify.h>\n");
85: fprintf(file, "#include <mach/mach_types.h>\n");
86: fprintf(file, "#include <mach/mig_errors.h>\n");
87: fprintf(file, "#include <mach/mig_support.h>\n");
88: fprintf(file, "#include <mach/msg_type.h>\n");
89: fprintf(file, "/* LINTLIBRARY */\n");
90: fprintf(file, "\n");
91: }
92:
93: static void
94: WriteGlobalDecls(FILE *file)
95: {
96: if (RCSId != strNULL)
97: WriteRCSDecl(file, strconcat(SubsystemName, "_user"), RCSId);
98:
99: fprintf(file, "#define msgh_request_port\tmsgh_remote_port\n");
100: fprintf(file, "#define msgh_reply_port\t\tmsgh_local_port\n");
101: fprintf(file, "\n");
102: }
103:
104: /*************************************************************
105: * Writes the standard #includes, #defines, and
106: * RCS declaration. Called by WriteUser.
107: *************************************************************/
108: static void
109: WriteProlog(FILE *file)
110: {
111: WriteIncludes(file);
112: WriteBogusDefines(file);
113: WriteGlobalDecls(file);
114: }
115:
116: /*ARGSUSED*/
117: static void
118: WriteEpilog(FILE *file)
119: {
120: }
121:
122: static const_string_t
123: WriteHeaderPortType(const argument_t *arg)
124: {
125: if (arg->argType->itInName == MACH_MSG_TYPE_POLYMORPHIC)
126: return arg->argPoly->argVarName;
127: else
128: return arg->argType->itInNameStr;
129: }
130:
131: static void
132: WriteRequestHead(FILE *file, const routine_t *rt)
133: {
134: if (rt->rtMaxRequestPos > 0)
135: fprintf(file, "\tInP = &Mess.In;\n");
136:
137: if (rt->rtSimpleFixedRequest) {
138: fprintf(file, "\tInP->Head.msgh_bits =");
139: if (!rt->rtSimpleSendRequest)
140: fprintf(file, " MACH_MSGH_BITS_COMPLEX|");
141: fprintf(file, "\n");
142: fprintf(file, "\t\tMACH_MSGH_BITS(%s, %s);\n",
143: WriteHeaderPortType(rt->rtRequestPort),
144: WriteHeaderPortType(rt->rtUReplyPort));
145: } else {
146: fprintf(file, "\tInP->Head.msgh_bits = msgh_simple ?\n");
147: fprintf(file, "\t\tMACH_MSGH_BITS(%s, %s) :\n",
148: WriteHeaderPortType(rt->rtRequestPort),
149: WriteHeaderPortType(rt->rtUReplyPort));
150: fprintf(file, "\t\t(MACH_MSGH_BITS_COMPLEX|\n");
151: fprintf(file, "\t\t MACH_MSGH_BITS(%s, %s));\n",
152: WriteHeaderPortType(rt->rtRequestPort),
153: WriteHeaderPortType(rt->rtUReplyPort));
154: }
155:
156: fprintf(file, "\t/* msgh_size passed as argument */\n");
157:
158: /*
159: * KernelUser stubs need to cast the request and reply ports
160: * from ipc_port_t to mach_port_t.
161: */
162:
163: if (IsKernelUser)
164: fprintf(file, "\tInP->%s = (mach_port_t) %s;\n",
165: rt->rtRequestPort->argMsgField,
166: rt->rtRequestPort->argVarName);
167: else
168: fprintf(file, "\tInP->%s = %s;\n",
169: rt->rtRequestPort->argMsgField,
170: rt->rtRequestPort->argVarName);
171:
172: if (akCheck(rt->rtUReplyPort->argKind, akbUserArg)) {
173: if (IsKernelUser)
174: fprintf(file, "\tInP->%s = (mach_port_t) %s;\n",
175: rt->rtUReplyPort->argMsgField,
176: rt->rtUReplyPort->argVarName);
177: else
178: fprintf(file, "\tInP->%s = %s;\n",
179: rt->rtUReplyPort->argMsgField,
180: rt->rtUReplyPort->argVarName);
181: } else if (rt->rtOneWay || IsKernelUser)
182: fprintf(file, "\tInP->%s = MACH_PORT_NULL;\n",
183: rt->rtUReplyPort->argMsgField);
184: else
185: fprintf(file, "\tInP->%s = %smig_get_reply_port();\n",
186: rt->rtUReplyPort->argMsgField, SubrPrefix);
187:
188: fprintf(file, "\tInP->Head.msgh_seqno = 0;\n");
189: fprintf(file, "\tInP->Head.msgh_id = %d;\n", rt->rtNumber + SubsystemBase);
190: }
191:
192: /*************************************************************
193: * Writes declarations for the message types, variables
194: * and return variable if needed. Called by WriteRoutine.
195: *************************************************************/
196: static void
197: WriteVarDecls(FILE *file, const routine_t *rt)
198: {
199: fprintf(file, "\tunion {\n");
200: fprintf(file, "\t\tRequest In;\n");
201: if (!rt->rtOneWay)
202: fprintf(file, "\t\tReply Out;\n");
203: fprintf(file, "\t} Mess;\n");
204: fprintf(file, "\n");
205:
206: fprintf(file, "\tregister Request *InP = &Mess.In;\n");
207: if (!rt->rtOneWay)
208: fprintf(file, "\tregister Reply *OutP = &Mess.Out;\n");
209: fprintf(file, "\n");
210:
211: if (!rt->rtOneWay || rt->rtProcedure)
212: fprintf(file, "\tmach_msg_return_t msg_result;\n");
213:
214: if (!rt->rtSimpleFixedRequest)
215: fprintf(file, "\tboolean_t msgh_simple = %s;\n",
216: strbool(rt->rtSimpleSendRequest));
217: else if (!rt->rtOneWay &&
218: !(rt->rtSimpleCheckReply && rt->rtSimpleReceiveReply)) {
219: fprintf(file, "#if\tTypeCheck\n");
220: fprintf(file, "\tboolean_t msgh_simple;\n");
221: fprintf(file, "#endif\t/* TypeCheck */\n");
222: }
223:
224: if (rt->rtNumRequestVar > 0)
225: fprintf(file, "\tunsigned int msgh_size;\n");
226: else if (!rt->rtOneWay && !rt->rtNoReplyArgs)
227: {
228: fprintf(file, "#if\tTypeCheck\n");
229: fprintf(file, "\tunsigned int msgh_size;\n");
230: fprintf(file, "#endif\t/* TypeCheck */\n");
231: }
232:
233: /* if either request or reply is variable, we need msgh_size_delta */
234: if ((rt->rtMaxRequestPos > 0) ||
235: (rt->rtMaxReplyPos > 0))
236: fprintf(file, "\tunsigned int msgh_size_delta;\n");
237:
238: fprintf(file, "\n");
239: }
240:
241: /*************************************************************
242: * Writes code to call the user provided error procedure
243: * when a MIG error occurs. Called by WriteMsgSend,
244: * WriteMsgCheckReceive, WriteMsgSendReceive, WriteCheckIdentity,
245: * WriteRetCodeCheck, WriteTypeCheck, WritePackArgValue.
246: *************************************************************/
247: static void
248: WriteMsgError(FILE *file, const routine_t *rt, const char *error_msg)
249: {
250: if (rt->rtProcedure)
251: fprintf(file, "\t\t{ %s(%s); return; }\n", rt->rtErrorName, error_msg);
252: else if (rt->rtReturn != rt->rtRetCode)
253: {
254: fprintf(file, "\t\t{ %s(%s); ", rt->rtErrorName, error_msg);
255: if (rt->rtNumReplyVar > 0)
256: fprintf(file, "OutP = &Mess.Out; ");
257: fprintf(file, "return OutP->%s; }\n", rt->rtReturn->argMsgField);
258: }
259: else
260: fprintf(file, "\t\treturn %s;\n", error_msg);
261: }
262:
263: /*************************************************************
264: * Writes the send call when there is to be no subsequent
265: * receive. Called by WriteRoutine for SimpleProcedures
266: * or SimpleRoutines
267: *************************************************************/
268: static void
269: WriteMsgSend(FILE *file, const routine_t *rt)
270: {
271: const char *MsgResult = (rt->rtProcedure)
272: ? "msg_result ="
273: : "return";
274:
275: char SendSize[24];
276:
277: if (rt->rtNumRequestVar == 0)
278: sprintf(SendSize, "%d", rt->rtRequestSize);
279: else
280: strcpy(SendSize, "msgh_size");
281:
282: if (IsKernelUser)
283: {
284: fprintf(file, "\t%s %smach_msg_send_from_kernel(",
285: MsgResult, SubrPrefix);
286: fprintf(file, "&InP->Head, %s);\n", SendSize);
287: }
288: else
289: {
290: fprintf(file, "\t%s %smach_msg(&InP->Head, MACH_SEND_MSG|%s, %s, 0,",
291: MsgResult,
292: SubrPrefix,
293: rt->rtMsgOption->argVarName,
294: SendSize);
295: fprintf(file,
296: " MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);\n"
297: );
298: }
299:
300: if (rt->rtProcedure)
301: {
302: fprintf(file, "\tif (msg_result != MACH_MSG_SUCCESS)\n");
303: WriteMsgError(file, rt, "msg_result");
304: }
305: }
306:
307: /*************************************************************
308: * Writes to code to check for error returns from receive.
309: * Called by WriteMsgSendReceive and WriteMsgRPC
310: *************************************************************/
311: static void
312: WriteMsgCheckReceive(FILE *file, const routine_t *rt, const char *success)
313: {
314: fprintf(file, "\tif (msg_result != %s) {\n", success);
315: if (!akCheck(rt->rtUReplyPort->argKind, akbUserArg) && !IsKernelUser)
316: {
317: /* If we aren't using a user-supplied reply port,
318: then deallocate the reply port on any message transmission
319: errors. */
320: fprintf(file, "\t\t%smig_dealloc_reply_port(%s);\n",
321: SubrPrefix, "InP->Head.msgh_reply_port");
322: }
323: WriteMsgError(file, rt, "msg_result");
324: fprintf(file, "\t}\n");
325:
326: /*
327: * If not using a user supplied reply port, tell the port
328: * allocator we're done with the port.
329: */
330: if (!akCheck(rt->rtUReplyPort->argKind, akbUserArg) && !IsKernelUser)
331: {
332: fprintf(file, "\t%smig_put_reply_port(InP->Head.msgh_reply_port);\n",
333: SubrPrefix);
334: }
335: }
336:
337: /*************************************************************
338: * Writes the send and receive calls and code to check
339: * for errors. Normally the rpc code is generated instead
340: * although, the subsytem can be compiled with the -R option
341: * which will cause this code to be generated. Called by
342: * WriteRoutine if UseMsgRPC option is false.
343: *************************************************************/
344: static void
345: WriteMsgSendReceive(FILE *file, const routine_t *rt)
346: {
347: char SendSize[24];
348:
349: if (rt->rtNumRequestVar == 0)
350: sprintf(SendSize, "%d", rt->rtRequestSize);
351: else
352: strcpy(SendSize, "msgh_size");
353:
354: fprintf(file, "\tmsg_result = %smach_msg(&InP->Head, MACH_SEND_MSG|%s, %s, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);\n",
355: SubrPrefix,
356: rt->rtMsgOption->argVarName,
357: SendSize);
358:
359: fprintf(file, "\tif (msg_result != MACH_MSG_SUCCESS)\n");
360: WriteMsgError(file, rt, "msg_result");
361: fprintf(file, "\n");
362:
363: fprintf(file, "\tmsg_result = %smach_msg(&OutP->Head, MACH_RCV_MSG|%s%s, 0, sizeof(Reply), InP->Head.msgh_local_port, %s, MACH_PORT_NULL);\n",
364: SubrPrefix,
365: rt->rtMsgOption->argVarName,
366: rt->rtWaitTime != argNULL ? "|MACH_RCV_TIMEOUT" : "",
367: rt->rtWaitTime != argNULL ? rt->rtWaitTime->argVarName : "MACH_MSG_TIMEOUT_NONE");
368: WriteMsgCheckReceive(file, rt, "MACH_MSG_SUCCESS");
369: fprintf(file, "\n");
370: }
371:
372: /*************************************************************
373: * Writes the rpc call and the code to check for errors.
374: * This is the default code to be generated. Called by WriteRoutine
375: * for all routine types except SimpleProcedure and SimpleRoutine.
376: *************************************************************/
377: static void
378: WriteMsgRPC(FILE *file, const routine_t *rt)
379: {
380: char SendSize[24];
381:
382: if (rt->rtNumRequestVar == 0)
383: sprintf(SendSize, "%d", rt->rtRequestSize);
384: else
385: strcpy(SendSize, "msgh_size");
386:
387: if (IsKernelUser)
388: fprintf(file, "\tmsg_result = %smach_msg_rpc_from_kernel(&InP->Head, %s, sizeof(Reply));\n",
389: SubrPrefix,
390: SendSize);
391: else
392: fprintf(file, "\tmsg_result = %smach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|%s%s, %s, sizeof(Reply), InP->Head.msgh_reply_port, %s, MACH_PORT_NULL);\n",
393: SubrPrefix,
394: rt->rtMsgOption->argVarName,
395: rt->rtWaitTime != argNULL ? "|MACH_RCV_TIMEOUT" : "",
396: SendSize,
397: rt->rtWaitTime != argNULL? rt->rtWaitTime->argVarName : "MACH_MSG_TIMEOUT_NONE");
398: WriteMsgCheckReceive(file, rt, "MACH_MSG_SUCCESS");
399: fprintf(file, "\n");
400: }
401:
402: /*************************************************************
403: * Sets the correct value of the dealloc flag and calls
404: * Utils:WritePackMsgType to fill in the ipc msg type word(s)
405: * in the request message. Called by WriteRoutine for each
406: * argument that is to be sent in the request message.
407: *************************************************************/
408: static void
409: WritePackArgType(FILE *file, const argument_t *arg)
410: {
411: WritePackMsgType(file, arg->argType,
412: arg->argType->itIndefinite ? d_NO : arg->argDeallocate,
413: arg->argLongForm, TRUE,
414: "InP->%s", "%s", arg->argTTName);
415: fprintf(file, "\n");
416: }
417:
418: /*************************************************************
419: * Writes code to copy an argument into the request message.
420: * Called by WriteRoutine for each argument that is to placed
421: * in the request message.
422: *************************************************************/
423: static void
424: WritePackArgValue(FILE *file, register const argument_t *arg)
425: {
426: register const ipc_type_t *it = arg->argType;
427: register const char *ref = arg->argByReferenceUser ? "*" : "";
428:
429: if (it->itInLine && it->itVarArray) {
430:
431: if (it->itString) {
432: /*
433: * Copy variable-size C string with mig_strncpy.
434: * Save the string length (+ 1 for trailing 0)
435: * in the argument`s count field.
436: */
437: fprintf(file,
438: "\tInP->%s = %smig_strncpy(InP->%s, %s, %d);\n",
439: arg->argCount->argMsgField,
440: SubrPrefix,
441: arg->argMsgField,
442: arg->argVarName,
443: it->itNumber);
444: }
445: else {
446:
447: /*
448: * Copy in variable-size inline array with memcpy,
449: * after checking that number of elements doesn`t
450: * exceed declared maximum.
451: */
452: register const argument_t *count = arg->argCount;
453: register const char *countRef = count->argByReferenceUser ? "*" :"";
454: register const ipc_type_t *btype = it->itElement;
455:
456: /* Note btype->itNumber == count->argMultiplier */
457:
458: fprintf(file, "\tif (%s%s > %d) {\n",
459: countRef, count->argVarName,
460: it->itNumber/btype->itNumber);
461: if (it->itIndefinite) {
462: fprintf(file, "\t\tInP->%s%s.msgt_inline = FALSE;\n",
463: arg->argTTName,
464: arg->argLongForm ? ".msgtl_header" : "");
465: if (arg->argDeallocate == d_YES)
466: fprintf(file, "\t\tInP->%s%s.msgt_deallocate = TRUE;\n",
467: arg->argTTName,
468: arg->argLongForm ? ".msgtl_header" : "");
469: else if (arg->argDeallocate == d_MAYBE)
470: fprintf(file, "\t\tInP->%s%s.msgt_deallocate = %s%s;\n",
471: arg->argTTName,
472: arg->argLongForm ? ".msgtl_header" : "",
473: arg->argDealloc->argByReferenceUser ? "*" : "",
474: arg->argDealloc->argVarName);
475: fprintf(file, "\t\t*((%s **)InP->%s) = %s%s;\n",
476: FetchUserType(btype),
477: arg->argMsgField,
478: ref, arg->argVarName);
479: if (!arg->argRoutine->rtSimpleFixedRequest)
480: fprintf(file, "\t\tmsgh_simple = FALSE;\n");
481: }
482: else
483: WriteMsgError(file, arg->argRoutine, "MIG_ARRAY_TOO_LARGE");
484:
485: fprintf(file, "\t}\n\telse {\n");
486:
487: fprintf(file, "\t\tmemcpy(InP->%s, %s%s, ", arg->argMsgField,
488: ref, arg->argVarName);
489: if (btype->itTypeSize > 1)
490: fprintf(file, "%d * ", btype->itTypeSize);
491: fprintf(file, "%s%s);\n",
492: countRef, count->argVarName);
493: fprintf(file, "\t}\n");
494: }
495: }
496: else if (arg->argMultiplier > 1)
497: WriteCopyType(file, it, "InP->%s", "/* %s */ %d * %s%s",
498: arg->argMsgField, arg->argMultiplier,
499: ref, arg->argVarName);
500: else
501: WriteCopyType(file, it, "InP->%s", "/* %s */ %s%s",
502: arg->argMsgField, ref, arg->argVarName);
503: fprintf(file, "\n");
504: }
505:
506: static void
507: WriteAdjustMsgSimple(FILE *file, register const argument_t *arg)
508: {
509: if (!arg->argRoutine->rtSimpleFixedRequest)
510: {
511: register const char *ref = arg->argByReferenceUser ? "*" : "";
512:
513: fprintf(file, "\tif (MACH_MSG_TYPE_PORT_ANY(%s%s))\n",
514: ref, arg->argVarName);
515: fprintf(file, "\t\tmsgh_simple = FALSE;\n");
516: fprintf(file, "\n");
517: }
518: }
519:
520: /*
521: * Calculate the size of a variable-length message field.
522: */
523: static void
524: WriteArgSize(FILE *file, register const argument_t *arg)
525: {
526: register const ipc_type_t *ptype = arg->argType;
527: register int bsize = ptype->itElement->itTypeSize;
528: register const argument_t *count = arg->argCount;
529:
530: if (ptype->itIndefinite) {
531: /*
532: * Check descriptor. If out-of-line, use standard size.
533: */
534: fprintf(file, "(InP->%s%s.msgt_inline) ? ",
535: arg->argTTName, arg->argLongForm ? ".msgtl_header" : "");
536: }
537: if (bsize % 4 != 0)
538: fprintf(file, "(");
539:
540: if (bsize > 1)
541: fprintf(file, "%d * ", bsize);
542:
543: if (ptype->itString)
544: /* get count from descriptor in message */
545: fprintf(file, "InP->%s", count->argMsgField);
546: else
547: /* get count from argument */
548: fprintf(file, "%s%s",
549: count->argByReferenceUser ? "*" : "",
550: count->argVarName);
551:
552: /*
553: * If the base type size is not a multiple of sizeof(int) [4],
554: * we have to round up.
555: */
556: if (bsize % 4 != 0)
557: fprintf(file, " + 3) & ~3");
558:
559: if (ptype->itIndefinite) {
560: fprintf(file, " : sizeof(%s *)",
561: FetchUserType(ptype->itElement));
562: }
563: }
564:
565: /*
566: * Adjust message size and advance request pointer.
567: * Called after packing a variable-length argument that
568: * has more arguments following.
569: */
570: static void
571: WriteAdjustMsgSize(FILE *file, register const argument_t *arg)
572: {
573: register const ipc_type_t *ptype = arg->argType;
574:
575: /* There are more In arguments. We need to adjust msgh_size
576: and advance InP, so we save the size of the current field
577: in msgh_size_delta. */
578:
579: fprintf(file, "\tmsgh_size_delta = ");
580: WriteArgSize(file, arg);
581: fprintf(file, ";\n");
582:
583: if (arg->argRequestPos == 0)
584: /* First variable-length argument. The previous msgh_size value
585: is the minimum request size. */
586:
587: fprintf(file, "\tmsgh_size = %d + msgh_size_delta;\n",
588: arg->argRoutine->rtRequestSize);
589: else
590: fprintf(file, "\tmsgh_size += msgh_size_delta;\n");
591:
592: fprintf(file,
593: "\tInP = (Request *) ((char *) InP + msgh_size_delta - %d);\n",
594: ptype->itTypeSize + ptype->itPadSize);
595: }
596:
597: /*
598: * Calculate the size of the message. Called after the
599: * last argument has been packed.
600: */
601: static void
602: WriteFinishMsgSize(FILE *file, register const argument_t *arg)
603: {
604: /* No more In arguments. If this is the only variable In
605: argument, the previous msgh_size value is the minimum
606: request size. */
607:
608: if (arg->argRequestPos == 0) {
609: fprintf(file, "\tmsgh_size = %d + (",
610: arg->argRoutine->rtRequestSize);
611: WriteArgSize(file, arg);
612: fprintf(file, ");\n");
613: }
614: else {
615: fprintf(file, "\tmsgh_size += ");
616: WriteArgSize(file, arg);
617: fprintf(file, ";\n");
618: }
619: }
620:
621: static void
622: WriteInitializeCount(FILE *file, register const argument_t *arg)
623: {
624: register const ipc_type_t *ptype = arg->argCInOut->argParent->argType;
625: register const ipc_type_t *btype = ptype->itElement;
626:
627: fprintf(file, "\tif (%s%s < %d)\n",
628: arg->argByReferenceUser ? "*" : "",
629: arg->argVarName,
630: ptype->itNumber/btype->itNumber);
631: fprintf(file, "\t\tInP->%s = %s%s;\n",
632: arg->argMsgField,
633: arg->argByReferenceUser ? "*" : "",
634: arg->argVarName);
635: fprintf(file, "\telse\n");
636: fprintf(file, "\t\tInP->%s = %d;\n",
637: arg->argMsgField, ptype->itNumber/btype->itNumber);
638: fprintf(file, "\n");
639: }
640:
641: /*
642: * Called for every argument. Responsible for packing that
643: * argument into the request message.
644: */
645: static void
646: WritePackArg(FILE *file, register const argument_t *arg)
647: {
648: if (akCheck(arg->argKind, akbRequest))
649: WritePackArgType(file, arg);
650:
651: if ((akIdent(arg->argKind) == akePoly) &&
652: akCheckAll(arg->argKind, akbSendSnd|akbUserArg))
653: WriteAdjustMsgSimple(file, arg);
654:
655: if ((akIdent(arg->argKind) == akeCountInOut) &&
656: akCheck(arg->argKind, akbSendSnd))
657: WriteInitializeCount(file, arg);
658: else if (akCheckAll(arg->argKind, akbSendSnd|akbSendBody))
659: WritePackArgValue(file, arg);
660: }
661:
662: /*
663: * Generate code to fill in all of the request arguments and their
664: * message types.
665: */
666: static void
667: WriteRequestArgs(FILE *file, register const routine_t *rt)
668: {
669: register const argument_t *arg;
670: register const argument_t *lastVarArg;
671:
672: lastVarArg = argNULL;
673: for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext)
674: {
675: /*
676: * Adjust message size and advance message pointer if
677: * the last request argument was variable-length and the
678: * request position will change.
679: */
680: if (lastVarArg != argNULL &&
681: lastVarArg->argRequestPos < arg->argRequestPos)
682: {
683: WriteAdjustMsgSize(file, lastVarArg);
684: lastVarArg = argNULL;
685: }
686:
687: /*
688: * Copy the argument
689: */
690: WritePackArg(file, arg);
691:
692: /*
693: * Remember whether this was variable-length.
694: */
695: if (akCheckAll(arg->argKind, akbSendSnd|akbSendBody|akbVariable))
696: lastVarArg = arg;
697: }
698:
699: /*
700: * Finish the message size.
701: */
702: if (lastVarArg != argNULL)
703: WriteFinishMsgSize(file, lastVarArg);
704: }
705:
706: /*************************************************************
707: * Writes code to check that the return msgh_id is correct and that
708: * the size of the return message is correct. Called by
709: * WriteRoutine.
710: *************************************************************/
711: static void
712: WriteCheckIdentity(FILE *file, const routine_t *rt)
713: {
714: fprintf(file, "\tif (OutP->Head.msgh_id != %d) {\n",
715: rt->rtNumber + SubsystemBase + 100);
716: fprintf(file, "\t\tif (OutP->Head.msgh_id == MACH_NOTIFY_SEND_ONCE)\n");
717: WriteMsgError(file, rt, "MIG_SERVER_DIED");
718: fprintf(file, "\t\telse {\n");
719: fprintf(file, "\t\t\t%smig_dealloc_reply_port(%s);\n\t",
720: SubrPrefix,"InP->Head.msgh_reply_port");
721: WriteMsgError(file, rt, "MIG_REPLY_MISMATCH");
722: fprintf(file, "\t\t}\n\t}\n");
723: fprintf(file, "\n");
724: fprintf(file, "#if\tTypeCheck\n");
725:
726: if (rt->rtSimpleCheckReply && rt->rtSimpleReceiveReply)
727: {
728: /* Expecting a simple message. We can factor out the check for
729: a simple message, since the error reply message is also simple.
730: */
731:
732: if (!rt->rtNoReplyArgs)
733: fprintf(file, "\tmsgh_size = OutP->Head.msgh_size;\n\n");
734:
735: fprintf(file,
736: "\tif ((OutP->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) ||\n");
737: if (rt->rtNoReplyArgs)
738: fprintf(file, "\t (OutP->Head.msgh_size != %d))\n",
739: rt->rtReplySize);
740: else {
741: fprintf(file, "\t ((msgh_size %s %d) &&\n",
742: (rt->rtNumReplyVar > 0) ? "<" : "!=",
743: rt->rtReplySize);
744: fprintf(file, "\t ((msgh_size != sizeof(mig_reply_header_t)) ||\n");
745: fprintf(file, "\t (OutP->RetCode == KERN_SUCCESS))))\n");
746: }
747: }
748: else {
749: /* Expecting a complex message, or may vary at run time. */
750:
751: fprintf(file, "\tmsgh_size = OutP->Head.msgh_size;\n");
752: fprintf(file, "\tmsgh_simple = !(OutP->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX);\n");
753: fprintf(file, "\n");
754:
755: fprintf(file, "\tif (((msgh_size %s %d)",
756: (rt->rtNumReplyVar > 0) ? "<" : "!=",
757: rt->rtReplySize);
758:
759: if (rt->rtSimpleCheckReply)
760: /* if rtSimpleReceiveReply was true, then we would have
761: executed the code above. So we know that the message
762: is complex. */
763: fprintf(file, " || msgh_simple");
764: fprintf(file, ") &&\n");
765:
766: fprintf(file, "\t ((msgh_size != sizeof(mig_reply_header_t)) ||\n");
767: fprintf(file, "\t !msgh_simple ||\n");
768: fprintf(file, "\t (OutP->RetCode == KERN_SUCCESS)))\n");
769: }
770: WriteMsgError(file, rt, "MIG_TYPE_ERROR");
771: fprintf(file, "#endif\t/* TypeCheck */\n");
772: fprintf(file, "\n");
773: }
774:
775: /*************************************************************
776: * Write code to generate error handling code if the RetCode
777: * argument of a Routine is not KERN_SUCCESS.
778: *************************************************************/
779: static void
780: WriteRetCodeCheck(FILE *file, const routine_t *rt)
781: {
782: fprintf(file, "\tif (OutP->RetCode != KERN_SUCCESS)\n");
783: WriteMsgError(file, rt, "OutP->RetCode");
784: fprintf(file, "\n");
785: }
786:
787: /*************************************************************
788: * Writes code to check that the type of each of the arguments
789: * in the reply message is what is expected. Called by
790: * WriteRoutine for each argument in the reply message.
791: *************************************************************/
792: static void
793: WriteTypeCheck(FILE *file, register const argument_t *arg)
794: {
795: register const ipc_type_t *it = arg->argType;
796: register const routine_t *rt = arg->argRoutine;
797:
798: fprintf(file, "#if\tTypeCheck\n");
799: if (akCheck(arg->argKind, akbReplyQC))
800: {
801: fprintf(file, "\tif (* (int *) &OutP->%s != * (int *) &%sCheck)\n",
802: arg->argTTName, arg->argVarName);
803: }
804: else
805: {
806: fprintf(file, "\tif (");
807: if (!it->itIndefinite) {
808: fprintf(file, "(OutP->%s%s.msgt_inline != %s) ||\n\t ",
809: arg->argTTName,
810: arg->argLongForm ? ".msgtl_header" : "",
811: strbool(it->itInLine));
812: }
813: fprintf(file, "(OutP->%s%s.msgt_longform != %s) ||\n",
814: arg->argTTName,
815: arg->argLongForm ? ".msgtl_header" : "",
816: strbool(arg->argLongForm));
817: if (it->itOutName == MACH_MSG_TYPE_POLYMORPHIC)
818: {
819: if (!rt->rtSimpleCheckReply)
820: fprintf(file, "\t (MACH_MSG_TYPE_PORT_ANY(OutP->%s.msgt%s_name) && msgh_simple) ||\n",
821: arg->argTTName,
822: arg->argLongForm ? "l" : "");
823: }
824: else
825: fprintf(file, "\t (OutP->%s.msgt%s_name != %s) ||\n",
826: arg->argTTName,
827: arg->argLongForm ? "l" : "",
828: it->itOutNameStr);
829: if (!it->itVarArray)
830: fprintf(file, "\t (OutP->%s.msgt%s_number != %d) ||\n",
831: arg->argTTName,
832: arg->argLongForm ? "l" : "",
833: it->itNumber);
834: fprintf(file, "\t (OutP->%s.msgt%s_size != %d))\n",
835: arg->argTTName,
836: arg->argLongForm ? "l" : "",
837: it->itSize);
838: }
839: WriteMsgError(file, rt, "MIG_TYPE_ERROR");
840: fprintf(file, "#endif\t/* TypeCheck */\n");
841: fprintf(file, "\n");
842: }
843:
844: static void
845: WriteCheckArgSize(FILE *file, register const argument_t *arg)
846: {
847: register const ipc_type_t *ptype = arg->argType;
848: register const ipc_type_t *btype = ptype->itElement;
849: const argument_t *count = arg->argCount;
850: int multiplier = btype->itTypeSize / btype->itNumber;
851:
852: if (ptype->itIndefinite) {
853: /*
854: * Check descriptor. If out-of-line, use standard size.
855: */
856: fprintf(file, "(OutP->%s%s.msgt_inline) ? ",
857: arg->argTTName, arg->argLongForm ? ".msgtl_header" : "");
858: }
859:
860: if (btype->itTypeSize % 4 != 0)
861: fprintf(file, "(");
862:
863: if (multiplier > 1)
864: fprintf(file, "%d * ", multiplier);
865:
866: fprintf(file, "OutP->%s", count->argMsgField);
867:
868: /* If the base type size of the data field isn`t a multiple of 4,
869: we have to round up. */
870: if (btype->itTypeSize % 4 != 0)
871: fprintf(file, " + 3) & ~3");
872:
873: if (ptype->itIndefinite)
874: fprintf(file, " : sizeof(%s *)", FetchUserType(btype));
875: }
876:
877: static void
878: WriteCheckMsgSize(FILE *file, register const argument_t *arg)
879: {
880: register const routine_t *rt = arg->argRoutine;
881:
882: /* If there aren't any more Out args after this, then
883: we can use the msgh_size_delta value directly in
884: the TypeCheck conditional. */
885:
886: if (arg->argReplyPos == rt->rtMaxReplyPos)
887: {
888: fprintf(file, "#if\tTypeCheck\n");
889: fprintf(file, "\tif (msgh_size != %d + (",
890: rt->rtReplySize);
891: WriteCheckArgSize(file, arg);
892: fprintf(file, "))\n");
893:
894: WriteMsgError(file, rt, "MIG_TYPE_ERROR");
895: fprintf(file, "#endif\t/* TypeCheck */\n");
896: }
897: else
898: {
899: /* If there aren't any more variable-sized arguments after this,
900: then we must check for exact msg-size and we don't need
901: to update msgh_size. */
902:
903: boolean_t LastVarArg = arg->argReplyPos+1 == rt->rtNumReplyVar;
904:
905: /* calculate the actual size in bytes of the data field. note
906: that this quantity must be a multiple of four. hence, if
907: the base type size isn't a multiple of four, we have to
908: round up. note also that btype->itNumber must
909: divide btype->itTypeSize (see itCalculateSizeInfo). */
910:
911: fprintf(file, "\tmsgh_size_delta = ");
912: WriteCheckArgSize(file, arg);
913: fprintf(file, ";\n");
914: fprintf(file, "#if\tTypeCheck\n");
915:
916: /* Don't decrement msgh_size until we've checked that
917: it won't underflow. */
918:
919: if (LastVarArg)
920: fprintf(file, "\tif (msgh_size != %d + msgh_size_delta)\n",
921: rt->rtReplySize);
922: else
923: fprintf(file, "\tif (msgh_size < %d + msgh_size_delta)\n",
924: rt->rtReplySize);
925: WriteMsgError(file, rt, "MIG_TYPE_ERROR");
926:
927: if (!LastVarArg)
928: fprintf(file, "\tmsgh_size -= msgh_size_delta;\n");
929:
930: fprintf(file, "#endif\t/* TypeCheck */\n");
931: }
932: fprintf(file, "\n");
933: }
934:
935: /*************************************************************
936: * Write code to copy an argument from the reply message
937: * to the parameter. Called by WriteRoutine for each argument
938: * in the reply message.
939: *************************************************************/
940: static void
941: WriteExtractArgValue(FILE *file, register const argument_t *arg)
942: {
943: register const ipc_type_t *argType = arg->argType;
944: register const char *ref = arg->argByReferenceUser ? "*" : "";
945:
946: if (argType->itInLine && argType->itVarArray) {
947:
948: if (argType->itString) {
949: /*
950: * Copy out variable-size C string with mig_strncpy.
951: */
952: fprintf(file, "\t(void) %smig_strncpy(%s%s, OutP->%s, %d);\n",
953: SubrPrefix,
954: ref,
955: arg->argVarName,
956: arg->argMsgField,
957: argType->itNumber);
958: }
959: else if (argType->itIndefinite) {
960: /*
961: * If data was returned out-of-line,
962: * change user`s pointer to point to it.
963: * If data was returned in-line but doesn`t fit,
964: * allocate a new buffer, copy the data to it,
965: * and change user`s pointer to point to it.
966: * If data was returned in-line and fits,
967: * copy to buffer.
968: */
969: const argument_t *count = arg->argCount;
970: const char *countRef = count->argByReferenceUser ? "*" : "";
971: const ipc_type_t *btype = argType->itElement;
972:
973: fprintf(file, "\tif (!OutP->%s%s.msgt_inline)\n",
974: arg->argTTName,
975: arg->argLongForm ? ".msgtl_header" : "");
976: fprintf(file, "\t %s%s = *((%s **)OutP->%s);\n",
977: ref, arg->argVarName,
978: FetchUserType(btype), arg->argMsgField);
979: fprintf(file, "\telse if (OutP->%s", count->argMsgField);
980: if (btype->itNumber > 1)
981: fprintf(file, " / %d", btype->itNumber);
982: fprintf(file, " > %s%s) {\n", countRef, count->argVarName);
983: fprintf(file, "\t %smig_allocate((vm_offset_t *)%s,\n\t\t",
984: SubrPrefix, arg->argVarName); /* no ref! */
985: if (btype->itTypeSize != btype->itNumber)
986: fprintf(file, "%d * ", btype->itTypeSize/btype->itNumber);
987: fprintf(file, "OutP->%s);\n", count->argMsgField);
988: fprintf(file, "\t memcpy(%s%s, OutP->%s, ", ref, arg->argVarName,
989: arg->argMsgField);
990: if (btype->itTypeSize != btype->itNumber)
991: fprintf(file, "%d * ", btype->itTypeSize/btype->itNumber);
992: fprintf(file, "OutP->%s);\n", count->argMsgField);
993: fprintf(file, "\t}\n");
994: fprintf(file, "\telse {\n");
995:
996: fprintf(file, "\t memcpy(%s%s, OutP->%s, ", ref, arg->argVarName,
997: arg->argMsgField);
998: if (btype->itTypeSize != btype->itNumber)
999: fprintf(file, "%d * ", btype->itTypeSize/btype->itNumber);
1000: fprintf(file, "OutP->%s);\n", count->argMsgField);
1001: fprintf(file, "\t}\n");
1002: }
1003: else {
1004:
1005: /*
1006: * Copy out variable-size inline array with memcpy,
1007: * after checking that number of elements doesn`t
1008: * exceed user`s maximum.
1009: */
1010: register const argument_t *count = arg->argCount;
1011: register const char *countRef = count->argByReferenceUser ? "*" :"";
1012: register const ipc_type_t *btype = argType->itElement;
1013:
1014: /* Note count->argMultiplier == btype->itNumber */
1015:
1016: fprintf(file, "\tif (OutP->%s", count->argMsgField);
1017: if (btype->itNumber > 1)
1018: fprintf(file, " / %d", btype->itNumber);
1019: fprintf(file, " > %s%s) {\n",
1020: countRef, count->argVarName);
1021:
1022: /*
1023: * If number of elements is too many for user receiving area,
1024: * fill user`s area as much as possible. Return the correct
1025: * number of elements.
1026: */
1027: fprintf(file, "\t\tmemcpy(%s%s, OutP->%s, ", ref, arg->argVarName,
1028: arg->argMsgField);
1029: if (btype->itTypeSize > 1)
1030: fprintf(file, "%d * ", btype->itTypeSize);
1031: fprintf(file, "%s%s);\n",
1032: countRef, count->argVarName);
1033:
1034: fprintf(file, "\t\t%s%s = OutP->%s",
1035: countRef, count->argVarName, count->argMsgField);
1036: if (btype->itNumber > 1)
1037: fprintf(file, " / %d", btype->itNumber);
1038: fprintf(file, ";\n");
1039: WriteMsgError(file,arg->argRoutine, "MIG_ARRAY_TOO_LARGE");
1040:
1041: fprintf(file, "\t}\n\telse {\n");
1042:
1043: fprintf(file, "\t\tmemcpy(%s%s, OutP->%s, ", ref, arg->argVarName,
1044: arg->argMsgField);
1045: if (btype->itTypeSize != btype->itNumber)
1046: fprintf(file, "%d * ", btype->itTypeSize/btype->itNumber);
1047: fprintf(file, "OutP->%s);\n", count->argMsgField);
1048: fprintf(file, "\t}\n");
1049: }
1050: }
1051: else if (arg->argMultiplier > 1)
1052: WriteCopyType(file, argType,
1053: "%s%s", "/* %s%s */ OutP->%s / %d",
1054: ref, arg->argVarName, arg->argMsgField,
1055: arg->argMultiplier);
1056: else
1057: WriteCopyType(file, argType,
1058: "%s%s", "/* %s%s */ OutP->%s",
1059: ref, arg->argVarName, arg->argMsgField);
1060: fprintf(file, "\n");
1061: }
1062:
1063: static void
1064: WriteExtractArg(FILE *file, register const argument_t *arg)
1065: {
1066: register const routine_t *rt = arg->argRoutine;
1067:
1068: if (akCheck(arg->argKind, akbReply))
1069: WriteTypeCheck(file, arg);
1070:
1071: if (akCheckAll(arg->argKind, akbVariable|akbReply))
1072: WriteCheckMsgSize(file, arg);
1073:
1074: /* Now that the RetCode is type-checked, check its value.
1075: Must abort immediately if it isn't KERN_SUCCESS, because
1076: in that case the reply message is truncated. */
1077:
1078: if (arg == rt->rtRetCode)
1079: WriteRetCodeCheck(file, rt);
1080:
1081: if (akCheckAll(arg->argKind, akbReturnRcv))
1082: WriteExtractArgValue(file, arg);
1083: }
1084:
1085: static void
1086: WriteAdjustReplyMsgPtr(FILE *file, register const argument_t *arg)
1087: {
1088: register const ipc_type_t *ptype = arg->argType;
1089:
1090: fprintf(file,
1091: "\tOutP = (Reply *) ((char *) OutP + msgh_size_delta - %d);\n\n",
1092: ptype->itTypeSize + ptype->itPadSize);
1093: }
1094:
1095: static void
1096: WriteReplyArgs(FILE *file, register const routine_t *rt)
1097: {
1098: register const argument_t *arg;
1099: register const argument_t *lastVarArg;
1100:
1101: lastVarArg = argNULL;
1102: for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
1103:
1104: /*
1105: * Advance message pointer if the last reply argument was
1106: * variable-length and the reply position will change.
1107: */
1108: if (lastVarArg != argNULL &&
1109: lastVarArg->argReplyPos < arg->argReplyPos)
1110: {
1111: WriteAdjustReplyMsgPtr(file, lastVarArg);
1112: lastVarArg = argNULL;
1113: }
1114:
1115: /*
1116: * Copy the argument
1117: */
1118: WriteExtractArg(file, arg);
1119:
1120: /*
1121: * Remember whether this was variable-length.
1122: */
1123: if (akCheckAll(arg->argKind, akbReturnRcv|akbVariable))
1124: lastVarArg = arg;
1125: }
1126: }
1127:
1128: /*************************************************************
1129: * Writes code to return the return value. Called by WriteRoutine
1130: * for routines and functions.
1131: *************************************************************/
1132: static void
1133: WriteReturnValue(FILE *file, const routine_t *rt)
1134: {
1135: if (rt->rtReturn == rt->rtRetCode)
1136: /* If returning RetCode, we have already checked that it is
1137: KERN_SUCCESS */
1138: fprintf(file, "\treturn KERN_SUCCESS;\n");
1139:
1140: else
1141: {
1142: if (rt->rtNumReplyVar > 0)
1143: fprintf(file, "\tOutP = &Mess.Out;\n");
1144:
1145: fprintf(file, "\treturn OutP->%s;\n", rt->rtReturn->argMsgField);
1146: }
1147: }
1148:
1149: /*************************************************************
1150: * Writes the elements of the message type declaration: the
1151: * msg_type structure, the argument itself and any padding
1152: * that is required to make the argument a multiple of 4 bytes.
1153: * Called by WriteRoutine for all the arguments in the request
1154: * message first and then the reply message.
1155: *************************************************************/
1156: static void
1157: WriteFieldDecl(FILE *file, const argument_t *arg)
1158: {
1159: WriteFieldDeclPrim(file, arg, FetchUserType);
1160: }
1161:
1162: static void
1163: WriteStubDecl(FILE *file, register const routine_t *rt)
1164: {
1165: fprintf(file, "\n");
1166: fprintf(file, "/* %s %s */\n", rtRoutineKindToStr(rt->rtKind), rt->rtName);
1167: fprintf(file, "mig_external %s %s\n", ReturnTypeStr(rt), rt->rtUserName);
1168: fprintf(file, "(\n");
1169: WriteList(file, rt->rtArgs, WriteUserVarDecl, akbUserArg, ",\n", "\n");
1170: fprintf(file, ")\n");
1171: fprintf(file, "{\n");
1172: }
1173:
1174: /*************************************************************
1175: * Writes all the code comprising a routine body. Called by
1176: * WriteUser for each routine.
1177: *************************************************************/
1178: static void
1179: WriteRoutine(FILE *file, register const routine_t *rt)
1180: {
1181: /* write the stub's declaration */
1182:
1183: WriteStubDecl(file, rt);
1184:
1185: /* typedef of structure for Request and Reply messages */
1186:
1187: WriteStructDecl(file, rt->rtArgs, WriteFieldDecl, akbRequest, "Request");
1188: if (!rt->rtOneWay)
1189: WriteStructDecl(file, rt->rtArgs, WriteFieldDecl, akbReply, "Reply");
1190:
1191: /* declarations for local vars: Union of Request and Reply messages,
1192: InP, OutP and return value */
1193:
1194: WriteVarDecls(file, rt);
1195:
1196: /* declarations and initializations of the mach_msg_type_t variables
1197: for each argument */
1198:
1199: WriteList(file, rt->rtArgs, WriteTypeDeclIn, akbRequest, "\n", "\n");
1200: if (!rt->rtOneWay)
1201: WriteList(file, rt->rtArgs, WriteCheckDecl, akbReplyQC, "\n", "\n");
1202:
1203: /* fill in all the request message types and then arguments */
1204:
1205: WriteRequestArgs(file, rt);
1206:
1207: /* fill in request message head */
1208:
1209: WriteRequestHead(file, rt);
1210: fprintf(file, "\n");
1211:
1212: /* Write the send/receive or rpc call */
1213:
1214: if (rt->rtOneWay)
1215: WriteMsgSend(file, rt);
1216: else
1217: {
1218: if (UseMsgRPC)
1219: WriteMsgRPC(file, rt);
1220: else
1221: WriteMsgSendReceive(file, rt);
1222:
1223: /* Check the values that are returned in the reply message */
1224:
1225: WriteCheckIdentity(file, rt);
1226:
1227: /* If the reply message has no Out parameters or return values
1228: other than the return code, we can type-check it and
1229: return it directly. */
1230:
1231: if (rt->rtNoReplyArgs)
1232: {
1233: WriteTypeCheck(file, rt->rtRetCode);
1234:
1235: fprintf(file, "\treturn OutP->RetCode;\n");
1236: }
1237: else {
1238: WriteReplyArgs(file, rt);
1239:
1240: /* return the return value, if any */
1241:
1242: if (rt->rtProcedure)
1243: fprintf(file, "\t/* Procedure - no return needed */\n");
1244: else
1245: WriteReturnValue(file, rt);
1246: }
1247: }
1248:
1249: fprintf(file, "}\n");
1250: }
1251:
1252: /*************************************************************
1253: * Writes out the xxxUser.c file. Called by mig.c
1254: *************************************************************/
1255: void
1256: WriteUser(FILE *file, const statement_t *stats)
1257: {
1258: register const statement_t *stat;
1259:
1260: WriteProlog(file);
1261: for (stat = stats; stat != stNULL; stat = stat->stNext)
1262: switch (stat->stKind)
1263: {
1264: case skRoutine:
1265: WriteRoutine(file, stat->stRoutine);
1266: break;
1267: case skImport:
1268: case skUImport:
1269: WriteImport(file, stat->stFileName);
1270: break;
1271: case skSImport:
1272: break;
1273: default:
1274: fatal("WriteUser(): bad statement_kind_t (%d)",
1275: (int) stat->stKind);
1276: }
1277: WriteEpilog(file);
1278: }
1279:
1280: /*************************************************************
1281: * Writes out individual .c user files for each routine. Called by mig.c
1282: *************************************************************/
1283: void
1284: WriteUserIndividual(const statement_t *stats)
1285: {
1286: register const statement_t *stat;
1287:
1288: for (stat = stats; stat != stNULL; stat = stat->stNext)
1289: switch (stat->stKind)
1290: {
1291: case skRoutine:
1292: {
1293: FILE *file;
1294: register char *filename;
1295:
1296: filename = strconcat(UserFilePrefix,
1297: strconcat(stat->stRoutine->rtName, ".c"));
1298: file = fopen(filename, "w");
1299: if (file == NULL)
1300: fatal("fopen(%s): %s", filename,
1301: unix_error_string(errno));
1302: WriteProlog(file);
1303:
1304: {
1305: /* Write all the imports. */
1306: const statement_t *s;
1307: for (s = stats; s != stNULL; s = s->stNext)
1308: switch (s->stKind)
1309: {
1310: case skImport:
1311: case skUImport:
1312: WriteImport(file, s->stFileName);
1313: break;
1314: }
1315: }
1316:
1317: WriteRoutine(file, stat->stRoutine);
1318: WriteEpilog(file);
1319: fclose(file);
1320: strfree(filename);
1321: }
1322: break;
1323: case skImport:
1324: case skUImport:
1325: break;
1326: case skSImport:
1327: break;
1328: default:
1329: fatal("WriteUserIndividual(): bad statement_kind_t (%d)",
1330: (int) stat->stKind);
1331: }
1332: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.