/* * The Unix Channel * * by Michel Beaudouin-Lafon * * Copyright 1993-1995 * Centre d'Etudes de la Navigation Aerienne (CENA) * * Request management, by Stephane Chatty * * $Id$ * $CurLog$ */ #include "ReqMgr.h" #include #include #include #include UchMsgMgr :: UchMsgMgr () : Name () { } UchMsgMgr :: ~UchMsgMgr () { } void UchMsgMgr :: SetName (const char* n) { if (Name) fprintf (stderr, "service type already set to %s\n", (const char*) Name); else Name = n; } void UchMsgMgr :: DumpEnum (ofstream& f, MsgType::msg_kind k, CcuListOf & l) { if (l.IsEmpty ()) return; f << "enum " << Name << MsgType::EnumSuffix [k] << " {\n"; CcuListIterOf msg = l; bool first = true; while (++msg) { if (first) first = false; else f << ",\n"; f << "\t" << MsgType::EnumPrefix [k] << (*msg)->GetName (); } f << "\n};\n\n"; } /*? Create the C++ header file containing the declarations of the requests defined in the file that has been read. ?*/ void UchMsgMgr :: DumpServerHeader () { /* build file name: ServerMsg.h, eg. FooServerMsg.h */ char file [128]; sprintf (file, "%sServerMsg.h", GetName ()); DumpDecl (file, isServer); } void UchMsgMgr :: DumpClientHeader () { /* build file name: ClientMsg.h, eg. FooClientMsg.h */ char file [128]; sprintf (file, "%sClientMsg.h", GetName ()); DumpDecl (file, isClient); } void UchMsgMgr :: DumpDecl (const char* file, int dest) { char macro [128]; sprintf (macro, "%sMsg_H_", GetName ()); ofstream f (file, ios::out); if (!f) { char buf[1024]; sprintf (buf, "can't write to %s", file); perror (buf); return; } f << "/*\n *\tMessages for service " << Name << "\n"; f << " *\n *\tThis file was generated by reqgen - do not edit\n*/\n\n"; f << "#ifndef " << macro << "\n"; f << "#define " << macro << "\n"; f << "#include \n\n"; DumpEnum (f, MsgType::isRequest, Requests); DumpEnum (f, MsgType::isAnswer, Answers); DumpEnum (f, MsgType::isEvent, Events); CcuListIterOf msg = Requests; while (++msg) (*msg)->DumpDecl (f, dest); msg = Answers; while (++msg) (*msg)->DumpDecl (f, dest); msg = Events; while (++msg) (*msg)->DumpDecl (f, dest); f << "#endif\t/* " << macro << " */\n"; } /*? Create the C++ file containing the code implementing the requests defined in the file read. ?*/ void UchMsgMgr :: DumpClientSource (const char* suffix) { /* build file name: ClientMsg., eg. FooClientMsg.cc */ char file [128]; sprintf (file, "%sClientMsg.%s", GetName (), suffix); DumpCode (file, isClient); } void UchMsgMgr :: DumpServerSource (const char* suffix) { /* build file name: ServerMsg., eg. FooServerMsg.cc */ char file [128]; sprintf (file, "%sServerMsg.%s", GetName (), suffix); DumpCode (file, isServer); } void UchMsgMgr :: DumpCode (const char* file, int dest) { ofstream f (file, ios::out); if (!f) { char buf[1024]; sprintf (buf, "can't write to %s", file); perror (buf); return; } f << "/*\n *\tMessages for service " << Name << "\n"; f << " *\n *\tThis file was generated by reqgen - do not edit\n*/\n\n"; if (dest & isClient) { f << "#include \"" << Name << "ClientMsg.h\"\n"; f << "#include \"" << Name << "Service.h\"\n"; } if (dest & isServer) { f << "#include \"" << Name << "ServerMsg.h\"\n"; f << "#include \"" << Name << "Server.h\"\n"; } f << "\n"; CcuListIterOf msg = Requests; while (++msg) (*msg)->DumpCode (f, dest); msg = Answers; while (++msg) (*msg)->DumpCode (f, dest); msg = Events; while (++msg) (*msg)->DumpCode (f, dest); if (dest & isClient) DumpClientCode (f); if (dest & isServer) DumpServerCode (f); } void UchMsgMgr :: DumpClientCode (ofstream& f) { f << "UchMessage*\n" << Name << "Service :: DecodeAnswer (UchMsgBuffer& b)\n{\n"; f << "\tlword type;\n"; f << "\tb.PeekLong (type, lwsize);\n\n"; f << "\tUchMessage* a = 0;\n"; f << "\tswitch (type) {\n"; CcuListIterOf ans = Answers; while (++ans) { f << "\tcase " << "an" << (*ans)->GetName () << ":\n"; f << "\t\ta = new " << (*ans)->GetName () << "Ans;\n"; f << "\t\tbreak;\n"; } f << "\t}\n"; f << "\tif (a)\n\t\tb.ReadMsg (*a);\n\treturn a;\n}\n\n"; f << "UchMessage*\n" << Name << "Service :: DecodeMessage (UchMsgBuffer& b)\n{\n"; f << "\tlword type;\n"; f << "\tb.PeekLong (type, lwsize);\n\n"; f << "\tUchMessage* m = 0;\n"; f << "\tswitch (type) {\n"; CcuListIterOf evt = Events; while (++evt) { f << "\tcase " << "ev" << (*evt)->GetName () << ":\n"; f << "\t\tm = new " << (*evt)->GetName () << "Event;\n"; f << "\t\tbreak;\n"; } f << "\t}\n"; f << "\tif (m)\n\t\tb.ReadMsg (*m);\n"; f << "\treturn m;\n}\n\n"; } void UchMsgMgr :: DumpServerCode (ofstream& f) { f << "UchMessage*\n" << Name << "Client :: DecodeMessage (UchMsgBuffer& b)\n{\n"; f << "\tlword type;\n"; f << "\tb.PeekLong (type, lwsize);\n\n"; f << "\tUchMessage* m = 0;\n"; f << "\tswitch (type) {\n"; CcuListIterOf req = Requests; while (++req) { f << "\tcase " << "rq" << (*req)->GetName () << ":\n"; f << "\t\tm = new " << (*req)->GetName () << "Req;\n"; f << "\t\tbreak;\n"; } f << "\t}\n"; f << "\tif (m)\n\t\tb.ReadMsg (*m);\n"; f << "\treturn m;\n}\n\n"; f << "UchClient*\n" << Name << "Server :: CreateClient (int fd)\n{\n"; f << "\treturn new " << Name << "Client (*this, fd);\n}\n\n"; } const char* const MsgType::ClassSuffix [3] = {"Req", "Ans", "Event"}; const char* const MsgType::EnumPrefix[3] = {"rq", "an", "ev"}; const char* const MsgType::EnumSuffix[3] = {"_requests", "_answers", "_events"}; /*? Dump the declaration of a request type to a file. ?*/ void MsgType :: DumpDecl (ofstream& f, int dest) { char classname [128]; sprintf (classname, "%s%s", GetName (), ClassSuffix [Kind]); int emitter, receiver; if (Kind == isRequest) { emitter = (dest & isClient); receiver = (dest & isServer); } else { emitter = (dest & isServer); receiver = (dest & isClient); } /* name and base class */ f << "class " << classname << " : public "; if (Kind == isEvent) f << "UchEventMsg"; else f << "UchMessage"; f << " {\n"; /* field containing the type */ f << "protected:\n"; f << "\tlword\tType;\n"; /* other fields */ CcuListIterOf fields (Fields); while (++fields) { MsgField* field = *fields; f << "\t" << field->GetImpl () << "\t" << field->GetName () << ";\n"; } /* default constructor, used in servers */ f << "public:\n"; if (!DefaultConstructor && (Fields.IsEmpty () || receiver)) f << "\t\t" << classname << " ();\n"; /* constructors declared in the file */ if (emitter) { CcuListIterOf constr (Constructors); while (++constr) { f << "\t\t" << classname << " ("; CcuListIterOf fields ((*constr)->GetParameters ()); int first = 1; while (++fields) { if (first) first = 0; else f << ", "; f << (*fields)->GetType (); } f << ");\n"; } } /* destructor */ f << "\t\t~" << classname << " ();\n"; /* other methods */ if (emitter) f << "\tvoid\tWriteTo (UchIOS&);\n"; if (receiver) { f << "\tvoid\tReadFrom (UchIOS&, lword);\n"; if (Kind == isRequest) f << "\nbool\tActivate (UchMsgStream&, bool);\n"; } /* getters defined in the file */ CcuListIterOf getter (Getters); while (++getter) { MsgField* field = *getter; f << "inline\t" << field->GetType () << "\tGet" << field->GetName () << " () const { return (" << field->GetType () << ") " << field->GetName () << "; }\n"; } /* setters defined in the file */ CcuListIterOf setter (Setters); while (++setter) { MsgField* field = *setter; f << "inline\tvoid\tSet" << field->GetName () << " (" << field->GetType () << " f) { " << field->GetName () << " = (" << field->GetImpl () << ") f; }\n"; } f << "};\n\n"; } /*? Dump the code of a request class to a file. ?*/ void MsgType :: DumpCode (ofstream& f, int dest) { char classname [128]; sprintf (classname, "%s%s", GetName (), ClassSuffix [Kind]); int emitter, receiver; if (Kind == isRequest) { emitter = (dest & isClient); receiver = (dest & isServer); } else { emitter = (dest & isServer); receiver = (dest & isClient); } /* the default constructor*/ if (!DefaultConstructor && (Fields.IsEmpty () || receiver)) { f << classname << " :: " << classname << " ()\n: "; if (Kind == isEvent) f << "UchEventMsg"; else f << "UchMessage"; f << " (),\n"; f << " Type (" << EnumPrefix [Kind] << Name << ")\n{\n}\n\n"; } /* other constructors, used in emitters */ if (emitter) { CcuListIterOf constr (Constructors); while (++constr) { f << classname << " :: " << classname << " ("; CcuListIterOf fields ((*constr)->GetParameters ()); int i = 0; while (++fields) { if (i > 0) f << ", "; f << (*fields)->GetType () << " i" << i; ++i; } f << ")\n: "; if (Kind == isEvent) f << "UchEventMsg"; else f << "UchMessage"; f << " (),\n Type (" << EnumPrefix [Kind] << Name << ")"; fields.Reset (); i = 0; while (++fields) { f << ",\n " << (*fields)->GetName () << " (i" << i << ")"; ++i; } f << "\n{\n}\n\n"; } } /* destructor */ f << classname << " :: ~" << classname << " ()\n{\n}\n\n"; CcuListIterOf field (Fields); if (receiver) { f << "void\n" << classname << " :: ReadFrom (UchIOS& b, lword)\n{\n"; #if 1 f << "\tlword type;\n\tb >> type"; #else f << "\t b "; #endif while (++field) f << " >> " << (*field)->GetName (); f << ";\n"; f << "}\n\n"; } if (emitter) { f << "void\n" << classname << " :: " << "WriteTo (UchIOS& b)\n{\n"; f << "\tb << Type"; field.Reset (); while (++field) f << " << " << (*field)->GetName (); f << ";\n"; f << "}\n\n"; } }