Annotation of Gnu-Mach/mig/user.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.