Implement C stub generator 40/286440/4
authorjusung <jusung07.son@samsung.com>
Fri, 6 Jan 2023 05:15:32 +0000 (14:15 +0900)
committerjusung <jusung07.son@samsung.com>
Tue, 10 Jan 2023 08:37:50 +0000 (17:37 +0900)
Change-Id: Ieb8d5243041323f782a114ea84a927cf5d24e5f1
Signed-off-by: jusung <jusung07.son@samsung.com>
14 files changed:
idlc/gen/version2/c_body_generator_base.cc
idlc/gen/version2/c_body_generator_base.hh
idlc/gen/version2/c_body_generator_base_cb.hh
idlc/gen/version2/c_group_body_generator_cb.hh
idlc/gen/version2/c_proxy_body_generator.cc
idlc/gen/version2/c_proxy_body_generator.hh
idlc/gen/version2/c_proxy_body_generator_cb.hh
idlc/gen/version2/c_stub_body_generator.cc [new file with mode: 0644]
idlc/gen/version2/c_stub_body_generator.hh [new file with mode: 0644]
idlc/gen/version2/c_stub_body_generator_cb.hh [new file with mode: 0644]
idlc/gen/version2/c_stub_header_generator.cc [new file with mode: 0644]
idlc/gen/version2/c_stub_header_generator.hh [new file with mode: 0644]
idlc/gen/version2/c_stub_header_generator_cb.hh [new file with mode: 0644]
idlc/main.cc

index 62404ff..6683217 100644 (file)
@@ -479,14 +479,7 @@ void CBodyGeneratorBase::GenStructureBase(std::ofstream& stream,
 void CBodyGeneratorBase::AddParameterType(const Interface& iface,
     const BaseType& type, ParameterType::Direction direction) {
   if (IsDelegateType(iface, type)) {
-    AddParameterType(
-        std::make_shared<ParameterType>(
-          new BaseType("delegate", "delegate", true),
-          ParameterType::Direction::IN));
-    AddParameterType(
-        std::make_shared<ParameterType>(
-          new BaseType("delegate", "delegate", true),
-          ParameterType::Direction::OUT));
+    return;
   } else if (type.IsUserDefinedType() || type.GetMetaType() != nullptr) {
     AddParameterType(
         std::make_shared<ParameterType>(
@@ -512,26 +505,11 @@ void CBodyGeneratorBase::AddParameterType(
   param_types_[key] = std::move(param_type);
 }
 
-void CBodyGeneratorBase::GenDelegateDefinition(std::ofstream& stream) {
-  stream << SmartIndent(CB_DELEGATE_DEFS);
-}
-
-void CBodyGeneratorBase::GenDelegateBase(std::ofstream& stream) {
-  stream << SmartIndent(CB_DELEGATE_BASE);
-}
-
 void CBodyGeneratorBase::GenUnitMapDefinition(std::ofstream& stream) {
   stream << SmartIndent(CB_UNIT_MAP_DEFS);
 }
 
 void CBodyGeneratorBase::GenParameterMap() {
-  if (GetChannelType() == ChannelType::TYPE_PROXY) {
-    AddParameterType(
-      std::make_shared<ParameterType>(
-        new BaseType("delegate", "delegate", true),
-        ParameterType::Direction::OUT));
-  }
-
   AddParameterType(
       std::make_shared<ParameterType>(
         new BaseType("int", "int"), ParameterType::Direction::IN));
@@ -554,17 +532,47 @@ void CBodyGeneratorBase::GenParameterMap() {
       for (const auto& decl : iface.GetDeclarations()) {
         for (const auto& param : decl->GetParameters()) {
           auto& type = param->GetParameterType().GetBaseType();
-          AddParameterType(iface, type,
+          if (decl->GetMethodType() == Declaration::MethodType::DELEGATE) {
+            AddParameterType(iface, type, ParameterType::Direction::OUT);
+          } else {
+            AddParameterType(iface, type,
               param->GetParameterType().GetDirection());
+          }
         }
 
+        auto& type = decl->GetType();
         if (decl->GetMethodType() == Declaration::MethodType::SYNC) {
-          auto& type = decl->GetType();
           AddParameterType(iface, type, ParameterType::Direction::OUT);
+        } else if (decl->GetMethodType() == Declaration::MethodType::DELEGATE) {
+          AddParameterType(
+              std::make_shared<ParameterType>(
+                new BaseType("delegate", "delegate", true),
+                  ParameterType::Direction::IN));
+          AddParameterType(
+              std::make_shared<ParameterType>(
+                new BaseType("delegate", "delegate", true),
+                  ParameterType::Direction::OUT));
+          AddParameterType(
+              std::make_shared<ParameterType>(
+                new BaseType(iface.GetID() + "_" + decl->GetID(), "", true),
+                  ParameterType::Direction::IN));
+          AddParameterType(
+              std::make_shared<ParameterType>(
+                new BaseType(iface.GetID() + "_" + decl->GetID(), "", true),
+                ParameterType::Direction::OUT));
         }
       }
     } else {
       auto& st = static_cast<const Structure&>(*block);
+      AddParameterType(
+        std::make_shared<ParameterType>(
+          new BaseType(st.GetID(), st.GetID(), true),
+            ParameterType::Direction::IN));
+      AddParameterType(
+        std::make_shared<ParameterType>(
+          new BaseType(st.GetID(), st.GetID(), true),
+            ParameterType::Direction::OUT));
+
       for (auto& elm : st.GetElements()) {
         auto& type = elm->GetType();
         AddParameterType(
@@ -581,6 +589,9 @@ void CBodyGeneratorBase::GenParameterMap() {
 void CBodyGeneratorBase::GenUnitMapBase(std::ofstream& stream) {
   stream << SmartIndent(CB_UNIT_MAP_BASE);
 
+  if (GetChannelType() == ChannelType::TYPE_PROXY)
+    stream << SmartIndent(CB_UNIT_MAP_CLEAR_BASE);
+
   GenParameterMap();
 
   std::string code;
index aaf4a71..34f6cad 100644 (file)
@@ -33,7 +33,6 @@ class CBodyGeneratorBase : public tidl::CBodyGeneratorBase {
 
   void GenStructureDefinition(std::ofstream& stream);
   void GenStructure(std::ofstream& stream);
-  void GenDelegateDefinition(std::ofstream& stream);
   void GenDelegateBase(std::ofstream& stream);
   void GenUnitMapDefinition(std::ofstream& stream);
   void GenUnitMapBase(std::ofstream& stream);
index 40eed5d..3ccf924 100644 (file)
 namespace tidl {
 namespace version2 {
 
-constexpr const char CB_DELEGATE_DEFS[] =
-R"__c_cb(
-typedef struct rpc_port_delegate_s {
-  rpc_port_parcelable_t parcelable;
-  int id;
-  int seq_id;
-  bool once;
-} rpc_port_delegate_t;
-
-typedef rpc_port_delegate_t *rpc_port_delegate_h;
-
-static rpc_port_delegate_h rpc_port_delegate_create(int id, int seq_id, bool once);
-)__c_cb";
-
-constexpr const char CB_DELEGATE_BASE[] =
-R"__c_cb(
-static void __rpc_port_delegate_to(rpc_port_parcel_h parcel, void *user_data)
-{
-  rpc_port_delegate_h delegate = user_data;
-  rpc_port_unit_map_h map;
-
-  map = rpc_port_unit_map_create();
-  if (map == nullptr) {
-    set_last_result(RPC_PORT_ERROR_OUT_OF_MEMORY);
-    return;
-  }
-
-  rpc_port_unit_map_write_int(map, "id", delegate->id);
-  rpc_port_unit_map_write_int(map, "seq_id", delegate->seq_id);
-  rpc_port_unit_map_write_bool(map, "once", delegate->once);
-  rpc_port_parcel_write(parcel, &map->parcelable, map);
-  rpc_port_unit_map_destroy(map);
-  set_last_result(RPC_PORT_ERROR_NONE);
-}
-
-static void __rpc_port_delegate_from(rpc_port_parcel_h parcel, void *user_data)
-{
-  rpc_port_delegate_h delegate = user_data;
-  rpc_port_unit_map_h map;
-
-  map = rpc_port_unit_map_create();
-  if (map == nullptr) {
-    set_last_result(RPC_PORT_ERROR_OUT_OF_MEMORY);
-    return;
-  }
-
-  rpc_port_parcel_read(parcel, &map->parcelable, map);
-  rpc_port_unit_map_read_int(map, "id", &delegate->id);
-  rpc_port_unit_map_read_int(map, "seq_id", &delegate->seq_id);
-  rpc_port_unit_map_read_bool(map, "once", &delegate->once);
-  rpc_port_unit_map_destroy(map);
-  set_last_result(RPC_PORT_ERROR_NONE);
-}
-
-static void rpc_port_delegate_destroy(rpc_port_delegate_h handle)
-{
-  if (handle == nullptr)
-    return;
-
-  free(handle);
-}
-
-static rpc_port_delegate_h rpc_port_delegate_create(int id, int seq_id, bool once)
-{
-  rpc_port_delegate_h delegate;
-
-  delegate = malloc(sizeof(rpc_port_delegate_t));
-  if (delegate == nullptr) {
-    _E("malloc() is failed");
-    return nullptr;
-  }
-
-  delegate->parcelable.to = __rpc_port_delegate_to;
-  delegate->parcelable.from = __rpc_port_delegate_from;
-  delegate->id = id;
-  delegate->seq_id = seq_id;
-  delegate->once = once;
-
-  return delegate;
-}
-)__c_cb";
-
 constexpr const char CB_UNIT_MAP_DEFS[] =
 R"__c_cb(
 typedef struct rpc_port_unit_s {
@@ -339,7 +257,10 @@ static rpc_port_unit_map_h rpc_port_unit_map_create(void)
 
   return unit_map;
 }
+)__c_cb";
 
+constexpr const char CB_UNIT_MAP_CLEAR_BASE[] =
+R"__c_cb(
 static int rpc_port_unit_map_clear(rpc_port_unit_map_h map)
 {
     if (map == nullptr) {
@@ -518,7 +439,7 @@ static int rpc_port_unit_map_read_delegate(rpc_port_unit_map_h unit_map,
   if (unit_map == nullptr || name == nullptr || value == nullptr)
     return RPC_PORT_ERROR_INVALID_PARAMETER;
 
-  delegate = rpc_port_delegate_create(0, 0, false);
+  delegate = rpc_port_delegate_create();
   if (delegate == NULL)
     return RPC_PORT_ERROR_OUT_OF_MEMORY;
 
index c9a837b..f931555 100644 (file)
@@ -171,7 +171,7 @@ static void __<NAME>_event_system_cb(const char *event_name, bundle *event_data,
   rpc_port_parcel_h header;
   int seq_num = -1;
   int cmd;
-       rpc_port_unit_map_h map;
+  rpc_port_unit_map_h map;
 
   rpc_port_parcel_get_header(p, &header);
   rpc_port_parcel_header_get_seq_num(header, &seq_num);
@@ -196,7 +196,6 @@ static void __<NAME>_event_system_cb(const char *event_name, bundle *event_data,
   } else {
     _W("Invalid protocol. cmd(%d)", cmd);
   }
-  rpc_port_unit_map_clear(map);
   rpc_port_unit_map_destroy(map);
 }
 
index f9aaaa4..419f799 100644 (file)
@@ -51,6 +51,14 @@ void CProxyBodyGenerator::OnInitGen(std::ofstream& stream) {
 void CProxyBodyGenerator::OnFiniGen(std::ofstream& stream) {
 }
 
+void CProxyBodyGenerator::GenDelegateDefinition(std::ofstream& stream) {
+  stream << SmartIndent(CB_DELEGATE_DEFS);
+}
+
+void CProxyBodyGenerator::GenDelegateBase(std::ofstream& stream) {
+  stream << SmartIndent(CB_DELEGATE_BASE);
+}
+
 void CProxyBodyGenerator::GenInterfaceDelegateCallback(std::ofstream& stream) {
   stream << SmartIndent(CB_INTERFACE_DELEGATE_CALLBACK);
 }
@@ -488,7 +496,7 @@ void CProxyBodyGenerator::GenInterfaceDelegateEnumBase(std::ofstream& stream,
   unsigned int num = 1;
   std::string enums;
   for (const auto& decl : iface.GetDeclarations()) {
-    if (decl->GetMethodType() == Declaration::MethodType::DELEGATE)
+    if (decl->GetMethodType() != Declaration::MethodType::DELEGATE)
       continue;
 
     enums += GetHandlePrefix() + "_" + iface.GetID() + "_DELEGATE_" +
index 4a205bd..ed4df29 100644 (file)
@@ -77,6 +77,8 @@ class CProxyBodyGenerator : public CBodyGeneratorBase {
       const Declaration& decl, bool& has_free);
   void GenInterfaceDelegateEnumBase(std::ofstream& stream,
       const Interface& iface);
+  void GenDelegateDefinition(std::ofstream& stream);
+  void GenDelegateBase(std::ofstream& stream);
 
  private:
   std::shared_ptr<Options> options_;
index 31359f7..4a7b35b 100644 (file)
 namespace tidl {
 namespace version2 {
 
+constexpr const char CB_DELEGATE_DEFS[] =
+R"__c_cb(
+typedef struct rpc_port_delegate_s {
+  rpc_port_parcelable_t parcelable;
+  int id;
+  int seq_id;
+  bool once;
+} rpc_port_delegate_t;
+
+typedef rpc_port_delegate_t *rpc_port_delegate_h;
+
+static rpc_port_delegate_h rpc_port_delegate_create();
+)__c_cb";
+
+constexpr const char CB_DELEGATE_BASE[] =
+R"__c_cb(
+static void __rpc_port_delegate_to(rpc_port_parcel_h parcel, void *user_data)
+{
+  rpc_port_delegate_h delegate = user_data;
+  rpc_port_unit_map_h map;
+
+  map = rpc_port_unit_map_create();
+  if (map == nullptr) {
+    set_last_result(RPC_PORT_ERROR_OUT_OF_MEMORY);
+    return;
+  }
+
+  rpc_port_unit_map_write_int(map, "id", delegate->id);
+  rpc_port_unit_map_write_int(map, "seq_id", delegate->seq_id);
+  rpc_port_unit_map_write_bool(map, "once", delegate->once);
+  rpc_port_parcel_write(parcel, &map->parcelable, map);
+  rpc_port_unit_map_destroy(map);
+  set_last_result(RPC_PORT_ERROR_NONE);
+}
+
+static void __rpc_port_delegate_from(rpc_port_parcel_h parcel, void *user_data)
+{
+  rpc_port_delegate_h delegate = user_data;
+  rpc_port_unit_map_h map;
+
+  map = rpc_port_unit_map_create();
+  if (map == nullptr) {
+    set_last_result(RPC_PORT_ERROR_OUT_OF_MEMORY);
+    return;
+  }
+
+  rpc_port_parcel_read(parcel, &map->parcelable, map);
+  rpc_port_unit_map_read_int(map, "id", &delegate->id);
+  rpc_port_unit_map_read_int(map, "seq_id", &delegate->seq_id);
+  rpc_port_unit_map_read_bool(map, "once", &delegate->once);
+  rpc_port_unit_map_destroy(map);
+  set_last_result(RPC_PORT_ERROR_NONE);
+}
+
+static void rpc_port_delegate_destroy(rpc_port_delegate_h handle)
+{
+  if (handle == nullptr)
+    return;
+
+  free(handle);
+}
+
+static rpc_port_delegate_h rpc_port_delegate_create()
+{
+  rpc_port_delegate_h delegate;
+
+  delegate = calloc(1, sizeof(rpc_port_delegate_t));
+  if (delegate == nullptr) {
+    _E("malloc() is failed");
+    return nullptr;
+  }
+
+  delegate->parcelable.to = __rpc_port_delegate_to;
+  delegate->parcelable.from = __rpc_port_delegate_from;
+
+  return delegate;
+}
+)__c_cb";
+
 constexpr const char CB_INTERFACE_DELEGATE_CALLBACK[] =
 R"__c_cb(
 typedef void (*rpc_port_proxy_delegate_cb)(GList **delegates, rpc_port_unit_map_h map, rpc_port_delegate_h delegate);
@@ -183,7 +262,6 @@ int <PREFIX>_<NAME>_<DELEGATE_NAME>_destroy(<PREFIX>_<NAME>_<DELEGATE_NAME>_h h)
 
 int <PREFIX>_<NAME>_<DELEGATE_NAME>_clone(<PREFIX>_<NAME>_<DELEGATE_NAME>_h h, <PREFIX>_<NAME>_<DELEGATE_NAME>_h *clone)
 {
-  <PREFIX>_<NAME>_<DELEGATE_NAME>_h handle;
   rpc_port_unit_map_h map;
   int ret;
 
@@ -198,14 +276,14 @@ int <PREFIX>_<NAME>_<DELEGATE_NAME>_clone(<PREFIX>_<NAME>_<DELEGATE_NAME>_h h, <
     return RPC_PORT_ERROR_OUT_OF_MEMORY;
   }
 
-  ret = rpc_port_unit_map_write_<DELEGATE_NAME>(map, "clone", h);
+  ret = rpc_port_unit_map_write_<NAME>_<DELEGATE_NAME>(map, "clone", h);
   if (ret != RPC_PORT_ERROR_NONE) {
     _E("Failed to write <DELEGATE_NAME>. error(%d)", ret);
     rpc_port_unit_map_destroy(map);
     return ret;
   }
 
-  ret = rpc_port_unit_map_read_<DELEGATE_NAME>(map, "clone", clone);
+  ret = rpc_port_unit_map_read_<NAME>_<DELEGATE_NAME>(map, "clone", clone);
   rpc_port_unit_map_destroy(map);
 
   return ret;
@@ -795,6 +873,7 @@ void <PREFIX>_<NAME>_invoke_<METHOD_NAME>(<PREFIX>_<NAME>_h h<METHOD_PARAMS>)
 {
   rpc_port_parcel_h parcel_;
   rpc_port_parcel_header_h header_;
+  rpc_port_unit_map_h map_;
   int seq_num_ = -1;
   int res_;
 
@@ -994,7 +1073,6 @@ rpc_port_unit_map_write_<TYPE_NAME>(map_, "<ARG>", <ARG>);
  */
 constexpr const char CB_INTERFACE_METHOD_USER_DEFINED_UNIT_MAP_READ[] =
 R"__c_cb(
-<ARG> = nullptr;
 res_ = rpc_port_unit_map_read_<TYPE_NAME>(map_, "<ARG_NAME>", &<ARG>);
 if (res_ != RPC_PORT_ERROR_NONE) {
   _E("Failed to read <TYPE_NAME>. error(%d)", res);
@@ -1009,7 +1087,6 @@ if (res_ != RPC_PORT_ERROR_NONE) {
  */
 constexpr const char CB_INTERFACE_METHOD_BUNDLE_UNIT_MAP_READ[] =
 R"__c_cb(
-<ARG> = nullptr;
 res_ = rpc_port_unit_map_read_bundle(map_, "<ARG_NAME>", &<ARG>);
 if (res_ != RPC_PORT_ERROR_NONE) {
   _E("Failed to read bundle. error(%d)", res_);
@@ -1024,7 +1101,6 @@ if (res_ != RPC_PORT_ERROR_NONE) {
  */
 constexpr const char CB_INTERFACE_METHOD_STRING_UNIT_MAP_READ[] =
 R"__c_cb(
-<ARG> = nullptr;
 res_ = rpc_port_unit_map_read_string(map_, "<ARG_NAME>", &<ARG>);
 if (res_ != RPC_PORT_ERROR_NONE) {
   _E("Failed to read string. error(%d)", res_);
diff --git a/idlc/gen/version2/c_stub_body_generator.cc b/idlc/gen/version2/c_stub_body_generator.cc
new file mode 100644 (file)
index 0000000..4becb46
--- /dev/null
@@ -0,0 +1,704 @@
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <algorithm>
+
+#include "idlc/gen/version2/c_stub_body_generator.hh"
+#include "idlc/gen/version2/c_stub_body_generator_cb.hh"
+
+namespace tidl {
+namespace version2 {
+
+CStubBodyGenerator::CStubBodyGenerator(std::shared_ptr<Document> doc,
+    std::shared_ptr<Options> options)
+    : CBodyGeneratorBase(doc), options_(options) {
+}
+
+void CStubBodyGenerator::OnInitGen(std::ofstream& stream) {
+  GenVersion(stream);
+  GenGNUSourceDefinition(stream);
+  GenIncludeDefaultHeaders(stream);
+  GenIncludeHeader(stream);
+  GenLogTag(stream, std::string("RPC_PORT_STUB"));
+  GenLogDefinition(stream);
+  GenVersionDefinition(stream);
+  GenBaseDefinition(stream);
+  GenThreadEnableDefinition(stream);
+  GenInterfaceEnums(stream);
+  GenUnitMapDefinition(stream);
+  GenInterfaceMethodHandlerType(stream);
+  GenDelegateDefinition(stream);
+  GenStructureDefinition(stream);
+  GenInterfaceDefs(stream);
+  GenPrivateSharingListSet(stream);
+  GenUnitMapBase(stream);
+  GenDelegateBase(stream);
+  GenStructure(stream);
+  GenInterfaces(stream);
+}
+
+void CStubBodyGenerator::OnFiniGen(std::ofstream& stream) {
+}
+
+void CStubBodyGenerator::GenDelegateDefinition(std::ofstream& stream) {
+  stream << SmartIndent(CB_DELEGATE_DEFS);
+}
+
+void CStubBodyGenerator::GenDelegateBase(std::ofstream& stream) {
+  stream << SmartIndent(CB_DELEGATE_BASE);
+}
+
+// @see #CB_THREAD_ENABLE_DEF
+void CStubBodyGenerator::GenThreadEnableDefinition(std::ofstream& stream) {
+  if (!options_->IsThreadEnabled())
+    return;
+
+  stream << std::string(CB_THREAD_ENABLE_DEF);
+}
+
+// @see #CB_INTERFACE_METHOD_HANDLER_TYPE
+void CStubBodyGenerator::GenInterfaceMethodHandlerType(std::ofstream& stream) {
+  stream << SmartIndent(CB_INTERFACE_METHOD_HANDLER_TYPE);
+}
+
+void CStubBodyGenerator::GenInterfaceEnums(std::ofstream& stream) {
+  for (auto& b : GetDocument().GetBlocks()) {
+    if (b->GetType() != Block::TYPE_INTERFACE)
+      continue;
+
+    auto& iface = static_cast<const Interface&>(*b);
+    GenInterfaceEnum(stream, iface);
+  }
+}
+
+void CStubBodyGenerator::GenInterfaceEnum(std::ofstream& stream,
+    const Interface& iface) {
+  GenInterfaceMethodEnumBase(stream, iface);
+  GenInterfaceDelegateEnumBase(stream, iface);
+}
+
+// @see #CB_INTERFACE_METHOD_ENUM
+std::string CStubBodyGenerator::GenMethodEnums(const Interface& iface) {
+  std::string method_enum(ReplaceAll(CB_INTERFACE_METHOD_ENUM, {
+      { "<UPPERCASE_PREFIX>", GetHandlePrefix() },
+      { "<UPPERCASE_NAME>", iface.GetID() },
+      { "<UPPERCASE_METHOD_NAME>", "RESULT_" }
+  }));
+
+  std::string method_enums = RemoveLine(method_enum);
+
+  method_enum = ReplaceAll(CB_INTERFACE_METHOD_ENUM, {
+      { "<UPPERCASE_PREFIX>", GetHandlePrefix() },
+      { "<UPPERCASE_NAME>", iface.GetID() },
+      { "<UPPERCASE_METHOD_NAME>", "CALLBACK_" }
+  });
+
+  method_enums += RemoveLine(method_enum);
+
+  for (const auto& d : iface.GetDeclarations()) {
+    if (d->GetMethodType() == Declaration::MethodType::DELEGATE)
+      continue;
+
+    method_enum = ReplaceAll(CB_INTERFACE_METHOD_ENUM, {
+        { "<UPPERCASE_PREFIX>", GetHandlePrefix() },
+        { "<UPPERCASE_NAME>", iface.GetID() },
+        { "<UPPERCASE_METHOD_NAME>", d->GetID() }
+    });
+
+    method_enums += RemoveLine(method_enum);
+  }
+  std::transform(method_enums.begin(), method_enums.end(), method_enums.begin(),
+      ::toupper);
+
+  return method_enums;
+}
+
+// @see #CB_INTERFACE_METHOD_ENUM_BASE
+void CStubBodyGenerator::GenInterfaceMethodEnumBase(std::ofstream& stream,
+    const Interface& iface) {
+  std::string code(ReplaceAll(CB_INTERFACE_METHOD_ENUM_BASE, {
+      { "<PREFIX>", GetHandlePrefix() },
+      { "<NAME>", iface.GetID() },
+      { "<METHOD_ENUMS>", GenMethodEnums(iface) }
+  }));
+
+  stream << SmartIndent(code);
+}
+
+// @see #CB_INTERFACE_DELEGATE_ENUM
+std::string CStubBodyGenerator::GenDelegateEnums(const Interface& iface) {
+  unsigned int num = 1;
+  std::string method_enums;
+  for (const auto& d : iface.GetDeclarations()) {
+    if (d->GetMethodType() != Declaration::MethodType::DELEGATE)
+      continue;
+
+    std::string method_enum(ReplaceAll(CB_INTERFACE_DELEGATE_ENUM, {
+        { "<UPPERCASE_PREFIX>", GetHandlePrefix() },
+        { "<UPPERCASE_NAME>", iface.GetID() },
+        { "<UPPERCASE_DELEGATE_NAME>", d->GetID() },
+        { "<NUMBER>", std::to_string(num++) }
+    }));
+
+    method_enums += RemoveLine(method_enum);
+  }
+  std::transform(method_enums.begin(), method_enums.end(), method_enums.begin(),
+      ::toupper);
+
+  return method_enums;
+}
+
+// @see #CB_INTERFACE_DELEGATE_ENUM_BASE
+void CStubBodyGenerator::GenInterfaceDelegateEnumBase(std::ofstream& stream,
+    const Interface& iface) {
+  std::string delegate_enums = GenDelegateEnums(iface);
+  if (delegate_enums.empty())
+    return;
+
+  std::string code(ReplaceAll(CB_INTERFACE_DELEGATE_ENUM_BASE, {
+      { "<PREFIX>", GetHandlePrefix() },
+      { "<NAME>", iface.GetID() },
+      { "<DELEGATE_ENUMS>", delegate_enums }
+  }));
+
+  stream << SmartIndent(code);
+}
+
+void CStubBodyGenerator::GenInterfaceDefs(std::ofstream& stream) {
+  for (auto& b : GetDocument().GetBlocks()) {
+    if (b->GetType() != Block::TYPE_INTERFACE)
+      continue;
+
+    auto& iface = static_cast<const Interface&>(*b);
+    GenInterfaceDef(stream, iface);
+  }
+}
+
+void CStubBodyGenerator::GenInterfaceDef(std::ofstream& stream,
+    const Interface& iface) {
+  bool has_delegate = false;
+  for (const auto& d : iface.GetDeclarations()) {
+    if (d->GetMethodType() != Declaration::MethodType::DELEGATE)
+      continue;
+
+    GenInterfaceDelegateDef(stream, iface, *d);
+    has_delegate = true;
+  }
+
+  if (has_delegate)
+    GenInterfaceCallbackPortCheckDef(stream, iface);
+
+  GenInterfaceContextDef(stream, iface);
+  GenInterfaceBaseDef(stream, iface);
+}
+
+// @see #CB_INTERFACE_DELEGATE_DEF
+void CStubBodyGenerator::GenInterfaceDelegateDef(std::ofstream& stream,
+    const Interface& iface, const Declaration& decl) {
+  std::string code(ReplaceAll(CB_INTERFACE_DELEGATE_DEF, {
+      { "<PREFIX>", GetHandlePrefix() },
+      { "<NAME>", iface.GetID() },
+      { "<DELEGATE_NAME>", decl.GetID() }
+  }));
+
+  stream << SmartIndent(code);
+}
+
+// @see #CB_INTERFACE_CALLBACK_PORT_CHECK_DEF
+void CStubBodyGenerator::GenInterfaceCallbackPortCheckDef(std::ofstream& stream,
+    const Interface& iface) {
+  std::string code(ReplaceAll(CB_INTERFACE_CALLBACK_PORT_CHECK_DEF, {
+      { "<PREFIX>", GetHandlePrefix() },
+      { "<NAME>", iface.GetID() }
+  }));
+
+  stream << SmartIndent(code);
+}
+
+// @see #CB_INTERFACE_CONTEXT_DEF
+void CStubBodyGenerator::GenInterfaceContextDef(std::ofstream& stream,
+    const Interface& iface) {
+  std::string code(ReplaceAll(CB_INTERFACE_CONTEXT_DEF, {
+      { "<PREFIX>", GetHandlePrefix() },
+      { "<NAME>", iface.GetID() }
+  }));
+
+  stream << SmartIndent(code);
+}
+
+// @see #CB_INTERFACE_BASE_DEF
+void CStubBodyGenerator::GenInterfaceBaseDef(std::ofstream& stream,
+    const Interface& iface) {
+  std::string code(ReplaceAll(CB_INTERFACE_BASE_DEF, {
+      { "<PREFIX>", GetHandlePrefix() },
+      { "<NAME>", iface.GetID() }
+  }));
+
+  stream << SmartIndent(code);
+}
+
+void CStubBodyGenerator::GenInterfaces(std::ofstream& stream) {
+  for (auto& i : GetDocument().GetBlocks()) {
+    if (i->GetType() != Block::TYPE_INTERFACE)
+      continue;
+
+    const Interface &iface = static_cast<const Interface&>(*i);
+    GenInterface(stream, iface);
+  }
+}
+
+void CStubBodyGenerator::GenInterface(std::ofstream& stream, const Interface& iface) {
+  bool has_delegate = false;
+  for (const auto& d : iface.GetDeclarations()) {
+    if (d->GetMethodType() != Declaration::MethodType::DELEGATE)
+      continue;
+
+    GenInterfaceDelegateBase(stream, iface, *d);
+    has_delegate = true;
+  }
+
+  for (const auto& d : iface.GetDeclarations()) {
+    if (d->GetMethodType() == Declaration::MethodType::DELEGATE)
+      continue;
+
+    GenInterfaceMethodHandlerBase(stream, iface, *d);
+  }
+
+  GenInterfaceMethodTable(stream, iface);
+  GenInterfaceContextBase(stream, iface);
+
+  if (has_delegate)
+    GenInterfaceCallbackPortCheck(stream, iface);
+
+  GenInterfaceBase(stream, iface);
+}
+
+// @see #CB_INTERFACE_CONTEXT_BASE
+void CStubBodyGenerator::GenInterfaceContextBase(std::ofstream& stream,
+    const Interface& iface) {
+  std::string code(ReplaceAll(CB_INTERFACE_CONTEXT_BASE, {
+      { "<PREFIX>", GetHandlePrefix() },
+      { "<NAME>", iface.GetID() }
+  }));
+
+  stream << SmartIndent(code);
+}
+
+std::string CStubBodyGenerator::GenDelegateParams(const Interface& iface,
+    const Declaration& decl) {
+  std::string params;
+  for (const auto& p : decl.GetParameters()) {
+    params += ", ";
+    auto& param_type = p->GetParameterType();
+    auto& type = param_type.GetBaseType();
+    params += GetParamTypeString(param_type.GetDirection(), type, iface) +
+        p->GetID();
+  }
+
+  return params;
+}
+
+std::string CStubBodyGenerator::GenDelegateParamsCheck(const Interface& iface,
+    const Declaration& decl) {
+  std::string params_check;
+  for (const auto& p : decl.GetParameters()) {
+    auto& param_type = p->GetParameterType();
+    auto& type = param_type.GetBaseType();
+    if (IsDelegateType(iface, type) ||
+        type.IsUserDefinedType() ||
+        type.ToString() == "list" ||
+        type.ToString() == "array" ||
+        type.ToString() == "bundle" ||
+        type.ToString() == "string" ||
+        type.ToString() == "file")
+      params_check += " || " + p->GetID() + " == nullptr";
+  }
+
+  return params_check;
+}
+
+// @see #CB_INTERFACE_DELEGATE_BASE
+void CStubBodyGenerator::GenInterfaceDelegateBase(std::ofstream& stream,
+    const Interface& iface, const Declaration& decl) {
+  std::string enum_value = GetHandlePrefix() + "_" + iface.GetID() +
+      "_DELEGATE_" + decl.GetID();
+  std::transform(enum_value.begin(), enum_value.end(), enum_value.begin(),
+      ::toupper);
+
+  std::string prefix = GetHandlePrefix();
+  std::transform(prefix.begin(), prefix.end(), prefix.begin(), ::toupper);
+
+  std::string name = iface.GetID();
+  std::transform(name.begin(), name.end(), name.begin(), ::toupper);
+
+  std::string code(ReplaceAll(CB_INTERFACE_DELEGATE_BASE, {
+      { "<PREFIX>", GetHandlePrefix() },
+      { "<NAME>", iface.GetID() },
+      { "<DELEGATE_NAME>", decl.GetID() },
+      { "<DELEGATE_PARAMS>", GenDelegateParams(iface, decl) },
+      { "<DELEGATE_PARAMS_CHECK>", GenDelegateParamsCheck(iface, decl) },
+      { "<DELEGATE_ENUM_VALUE>", enum_value },
+      { "<DELEGATE_UNIT_MAP_WRITE>", GenDelegateUnitMapWrite(iface, decl) },
+      { "<UPPERCASE_PREFIX>", prefix },
+      { "<UPPERCASE_NAME>", name }
+  }));
+
+  stream << SmartIndent(code);
+}
+
+std::string CStubBodyGenerator::GenMethodHandlerArgsDecl(const Interface& iface,
+    const Declaration& decl) {
+  std::string args_decl;
+  for (const auto& p : decl.GetParameters()) {
+    auto& param_type = p->GetParameterType();
+    auto& type = param_type.GetBaseType();
+    args_decl += GetArgTypeString(type, iface) + p->GetID() + " = " +
+        GetErrorValue(type) + ";" + NLine(1);
+  }
+
+  if (decl.GetMethodType() == Declaration::MethodType::SYNC) {
+    args_decl += "rpc_port_parcel_h parcel_;" + NLine(1);
+    args_decl += "rpc_port_unit_map_h map_;" + NLine(1);
+    args_decl += GetArgTypeString(decl.GetType(), iface) + "res_ = " +
+        GetErrorValue(decl.GetType()) + ";" + NLine(1);
+  }
+
+  return args_decl;
+}
+
+// @see #CB_INTERFACE_METHOD_DELEGATE_UNIT_MAP_READ
+// @see #CB_INTERFACE_METHOD_USER_DEFINED_UNIT_MAP_READ
+// @see #CB_INTERFACE_METHOD_BUNDLE_UNIT_MAP_READ
+// @see #CB_INTERFACE_METHOD_STRING_UNIT_MAP_READ
+// @see #CB_INTERFACE_METHOD_BASE_UNIT_MAP_READ
+std::string CStubBodyGenerator::GenMethodUnitMapRead(const Interface& iface,
+    const Declaration& decl) {
+  std::string code;
+  for (const auto& p : decl.GetParameters()) {
+    std::string parcel_read_code;
+    auto& param_type = p->GetParameterType();
+    if (param_type.GetDirection() != ParameterType::Direction::IN)
+      continue;
+
+    auto& type = param_type.GetBaseType();
+    if (IsDelegateType(iface, type)){
+      parcel_read_code = ReplaceAll(CB_INTERFACE_METHOD_DELEGATE_UNIT_MAP_READ)
+          .Change("<PREFIX>", GetHandlePrefix())
+          .Change("<TYPE_NAME>", GetFullNameFromType(type, iface))
+          .Change("<ARG_NAME>", std::string("delegate"))
+          .Change("<ARG>", p->GetID());
+
+    } else if (type.IsUserDefinedType() || type.GetMetaType() != nullptr) {
+      parcel_read_code = ReplaceAll(CB_INTERFACE_METHOD_USER_DEFINED_UNIT_MAP_READ)
+          .Change("<TYPE_NAME>", GetFullNameFromType(type, iface))
+          .Change("<ARG_NAME>", p->GetID())
+          .Change("<ARG>", p->GetID());
+    } else if (type.ToString() == "bundle") {
+      parcel_read_code = ReplaceAll(CB_INTERFACE_METHOD_BUNDLE_UNIT_MAP_READ)
+          .Change("<ARG_NAME>", p->GetID())
+          .Change("<ARG>", p->GetID());
+    } else if (type.ToString() == "string" || type.ToString() == "file") {
+      parcel_read_code = ReplaceAll(CB_INTERFACE_METHOD_STRING_UNIT_MAP_READ)
+          .Change("<ARG_NAME>", p->GetID())
+          .Change("<ARG>", p->GetID());
+    } else {
+      parcel_read_code = ReplaceAll(CB_INTERFACE_METHOD_BASE_UNIT_MAP_READ)
+          .Change("<TYPE_NAME>", GetFullNameFromType(type, iface))
+          .Change("<ARG_NAME>", p->GetID())
+          .Change("<ARG>", p->GetID());
+    }
+
+    code += parcel_read_code;
+  }
+
+  return RemoveLine(code);
+}
+
+// @see #CB_INTERFACE_METHOD_CALLBACK_INVOKE
+std::string CStubBodyGenerator::GenMethodHandlerCallbackInvoke(
+    const Declaration& decl) {
+  std::string code(ReplaceAll(CB_INTERFACE_METHOD_CALLBACK_INVOKE,
+      "<METHOD_NAME>", decl.GetID()));
+
+  if (decl.GetMethodType() == Declaration::MethodType::SYNC)
+    code = ReplaceAll(code, "<RES_SET>", "res_ = ");
+  else
+    code = ReplaceAll(code, "<RES_SET>", "");
+
+  std::string args;
+  for (const auto& p : decl.GetParameters()) {
+    args += ", ";
+    auto& param_type = p->GetParameterType();
+    if (param_type.GetDirection() != ParameterType::Direction::IN)
+      args += "&";
+
+    args += p->GetID();
+  }
+  code = ReplaceAll(code, "<METHOD_ARGS>", args);
+
+  return RemoveLine(code);
+}
+
+std::string CStubBodyGenerator::GenDelegateUnitMapWrite(
+    const Interface& iface, const Declaration& decl) {
+    std::string parcel_write_code;
+  for (const auto& p : decl.GetParameters()) {
+    auto& param_type = p->GetParameterType();
+    parcel_write_code += GenMethodUnitMapWriteBase(
+        iface, param_type.GetBaseType(), p->GetID(), p->GetID());
+  }
+  return RemoveLine(parcel_write_code);
+}
+
+// @see #CB_INTERFACE_METHOD_DELEGATE_UNIT_MAP_WRITE
+// @see #CB_INTERFACE_METHOD_USER_DEFINED_UNIT_MAP_WRITE
+// @see #CB_INTERFACE_METHOD_BUNDLE_UNIT_MAP_WRITE
+// @see #CB_INTERFACE_METHOD_STRING_UNIT_MAP_WRITE
+// @see #CB_INTERFACE_METHOD_BASE_UNIT_MAP_WRITE
+std::string CStubBodyGenerator::GenMethodUnitMapWriteBase(
+    const Interface& iface, const BaseType& type,
+    const std::string& arg_name, const std::string& arg) {
+  std::string parcel_write_code;
+
+  if (IsDelegateType(iface, type)) {
+     parcel_write_code = ReplaceAll(CB_INTERFACE_METHOD_DELEGATE_UNIT_MAP_WRITE)
+         .Change("<ARG_NAME>", std::string("delegate"))
+         .Change("<ARG>", arg);
+   } else if (type.IsUserDefinedType() ||
+       type.ToString() == "list" ||
+       type.ToString() == "array") {
+     parcel_write_code = ReplaceAll(CB_INTERFACE_METHOD_USER_DEFINED_UNIT_MAP_WRITE)
+         .Change("<TYPE_NAME>", GetFullNameFromType(type, iface))
+         .Change("<ARG_NAME>", arg_name)
+         .Change("<ARG>", arg);
+     parcel_write_code += GetPrivateSharingString(type, iface, "port", arg);
+   } else if (type.ToString() == "bundle") {
+     parcel_write_code = ReplaceAll(CB_INTERFACE_METHOD_BUNDLE_UNIT_MAP_WRITE)
+         .Change("<ARG_NAME>", arg_name)
+         .Change("<ARG>", arg);
+   } else if (type.ToString() == "string") {
+     parcel_write_code = ReplaceAll(CB_INTERFACE_METHOD_STRING_UNIT_MAP_WRITE)
+         .Change("<ARG_NAME>", arg_name)
+         .Change("<ARG>", arg);
+   } else if (type.ToString() == "file") {
+     parcel_write_code = ReplaceAll(CB_INTERFACE_METHOD_STRING_UNIT_MAP_WRITE)
+         .Change("<ARG_NAME>", arg_name)
+         .Change("<ARG>", arg);
+     parcel_write_code += GetPrivateSharingString(type, iface, "port", arg_name);
+   } else {
+     parcel_write_code = ReplaceAll(CB_INTERFACE_METHOD_BASE_UNIT_MAP_WRITE)
+         .Change("<TYPE_NAME>", GetFullNameFromType(type, iface))
+         .Change("<ARG_NAME>", arg_name)
+         .Change("<ARG>", arg);
+   }
+
+   return parcel_write_code;
+}
+// @see #CB_INTERFACE_METHOD_PARCEL_WRITE_PRE
+// @see #CB_INTERFACE_METHOD_PARCEL_WRITE_POST
+std::string CStubBodyGenerator::GenMethodUnitMapWrite(const Interface& iface,
+    const Declaration& decl) {
+  std::string code;
+  if (decl.GetMethodType() != Declaration::MethodType::SYNC)
+    return code;
+
+  std::string prefix = GetHandlePrefix();
+  std::transform(prefix.begin(), prefix.end(), prefix.begin(), ::toupper);
+  code = ReplaceAll(CB_INTERFACE_METHOD_PARCEL_WRITE_PRE, "<UPPERCASE_PREFIX>",
+      prefix);
+
+  std::string name = iface.GetID();
+  std::transform(name.begin(), name.end(), name.begin(), ::toupper);
+  code = ReplaceAll(code, "<UPPERCASE_NAME>", name);
+
+  std::string parcel_write_code;
+  for (const auto& p : decl.GetParameters()) {
+    auto& param_type = p->GetParameterType();
+    if (param_type.GetDirection() == ParameterType::Direction::IN)
+      continue;
+    code += GenMethodUnitMapWriteBase(
+        iface, param_type.GetBaseType(), p->GetID(), p->GetID());
+  }
+
+  code += GenMethodUnitMapWriteBase(iface, decl.GetType(), "[RESULT]", "res_");
+
+  code += std::string(CB_INTERFACE_METHOD_PARCEL_WRITE_POST);
+
+  return RemoveLine(code);
+}
+
+// @see #CB_INTERFACE_METHOD_USER_DEFINED_FREE
+// @see #CB_INTERFACE_METHOD_BUNDLE_FREE
+// @see #CB_INTERFACE_METHOD_STRING_FREE
+std::string CStubBodyGenerator::GenMethodHandlerArgsFree(const Interface& iface,
+    const Declaration& decl) {
+  std::string free_code;
+  std::string code;
+  for (const auto& p : decl.GetParameters()) {
+    auto& param_type = p->GetParameterType();
+    auto& type = param_type.GetBaseType();
+    if (IsDelegateType(iface, type) ||
+        type.IsUserDefinedType() ||
+        type.ToString() == "list" ||
+        type.ToString() == "array") {
+      free_code = ReplaceAll(CB_INTERFACE_METHOD_USER_DEFINED_FREE,
+          "<PREFIX>", GetHandlePrefix());
+      free_code = ReplaceAll(free_code, "<NAME>",
+          GetFullNameFromType(type, iface));
+      free_code = ReplaceAll(free_code, "<ARG>", p->GetID());
+    } else if (type.ToString() == "bundle") {
+      free_code = ReplaceAll(CB_INTERFACE_METHOD_BUNDLE_FREE,
+          "<ARG>", p->GetID());
+    } else if (type.ToString() == "string" || type.ToString() == "file") {
+      free_code = ReplaceAll(CB_INTERFACE_METHOD_STRING_FREE,
+          "<ARG>", p->GetID());
+    } else {
+      free_code.clear();
+    }
+
+    code += free_code;
+  }
+
+  if (decl.GetMethodType() == Declaration::MethodType::SYNC) {
+    auto& type = decl.GetType();
+    if (IsDelegateType(iface, type) ||
+        type.IsUserDefinedType() ||
+        type.ToString() == "list" ||
+        type.ToString() == "array") {
+      free_code = ReplaceAll(CB_INTERFACE_METHOD_USER_DEFINED_FREE,
+          "<PREFIX>", GetHandlePrefix());
+      free_code = ReplaceAll(free_code, "<NAME>",
+          GetFullNameFromType(type, iface));
+      free_code = ReplaceAll(free_code, "<ARG>", "res_");
+    } else if (type.ToString() == "bundle") {
+      free_code = ReplaceAll(CB_INTERFACE_METHOD_BUNDLE_FREE,
+          "<ARG>", "res_");
+    } else if (type.ToString() == "string" || type.ToString() == "file") {
+      free_code = ReplaceAll(CB_INTERFACE_METHOD_STRING_FREE,
+          "<ARG>", "res_");
+    } else {
+      free_code.clear();
+    }
+
+    code += free_code;
+  }
+
+  return RemoveLine(code);
+}
+
+// @see #CB_INTERFACE_METHOD_HANDLER_BASE
+void CStubBodyGenerator::GenInterfaceMethodHandlerBase(std::ofstream& stream,
+    const Interface& iface, const Declaration& decl) {
+  std::string code(ReplaceAll(CB_INTERFACE_METHOD_HANDLER_BASE, {
+      { "<PREFIX>", GetHandlePrefix() },
+      { "<NAME>", iface.GetID() },
+      { "<METHOD_NAME>", decl.GetID() },
+      { "<METHOD_HANDLER_ARGS_DECL>", GenMethodHandlerArgsDecl(iface, decl) },
+      { "<METHOD_UNIT_MAP_READ>",
+          GenMethodUnitMapRead(iface, decl) },
+      { "<METHOD_HANDLER_CALLBACK_INVOKE>",
+          GenMethodHandlerCallbackInvoke(decl) },
+      { "<METHOD_UNIT_MAP_WRITE>",
+          GenMethodUnitMapWrite(iface, decl) },
+      { "<METHOD_HANDLER_ARGS_FREE>", GenMethodHandlerArgsFree(iface, decl) }
+  }));
+
+  stream << SmartIndent(code);
+}
+
+// @see #CB_INTERFACE_METHOD_HANDLER
+std::string CStubBodyGenerator::GenMethodHandlers(const Interface& iface) {
+  std::string code;
+  for (const auto& d : iface.GetDeclarations()) {
+    if (d->GetMethodType() == Declaration::MethodType::DELEGATE)
+      continue;
+
+    std::string enum_value = GetHandlePrefix() + "_" + iface.GetID() +
+      "_METHOD_" + d->GetID();
+    std::transform(enum_value.begin(), enum_value.end(), enum_value.begin(),
+        ::toupper);
+    std::string method_handler(ReplaceAll(CB_INTERFACE_METHOD_HANDLER, {
+        { "<ENUM_VALUE>", enum_value },
+        { "<PREFIX>", GetHandlePrefix() },
+        { "<NAME>", iface.GetID() },
+        { "<METHOD_NAME>", d->GetID() }
+    }));
+
+    code += RemoveLine(method_handler);
+  }
+
+  return code;
+}
+
+// @see #CB_INTERFACE_METHOD_TABLE
+void CStubBodyGenerator::GenInterfaceMethodTable(std::ofstream& stream,
+    const Interface& iface) {
+  std::string code(ReplaceAll(CB_INTERFACE_METHOD_TABLE, {
+      { "<NAME>", iface.GetID() },
+      { "<METHOD_HANDLERS>", GenMethodHandlers(iface) }
+  }));
+
+  stream << SmartIndent(code);
+}
+
+// @see #CB_INTERFACE_CALLBACK_PORT_CHECK
+void CStubBodyGenerator::GenInterfaceCallbackPortCheck(std::ofstream& stream,
+    const Interface& iface) {
+  std::string code(ReplaceAll(CB_INTERFACE_CALLBACK_PORT_CHECK, {
+      { "<PREFIX>", GetHandlePrefix() },
+      { "<NAME>", iface.GetID() }
+  }));
+
+  stream << SmartIndent(code);
+}
+
+// @see #CB_INTERFACE_PRIVILEGE_ADD
+// @see #CB_INTERFACE_TRUSTED_SET
+std::string CStubBodyGenerator::GenAccessControlSet(const Interface& iface) {
+  std::string code;
+  for (const auto& attr : iface.GetAttributes()) {
+    if (attr->GetKey() == "privilege") {
+      std::string privilege_add(ReplaceAll(CB_INTERFACE_PRIVILEGE_ADD, {
+          { "<NAME>", iface.GetID() },
+          { "<PRIVILEGE>", attr->GetValue() }
+      }));
+
+      code += privilege_add;
+    } else if (attr->GetKey() == "trusted" && attr->GetValue() == "true") {
+      std::string trusted_set(ReplaceAll(CB_INTERFACE_TRUSTED_SET,
+          "<NAME>", iface.GetID()));
+
+      code += trusted_set;
+    }
+  }
+
+  return RemoveLine(code);
+}
+
+// @see #CB_INTERFACE_BASE
+void CStubBodyGenerator::GenInterfaceBase(std::ofstream& stream,
+    const Interface& iface) {
+  std::string code(ReplaceAll(CB_INTERFACE_BASE, {
+      { "<PREFIX>", GetHandlePrefix() },
+      { "<NAME>", iface.GetID() },
+      { "<ACCESS_CONTROL_SET>", GenAccessControlSet(iface) }
+  }));
+
+  stream << SmartIndent(code);
+}
+
+}  // namespace version2
+}  // namespace tidl
diff --git a/idlc/gen/version2/c_stub_body_generator.hh b/idlc/gen/version2/c_stub_body_generator.hh
new file mode 100644 (file)
index 0000000..639f476
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef IDLC_C_GEN_C_STUB_BODY_GENERATOR_HH_
+#define IDLC_C_GEN_C_STUB_BODY_GENERATOR_HH_
+
+#include <memory>
+#include <string>
+
+#include "idlc/gen/version2/c_body_generator_base.hh"
+#include "idlc/options.h"
+
+namespace tidl {
+namespace version2 {
+
+class CStubBodyGenerator : public CBodyGeneratorBase {
+ public:
+  explicit CStubBodyGenerator(std::shared_ptr<Document> doc,
+      std::shared_ptr<Options> options);
+  virtual ~CStubBodyGenerator() = default;
+
+  void OnInitGen(std::ofstream& stream) override;
+  void OnFiniGen(std::ofstream& stream) override;
+
+ private:
+  void GenThreadEnableDefinition(std::ofstream& stream);
+  void GenInterfaceMethodHandlerType(std::ofstream& stream);
+  void GenInterfaceEnums(std::ofstream& stream);
+  void GenInterfaceEnum(std::ofstream& stream, const Interface& iface);
+  void GenInterfaceMethodEnumBase(std::ofstream& stream,
+      const Interface& iface);
+  void GenInterfaceDelegateEnumBase(std::ofstream& stream,
+      const Interface& iface);
+
+  void GenInterfaceDefs(std::ofstream& stream);
+  void GenInterfaceDef(std::ofstream& stream, const Interface& iface);
+  void GenInterfaceContextDef(std::ofstream& stream, const Interface& iface);
+  void GenInterfaceDelegateDef(std::ofstream& stream, const Interface& iface,
+      const Declaration& decl);
+  void GenInterfaceCallbackPortCheckDef(std::ofstream& stream,
+      const Interface& iface);
+  void GenInterfaceBaseDef(std::ofstream& stream, const Interface& iface);
+
+  void GenInterfaces(std::ofstream& stream);
+  void GenInterface(std::ofstream& stream, const Interface& iface);
+  void GenInterfaceContextBase(std::ofstream& stream, const Interface& iface);
+  void GenInterfaceDelegateBase(std::ofstream& stream, const Interface& iface,
+      const Declaration& decl);
+  void GenInterfaceMethodHandlerBase(std::ofstream& stream,
+      const Interface& iface, const Declaration& decl);
+  void GenInterfaceMethodTable(std::ofstream& stream, const Interface& iface);
+  void GenInterfaceCallbackPortCheck(std::ofstream& stream,
+      const Interface& iface);
+  void GenInterfaceBase(std::ofstream& stream, const Interface& iface);
+
+  std::string GenMethodEnums(const Interface& iface);
+  std::string GenDelegateEnums(const Interface& iface);
+
+  std::string GenDelegateParams(const Interface& iface,
+      const Declaration& decl);
+  std::string GenDelegateParamsCheck(const Interface& iface,
+      const Declaration& decl);
+  std::string GenMethodHandlerArgsDecl(const Interface& iface,
+      const Declaration& decl);
+  std::string GenMethodUnitMapRead(const Interface& iface,
+      const Declaration& decl);
+  std::string GenMethodHandlerCallbackInvoke(const Declaration& decl);
+  std::string GenMethodUnitMapWriteBase(
+      const Interface& iface, const BaseType& type,
+      const std::string& arg_name, const std::string& arg);
+  std::string GenMethodUnitMapWrite(const Interface& iface,
+      const Declaration& decl);
+  std::string GenDelegateUnitMapWrite(
+    const Interface& iface, const Declaration& decl);
+  std::string GenMethodHandlerArgsFree(const Interface& iface,
+      const Declaration& decl);
+  std::string GenMethodHandlers(const Interface& iface);
+  std::string GenAccessControlSet(const Interface& iface);
+  void GenDelegateDefinition(std::ofstream& stream);
+  void GenDelegateBase(std::ofstream& stream);
+
+ private:
+  std::shared_ptr<Options> options_;
+};
+
+}  // namespace version2
+}  // namespace tidl
+
+#endif  // IDLC_C_GEN_C_STUB_BODY_GENERATOR_HH_
diff --git a/idlc/gen/version2/c_stub_body_generator_cb.hh b/idlc/gen/version2/c_stub_body_generator_cb.hh
new file mode 100644 (file)
index 0000000..64a93da
--- /dev/null
@@ -0,0 +1,1408 @@
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef IDLC_C_GEN_C_STUB_BODY_GENERATOR_CB_H_
+#define IDLC_C_GEN_C_STUB_BODY_GENERATOR_CB_H_
+
+constexpr const char CB_DELEGATE_DEFS[] =
+R"__c_cb(
+typedef struct rpc_port_delegate_s {
+  rpc_port_parcelable_t parcelable;
+  rpc_port_h port;
+  int id;
+  int seq_id;
+  bool once;
+  bool valid;
+} rpc_port_delegate_t;
+
+typedef rpc_port_delegate_t *rpc_port_delegate_h;
+
+static rpc_port_delegate_h rpc_port_delegate_create();
+)__c_cb";
+
+constexpr const char CB_DELEGATE_BASE[] =
+R"__c_cb(
+static void __rpc_port_delegate_to(rpc_port_parcel_h parcel, void *user_data)
+{
+  rpc_port_delegate_h delegate = user_data;
+  rpc_port_unit_map_h map;
+
+  map = rpc_port_unit_map_create();
+  if (map == nullptr) {
+    set_last_result(RPC_PORT_ERROR_OUT_OF_MEMORY);
+    return;
+  }
+
+  rpc_port_unit_map_write_int(map, "id", delegate->id);
+  rpc_port_unit_map_write_int(map, "seq_id", delegate->seq_id);
+  rpc_port_unit_map_write_bool(map, "once", delegate->once);
+  rpc_port_unit_map_write_bool(map, "valid", delegate->valid);
+  rpc_port_parcel_write(parcel, &map->parcelable, map);
+  rpc_port_unit_map_destroy(map);
+  set_last_result(RPC_PORT_ERROR_NONE);
+}
+
+static void __rpc_port_delegate_from(rpc_port_parcel_h parcel, void *user_data)
+{
+  rpc_port_delegate_h delegate = user_data;
+  rpc_port_unit_map_h map;
+
+  map = rpc_port_unit_map_create();
+  if (map == nullptr) {
+    set_last_result(RPC_PORT_ERROR_OUT_OF_MEMORY);
+    return;
+  }
+
+  rpc_port_parcel_read(parcel, &map->parcelable, map);
+  rpc_port_unit_map_read_int(map, "id", &delegate->id);
+  rpc_port_unit_map_read_int(map, "seq_id", &delegate->seq_id);
+  rpc_port_unit_map_read_bool(map, "once", &delegate->once);
+  rpc_port_unit_map_read_bool(map, "valid", &delegate->valid);
+  rpc_port_unit_map_destroy(map);
+  set_last_result(RPC_PORT_ERROR_NONE);
+}
+
+static rpc_port_delegate_h rpc_port_delegate_create()
+{
+  rpc_port_delegate_h delegate;
+
+  delegate = calloc(1, sizeof(rpc_port_delegate_t));
+  if (delegate == nullptr) {
+    _E("malloc() is failed");
+    return nullptr;
+  }
+
+  delegate->parcelable.to = __rpc_port_delegate_to;
+  delegate->parcelable.from = __rpc_port_delegate_from;
+
+  return delegate;
+}
+)__c_cb";
+
+constexpr const char CB_THREAD_ENABLE_DEF[] =
+R"__c_cb(
+#define TIDL_THREAD_ENABLE 1
+)__c_cb";
+
+constexpr const char CB_INTERFACE_METHOD_HANDLER_TYPE[] =
+R"__c_cb(
+typedef int (*rpc_port_stub_method_handler)(rpc_port_h port, rpc_port_parcel_h parcel, rpc_port_unit_map_h map, void *data);
+)__c_cb";
+
+/**
+ * <METHOD_ENUMS> The enumeration declarations of methods.
+ * <PREFIX> The prefix of the interface.
+ * <NAME> The name of the interface.
+ */
+constexpr const char CB_INTERFACE_METHOD_ENUM_BASE[] =
+R"__c_cb(
+typedef enum {
+  <METHOD_ENUMS>
+} <PREFIX>_<NAME>_method_e;
+)__c_cb";
+
+/**
+ * <UPPERCASE_PREFIX> The uppercase prefix of the interface.
+ * <UPPERCASE_NAME> The uppercase name of the interface.
+ * <UPPERCASE_METHOD_NAME> The uppercase method name of the interface.
+ */
+constexpr const char CB_INTERFACE_METHOD_ENUM[] =
+R"__c_cb(
+<UPPERCASE_PREFIX>_<UPPERCASE_NAME>_METHOD_<UPPERCASE_METHOD_NAME>,
+)__c_cb";
+
+/**
+ * <DELEGATE_ENUMS> The enumeration declarations of deleagtes.
+ * <PREFIX> The prefix of the interface.
+ * <NAME> The name of the interface.
+ */
+constexpr const char CB_INTERFACE_DELEGATE_ENUM_BASE[] =
+R"__c_cb(
+typedef enum {
+  <DELEGATE_ENUMS>
+} <PREFIX>_<NAME>_delegate_e;
+)__c_cb";
+
+/**
+ * <UPPERCASE_PREFIX> The uppercase prefix of the interface.
+ * <UPPERCASE_NAME> The uppercase name of the interface.
+ * <UPPERCASE_DELEGATE_NAME> The uppercase delegate name of the interface.
+ * <NUMBER> The number of the delegate.
+ */
+constexpr const char CB_INTERFACE_DELEGATE_ENUM[] =
+R"__c_cb(
+<UPPERCASE_PREFIX>_<UPPERCASE_NAME>_DELEGATE_<UPPERCASE_DELEGATE_NAME> = <NUMBER>,
+)__c_cb";
+
+/**
+ * <PREFIX> The prefix of the interface.
+ * <NAME> The name of the interface.
+ */
+constexpr const char CB_INTERFACE_BASE_DEF[] =
+R"__c_cb(
+typedef struct <PREFIX>_<NAME>_s {
+  rpc_port_stub_h stub;
+  <PREFIX>_<NAME>_callback_s callback;
+  void *user_data;
+  GList* contexts;
+  GList* callback_ports;
+  GRecMutex mutex;
+} <PREFIX>_<NAME>_t;
+
+static <PREFIX>_<NAME>_t __<NAME>;
+)__c_cb";
+
+/**
+ * <PREFIX> The prefix of the interface.
+ * <NAME> The name of the interface.
+ */
+constexpr const char CB_INTERFACE_CONTEXT_DEF[] =
+R"__c_cb(
+typedef struct <PREFIX>_<NAME>_context_s {
+  char *sender;
+  char *instance;
+  rpc_port_h port;
+  rpc_port_h callback_port;
+  void *tag;
+  <PREFIX>_<NAME>_callback_s callback;
+  void *user_data;
+#ifdef TIDL_THREAD_ENABLE
+  GThread *thread;
+  GQueue *queue;
+  GMutex mutex;
+  GCond cond;
+  bool done;
+#endif /* TIDL_THREAD_ENABLE */
+} <PREFIX>_<NAME>_context_t;
+)__c_cb";
+
+/**
+ *
+ */
+constexpr const char CB_INTERFACE_CALLBACK_PORT_CHECK_DEF[] =
+R"__c_cb(
+static bool __<PREFIX>_<NAME>_exist_callback_port(rpc_port_h callback_port);
+)__c_cb";
+
+/**
+ * <PREFIX> The prefix of the interface.
+ * <NAME> The name of the interface.
+ * <DELEGATE_NAME> The name of the delegate of the interface.
+ */
+constexpr const char CB_INTERFACE_DELEGATE_DEF[] =
+R"__c_cb(
+typedef struct <PREFIX>_<NAME>_<DELEGATE_NAME>_s {
+  rpc_port_parcelable_t parcelable;
+  rpc_port_h port;
+  int id;
+  int seq_id;
+  bool once;
+  bool valid;
+} <PREFIX>_<NAME>_<DELEGATE_NAME>_t;
+)__c_cb";
+
+/**
+ * <PREFIX> The prefix of the interface.
+ * <NAME> The name of the interface.
+ */
+constexpr const char CB_INTERFACE_CONTEXT_BASE[] =
+R"__c_cb(
+static int __<PREFIX>_<NAME>_context_handle_request(<PREFIX>_<NAME>_context_h h, rpc_port_parcel_h parcel)
+{
+  int ret = RPC_PORT_ERROR_NONE;
+  int cmd = -1;
+  rpc_port_unit_map_h map;
+
+  map = rpc_port_unit_map_create();
+  if (map == nullptr) {
+    _E("Failed to create unit map");
+    return RPC_PORT_ERROR_OUT_OF_MEMORY;
+  }
+
+  rpc_port_parcel_read(parcel, &map->parcelable, map);
+
+  rpc_port_unit_map_read_int(map, "[METHOD]", &cmd);
+
+  if (cmd > 1 && cmd < ARRAY_SIZE(__<NAME>_method_table)) {
+    if (__<NAME>_method_table[cmd])
+      ret = __<NAME>_method_table[cmd](h->port, parcel, map, h);
+  } else {
+    _W("Invalid protocol. cmd(%d)", cmd);
+    ret = RPC_PORT_ERROR_INVALID_PARAMETER;
+  }
+  rpc_port_unit_map_destroy(map);
+
+  return ret;
+}
+
+#ifdef TIDL_THREAD_ENABLE
+static int __<PREFIX>_<NAME>_context_push(<PREFIX>_<NAME>_context_h h, rpc_port_parcel_h parcel)
+{
+  g_mutex_lock(&h->mutex);
+  g_queue_push_tail(h->queue, parcel);
+  g_cond_signal(&h->cond);
+  g_mutex_unlock(&h->mutex);
+
+  return 0;
+}
+
+static rpc_port_parcel_h __<PREFIX>_<NAME>_context_wait_and_pop(<PREFIX>_<NAME>_context_h h)
+{
+  rpc_port_parcel_h parcel;
+
+  g_mutex_lock(&h->mutex);
+  while (g_queue_is_empty(h->queue) && !h->done)
+    g_cond_wait(&h->cond, &h->mutex);
+
+  parcel = g_queue_pop_head(h->queue);
+  g_mutex_unlock(&h->mutex);
+
+  return parcel;
+}
+
+static gpointer __<PREFIX>_<NAME>_context_thread_cb(gpointer user_data)
+{
+  <PREFIX>_<NAME>_context_h h = user_data;
+  rpc_port_parcel_h parcel;
+
+  _W("START");
+  while (!h->done) {
+    parcel = __<PREFIX>_<NAME>_context_wait_and_pop(h);
+    if (parcel) {
+      __<PREFIX>_<NAME>_context_handle_request(h, parcel);
+      rpc_port_parcel_destroy(parcel);
+    }
+  }
+  _W("END");
+
+  return nullptr;
+}
+#endif /* TIDL_THREAD_ENABLE */
+
+static void __<PREFIX>_<NAME>_context_destroy(gpointer data)
+{
+  <PREFIX>_<NAME>_context_h h = data;
+#ifdef TIDL_THREAD_ENABLE
+  rpc_port_parcel_h parcel;
+#endif /* TIDL_THREAD_ENABLE */
+
+  if (h == nullptr)
+    return;
+
+#ifdef TIDL_THREAD_ENABLE
+  g_mutex_lock(&h->mutex);
+  h->done = true;
+  g_cond_signal(&h->cond);
+  g_mutex_unlock(&h->mutex);
+
+  if (h->thread) {
+    g_thread_join(h->thread);
+    g_thread_unref(h->thread);
+  }
+
+  g_mutex_clear(&h->mutex);
+  g_cond_clear(&h->cond);
+
+  if (h->queue) {
+    while (!g_queue_is_empty(h->queue)) {
+      parcel = g_queue_pop_head(h->queue);
+      rpc_port_parcel_destroy(parcel);
+    }
+
+    g_queue_free(h->queue);
+  }
+#endif /* TIDL_THREAD_ENABLE */
+
+  if (h->instance)
+    free(h->instance);
+
+  if (h->sender)
+    free(h->sender);
+
+  free(h);
+}
+
+static <PREFIX>_<NAME>_context_h __<PREFIX>_<NAME>_context_create(const char *sender, const char *instance, rpc_port_h callback_port)
+{
+  <PREFIX>_<NAME>_context_t *handle;
+
+  if (sender == nullptr || instance == nullptr || callback_port == nullptr) {
+    _E("Invalid parameter");
+    return nullptr;
+  }
+
+  handle = calloc(1, sizeof(<PREFIX>_<NAME>_context_t));
+  if (handle == nullptr) {
+    _E("Out of memory");
+    return nullptr;
+  }
+
+  handle->sender = strdup(sender);
+  if (handle->sender == nullptr) {
+    _E("Failed to duplicate sender");
+    __<PREFIX>_<NAME>_context_destroy(handle);
+    return nullptr;
+  }
+
+  handle->instance = strdup(instance);
+  if (handle->instance == nullptr) {
+    _E("Failed to duplicate instance");
+    __<PREFIX>_<NAME>_context_destroy(handle);
+    return nullptr;
+  }
+
+#ifdef TIDL_THREAD_ENABLE
+  g_mutex_init(&handle->mutex);
+  g_cond_init(&handle->cond);
+
+  handle->queue = g_queue_new();
+  if (handle->queue == nullptr) {
+    _E("Failed to create queue");
+    __<PREFIX>_<NAME>_context_destroy(handle);
+    return nullptr;
+  }
+
+  handle->thread = g_thread_new(instance, __<PREFIX>_<NAME>_context_thread_cb, handle);
+  if (handle->thread == nullptr) {
+    _E("Failed to create thread");
+    __<PREFIX>_<NAME>_context_destroy(handle);
+    return nullptr;
+  }
+#endif /* TIDL_THREAD_ENABLE */
+
+  handle->callback_port = callback_port;
+  handle->callback = __<NAME>.callback;
+  handle->user_data = __<NAME>.user_data;
+
+  return handle;
+}
+
+int <PREFIX>_<NAME>_context_set_tag(<PREFIX>_<NAME>_context_h context, void *tag)
+{
+  if (context == nullptr) {
+    _E("Invalid parameter");
+    return RPC_PORT_ERROR_INVALID_PARAMETER;
+  }
+
+  context->tag = tag;
+
+  return RPC_PORT_ERROR_NONE;
+}
+
+int <PREFIX>_<NAME>_context_get_tag(<PREFIX>_<NAME>_context_h context, void **tag)
+{
+  if (context == nullptr || tag == nullptr) {
+    _E("Invalid parameter");
+    return RPC_PORT_ERROR_INVALID_PARAMETER;
+  }
+
+  *tag = context->tag;
+
+  return RPC_PORT_ERROR_NONE;
+}
+
+int <PREFIX>_<NAME>_context_get_sender(<PREFIX>_<NAME>_context_h context, char **sender)
+{
+  char *value;
+
+  if (context == nullptr || sender == nullptr) {
+    _E("Invalid parameter");
+    return RPC_PORT_ERROR_INVALID_PARAMETER;
+  }
+
+  value = strdup(context->sender);
+  if (value == nullptr) {
+    _E("Failed to duplicate sender");
+    return RPC_PORT_ERROR_OUT_OF_MEMORY;
+  }
+
+  *sender = value;
+
+  return RPC_PORT_ERROR_NONE;
+}
+
+int <PREFIX>_<NAME>_context_get_instance(<PREFIX>_<NAME>_context_h context, char **instance)
+{
+  char *value;
+
+  if (context == nullptr || instance == nullptr) {
+    _E("Invalid parameter");
+    return RPC_PORT_ERROR_INVALID_PARAMETER;
+  }
+
+  value = strdup(context->instance);
+  if (value == nullptr) {
+    _E("Failed to duplicate instance");
+    return RPC_PORT_ERROR_OUT_OF_MEMORY;
+  }
+
+  *instance = value;
+
+  return RPC_PORT_ERROR_NONE;
+}
+
+int <PREFIX>_<NAME>_context_disconnect(<PREFIX>_<NAME>_context_h context)
+{
+  int ret;
+
+  if (context == nullptr) {
+    _E("Invalid parameter");
+    return RPC_PORT_ERROR_INVALID_PARAMETER;
+  }
+
+  g_rec_mutex_lock(&__<NAME>.mutex);
+
+  ret = rpc_port_disconnect(context->callback_port);
+  if (ret != RPC_PORT_ERROR_NONE)
+    _E("Failed to disconnect. error(%d)", ret);
+
+  g_rec_mutex_unlock(&__<NAME>.mutex);
+
+  return ret;
+}
+
+static <PREFIX>_<NAME>_context_h __<PREFIX>_<NAME>_find_context(const char *instance)
+{
+  <PREFIX>_<NAME>_context_h context;
+  GList *iter;
+
+  g_rec_mutex_lock(&__<NAME>.mutex);
+  iter = __<NAME>.contexts;
+  while (iter) {
+    context = iter->data;
+    if (!strcmp(context->instance, instance)) {
+      g_rec_mutex_unlock(&__<NAME>.mutex);
+      return context;
+    }
+
+    iter = g_list_next(iter);
+  }
+  g_rec_mutex_unlock(&__<NAME>.mutex);
+
+  return nullptr;
+}
+
+static void __<PREFIX>_<NAME>_add_context(<PREFIX>_<NAME>_context_h context)
+{
+  g_rec_mutex_lock(&__<NAME>.mutex);
+  __<NAME>.contexts = g_list_append(__<NAME>.contexts, context);
+  g_rec_mutex_unlock(&__<NAME>.mutex);
+}
+
+static void __<PREFIX>_<NAME>_remove_context(<PREFIX>_<NAME>_context_h context)
+{
+  g_rec_mutex_lock(&__<NAME>.mutex);
+  __<NAME>.contexts = g_list_remove(__<NAME>.contexts, context);
+  g_rec_mutex_unlock(&__<NAME>.mutex);
+}
+)__c_cb";
+
+/**
+ * <PREFIX> The prefix of the interface.
+ * <NAME> The name of the interface.
+ * <DELEGATE_NAME> The name of the delegate of the interface.
+ * <DELEGATE_PARAMS> The parameters of the delegate.
+ * <DELEGATE_PARAMS_CHECK> The implementation to check whether arguments are nullptr or not
+ * <DELEGATE_ENUM_VALUE> The enumeration value of the method.
+ * <DELEGATE_PARCEL_WRITE> The implementation to write arguments to the parcel.
+ * <UPPERCASE_PREFIX> The uppercase prefix of the interface.
+ * <UPPERCASE_NAME> The uppercase name of the interface.
+ */
+constexpr const char CB_INTERFACE_DELEGATE_BASE[] =
+R"__c_cb(
+static void __<PREFIX>_<NAME>_<DELEGATE_NAME>_to(rpc_port_parcel_h parcel, void *user_data)
+{
+ <PREFIX>_<NAME>_<DELEGATE_NAME>_h h = user_data;
+  rpc_port_unit_map_h map;
+
+  if (parcel == nullptr || h == nullptr) {
+    _E("Invalid parameter");
+    set_last_result(RPC_PORT_ERROR_INVALID_PARAMETER);
+    return;
+  }
+
+  map = rpc_port_unit_map_create();
+  if (map == nullptr) {
+    _E("Failed to create unit map");
+    set_last_result(RPC_PORT_ERROR_OUT_OF_MEMORY);
+    return;
+  }
+
+  rpc_port_unit_map_write_int(map, "id", h->id);
+  rpc_port_unit_map_write_int(map, "seq_id", h->seq_id);
+  rpc_port_unit_map_write_bool(map, "once", h->once);
+
+  rpc_port_parcel_write(parcel, &map->parcelable, map);
+  rpc_port_unit_map_destroy(map);
+
+  _I("id(%d), seq_id(%d), once(%s)", h->id, h->seq_id, h->once ? "true" : "false");
+  set_last_result(RPC_PORT_ERROR_NONE);
+}
+
+static void __<PREFIX>_<NAME>_<DELEGATE_NAME>_from(rpc_port_parcel_h parcel, void *user_data)
+{
+  <PREFIX>_<NAME>_<DELEGATE_NAME>_h h = user_data;
+  rpc_port_unit_map_h map;
+  int ret;
+
+  if (parcel == nullptr || h == nullptr) {
+    _E("Invalid parameter");
+    set_last_result(RPC_PORT_ERROR_INVALID_PARAMETER);
+    return;
+  }
+
+  map = rpc_port_unit_map_create();
+  if (map == nullptr) {
+    _E("Failed to create unit map");
+    set_last_result(RPC_PORT_ERROR_OUT_OF_MEMORY);
+    return;
+  }
+
+  rpc_port_parcel_read(parcel, &map->parcelable, map);
+
+  ret = rpc_port_unit_map_read_int(map, "id", &h->id);
+  if (ret != RPC_PORT_ERROR_NONE) {
+    _E("Failed to read id. error(%d)", ret);
+    rpc_port_unit_map_destroy(map);
+    set_last_result(ret);
+    return;
+  }
+
+  ret = rpc_port_unit_map_read_int(map, "seq_id", &h->seq_id);
+  if (ret != RPC_PORT_ERROR_NONE) {
+    _E("Failed to read seq_id. error(%d)", ret);
+    rpc_port_unit_map_destroy(map);
+    set_last_result(ret);
+    return;
+  }
+
+  ret = rpc_port_unit_map_read_bool(map, "once", &h->once);
+  rpc_port_unit_map_destroy(map);
+
+  _I("id(%d), seq_id(%d), once(%s)", h->id, h->seq_id, h->once ? "true" : "false");
+  set_last_result(ret);
+}
+
+int <PREFIX>_<NAME>_<DELEGATE_NAME>_create(<PREFIX>_<NAME>_<DELEGATE_NAME>_h *h)
+{
+  <PREFIX>_<NAME>_<DELEGATE_NAME>_t *handle;
+  static int seq_num;
+
+  if (h == nullptr) {
+    _E("Invalid parameter");
+    return RPC_PORT_ERROR_INVALID_PARAMETER;
+  }
+
+  handle = calloc(1, sizeof(<PREFIX>_<NAME>_<DELEGATE_NAME>_t));
+  if (handle == nullptr) {
+    _E("Out of memory");
+    return RPC_PORT_ERROR_OUT_OF_MEMORY;
+  }
+
+  handle->parcelable.to = __<PREFIX>_<NAME>_<DELEGATE_NAME>_to;
+  handle->parcelable.from = __<PREFIX>_<NAME>_<DELEGATE_NAME>_from;
+  handle->id = <DELEGATE_ENUM_VALUE>;
+  handle->seq_id = g_atomic_int_add(&seq_num, 1) + 1;
+  handle->once = false;
+  handle->valid = true;
+  _I("id(%d), seq_id(%d)", handle->id, handle->seq_id);
+
+  *h = handle;
+
+  return RPC_PORT_ERROR_NONE;
+}
+
+int <PREFIX>_<NAME>_<DELEGATE_NAME>_destroy(<PREFIX>_<NAME>_<DELEGATE_NAME>_h h)
+{
+  if (h == nullptr) {
+    _E("Invalid parameter");
+    return RPC_PORT_ERROR_INVALID_PARAMETER;
+  }
+
+  _W("id(%d), seq_id(%d), once(%s)", h->id, h->seq_id, h->once ? "true" : "false");
+
+  free(h);
+
+  return RPC_PORT_ERROR_NONE;
+}
+
+int <PREFIX>_<NAME>_<DELEGATE_NAME>_clone(<PREFIX>_<NAME>_<DELEGATE_NAME>_h h, <PREFIX>_<NAME>_<DELEGATE_NAME>_h *clone)
+{
+  rpc_port_unit_map_h map;
+  int ret;
+
+  if (h == nullptr || clone == nullptr) {
+    _E("Invalid parameter");
+    return RPC_PORT_ERROR_INVALID_PARAMETER;
+  }
+
+  map = rpc_port_unit_map_create();
+  if (map == nullptr) {
+    _E("Failed to create unit map");
+    return RPC_PORT_ERROR_OUT_OF_MEMORY;
+  }
+
+  ret = rpc_port_unit_map_write_<NAME>_<DELEGATE_NAME>(map, "clone", h);
+  if (ret != RPC_PORT_ERROR_NONE) {
+    _E("Failed to write <DELEGATE_NAME>. error(%d)", ret);
+    rpc_port_unit_map_destroy(map);
+    return ret;
+  }
+
+  ret = rpc_port_unit_map_read_<NAME>_<DELEGATE_NAME>(map, "clone", clone);
+  rpc_port_unit_map_destroy(map);
+
+  (*clone)->port = h->port;
+
+  return ret;
+}
+
+int <PREFIX>_<NAME>_<DELEGATE_NAME>_get_id(<PREFIX>_<NAME>_<DELEGATE_NAME>_h h, int *id)
+{
+  if (h == nullptr || id == nullptr) {
+    _E("Invalid parameter");
+    return RPC_PORT_ERROR_INVALID_PARAMETER;
+  }
+
+  *id = h->id;
+
+  return RPC_PORT_ERROR_NONE;
+}
+
+int <PREFIX>_<NAME>_<DELEGATE_NAME>_get_seq_id(<PREFIX>_<NAME>_<DELEGATE_NAME>_h h, int *seq_id)
+{
+  if (h == nullptr || seq_id == nullptr) {
+    _E("Invalid parameter");
+    return RPC_PORT_ERROR_INVALID_PARAMETER;
+  }
+
+  *seq_id = h->seq_id;
+
+  return RPC_PORT_ERROR_NONE;
+}
+
+int <PREFIX>_<NAME>_<DELEGATE_NAME>_is_once(<PREFIX>_<NAME>_<DELEGATE_NAME>_h h, bool *once)
+{
+  if (h == nullptr || once == nullptr) {
+    _E("Invalid parameter");
+    return RPC_PORT_ERROR_INVALID_PARAMETER;
+  }
+
+  *once = h->once;
+
+  return RPC_PORT_ERROR_NONE;
+}
+
+int <PREFIX>_<NAME>_<DELEGATE_NAME>_get_tag(<PREFIX>_<NAME>_<DELEGATE_NAME>_h h, char **tag)
+{
+  char *value;
+  char buf[128];
+
+  if (h == nullptr || tag == nullptr) {
+    _E("Invalid parameter");
+    return RPC_PORT_ERROR_INVALID_PARAMETER;
+  }
+
+  snprintf(buf, sizeof(buf), "%d::%d", h->id, h->seq_id);
+  value = strdup(buf);
+  if (value == nullptr) {
+    _E("Out of memory");
+    return RPC_PORT_ERROR_OUT_OF_MEMORY;
+  }
+
+  *tag = value;
+
+  return RPC_PORT_ERROR_NONE;
+}
+
+int <PREFIX>_<NAME>_<DELEGATE_NAME>_set_port(<PREFIX>_<NAME>_<DELEGATE_NAME>_h h, rpc_port_h port)
+{
+  if (h == nullptr || port == nullptr) {
+    _E("Invalid parameter");
+    return RPC_PORT_ERROR_INVALID_PARAMETER;
+  }
+
+  h->port = port;
+
+  return RPC_PORT_ERROR_NONE;
+}
+
+int <PREFIX>_<NAME>_<DELEGATE_NAME>_invoke(<PREFIX>_<NAME>_<DELEGATE_NAME>_h h<DELEGATE_PARAMS>)
+{
+  rpc_port_parcel_h parcel_;
+  int ret_;
+  rpc_port_unit_map_h map_;
+
+  if (h == nullptr || h->port == nullptr<DELEGATE_PARAMS_CHECK>) {
+    _E("Invalid parameter");
+    return RPC_PORT_ERROR_INVALID_PARAMETER;
+  }
+
+  if (!__<PREFIX>_<NAME>_exist_callback_port(h->port)) {
+    _E("Not connected");
+    return RPC_PORT_ERROR_INVALID_PARAMETER;
+  }
+
+  if (h->once && !h->valid) {
+    _E("The delegate handle is already used");
+    return RPC_PORT_ERROR_INVALID_PARAMETER;
+  }
+
+  ret_ = rpc_port_parcel_create(&parcel_);
+  if (ret_ != RPC_PORT_ERROR_NONE) {
+    _E("Failed to create parcel handle. error(%d)", ret_);
+    return ret_;
+  }
+
+  map_ = rpc_port_unit_map_create();
+  if (map_ == nullptr) {
+    _E("Failed to create unit map");
+    rpc_port_parcel_destroy(parcel_);
+    set_last_result(RPC_PORT_ERROR_OUT_OF_MEMORY);
+    return ret_;
+  }
+
+  rpc_port_unit_map_write_int(map_, "[METHOD]", <UPPERCASE_PREFIX>_<UPPERCASE_NAME>_METHOD_CALLBACK_);
+
+  rpc_port_unit_map_write_delegate(map_, "delegate", (rpc_port_delegate_h)h);
+
+  <DELEGATE_UNIT_MAP_WRITE>
+  rpc_port_parcel_write(parcel_, &map_->parcelable, map_);
+
+  rpc_port_unit_map_destroy(map_);
+  ret_ = rpc_port_parcel_send(parcel_, h->port);
+  rpc_port_parcel_destroy(parcel_);
+  h->valid = false;
+
+  return ret_;
+}
+)__c_cb";
+
+
+/*
+ * <ARG> The argument.
+ */
+constexpr const char CB_INTERFACE_METHOD_DELEGATE_UNIT_MAP_WRITE[] =
+R"__c_cb(
+rpc_port_unit_map_write_delegate(map_, "<ARG_NAME>", (rpc_port_delegate_h)<ARG>);
+)__c_cb";
+
+
+/**
+ * <TYPE_NAME> The type name of the argument.
+ * <ARG> The argument.
+ */
+constexpr const char CB_INTERFACE_METHOD_USER_DEFINED_UNIT_MAP_WRITE[] =
+R"__c_cb(
+rpc_port_unit_map_write_<TYPE_NAME>(map_, "<ARG_NAME>", <ARG>);
+)__c_cb";
+
+/**
+ * <ARG> The argument.
+ */
+constexpr const char CB_INTERFACE_METHOD_BUNDLE_UNIT_MAP_WRITE[] =
+R"__c_cb(
+rpc_port_unit_map_write_bundle(map_, "<ARG_NAME>", <ARG>);
+)__c_cb";
+
+/**
+ * <ARG> The argument.
+ */
+constexpr const char CB_INTERFACE_METHOD_STRING_UNIT_MAP_WRITE[] =
+R"__c_cb(
+rpc_port_unit_map_write_string(map_, "<ARG_NAME>", <ARG>);
+)__c_cb";
+
+/**
+ * <TYPE_NAME> The type name of the argument.
+ * <ARG> The argument.
+ */
+constexpr const char CB_INTERFACE_METHOD_BASE_UNIT_MAP_WRITE[] =
+R"__c_cb(
+rpc_port_unit_map_write_<TYPE_NAME>(map_, "<ARG_NAME>", <ARG>);
+)__c_cb";
+
+/**
+ * <TYPE_NAME> The type name of the argument.
+ * <ARG_NAME> The argument name.
+ * <ARG> The argument.
+ */
+constexpr const char CB_INTERFACE_METHOD_USER_DEFINED_UNIT_MAP_READ[] =
+R"__c_cb(
+ret_ = rpc_port_unit_map_read_<TYPE_NAME>(map, "<ARG_NAME>", &<ARG>);
+if (ret_ != RPC_PORT_ERROR_NONE) {
+  _E("Failed to read <TYPE_NAME>. error(%d)", ret_);
+  goto out;
+}
+)__c_cb";
+
+/**
+ * <ARG_NAME> The argument name.
+ * <ARG> The argument.
+ */
+constexpr const char CB_INTERFACE_METHOD_BUNDLE_UNIT_MAP_READ[] =
+R"__c_cb(
+ret_ = rpc_port_unit_map_read_bundle(map, "<ARG_NAME>", &<ARG>);
+if (ret_ != RPC_PORT_ERROR_NONE) {
+  _E("Failed to read bundle. error(%d)", ret_);
+  goto out;
+}
+)__c_cb";
+
+/**
+ * <ARG_NAME> The argument name.
+ * <ARG> The argument.
+ */
+constexpr const char CB_INTERFACE_METHOD_STRING_UNIT_MAP_READ[] =
+R"__c_cb(
+ret_ = rpc_port_unit_map_read_string(map, "<ARG_NAME>", &<ARG>);
+if (ret_ != RPC_PORT_ERROR_NONE) {
+  _E("Failed to read string. error(%d)", ret_);
+  goto out;
+}
+)__c_cb";
+
+/*
+ * <ARG> The argument.
+ */
+constexpr const char CB_INTERFACE_METHOD_DELEGATE_UNIT_MAP_READ[] =
+R"__c_cb(
+ret_ = rpc_port_unit_map_read_delegate(map, "<ARG>", (rpc_port_delegate_h *)&<ARG>);
+if (ret_ != RPC_PORT_ERROR_NONE) {
+  _E("Failed to read delegate. error(%d)", ret_);
+  goto out;
+}
+<PREFIX>_<TYPE_NAME>_set_port(<ARG>, callback_port_);
+
+)__c_cb";
+
+
+/**
+ * <TYPE_NAME> The type name of the argument.
+ * <ARG_NAME> The argument name.
+ * <ARG> The argument.
+ */
+constexpr const char CB_INTERFACE_METHOD_BASE_UNIT_MAP_READ[] =
+R"__c_cb(
+ret_ = rpc_port_unit_map_read_<TYPE_NAME>(map, "<ARG_NAME>", &<ARG>);
+if (ret_ != RPC_PORT_ERROR_NONE) {
+  _E("Failed to read <TYPE_NAME>. error(%d)", ret_);
+  goto out;
+}
+)__c_cb";
+
+
+/**
+ * <PREFIX> The prefix of the interface.
+ * <NAME> The name of the interface.
+ * <METHOD_NAME> The method name of the interface.
+ * <METHOD_HANDLER_ARGS_DECL> The declarations for arguments of the method.
+ * <METHOD_HANDLER_PARCEL_READ> The implementation to read the parameter from the parcel.
+ * <METHOD_HANDLER_CALLBACK_INVOKE> The implementation to invoke the callback function of the method.
+ * <METHOD_HANDLER_PARCEL_WRITE> The implementation to write the result to the parcel.
+ * <METHOD_HANDLER_ARGS_FREE> The implementation to release arguments.
+ */
+constexpr const char CB_INTERFACE_METHOD_HANDLER_BASE[] =
+R"__c_cb(
+static int __<PREFIX>_<NAME>_method_<METHOD_NAME>_handler(rpc_port_h port, rpc_port_parcel_h parcel, rpc_port_unit_map_h map, void *user_data)
+{
+  <PREFIX>_<NAME>_context_h context_ = user_data;
+  rpc_port_parcel_header_h header_;
+  int seq_num_ = -1;
+  rpc_port_h callback_port_;
+  int ret_;
+
+  <METHOD_HANDLER_ARGS_DECL>
+
+  ret_ = rpc_port_stub_get_port(__<NAME>.stub, RPC_PORT_PORT_CALLBACK, context_->instance, &callback_port_);
+  if (ret_ != RPC_PORT_ERROR_NONE) {
+    _E("Failed to get callback port. error(%d)", ret_);
+    goto out;
+  }
+
+  rpc_port_parcel_get_header(parcel, &header_);
+  rpc_port_parcel_header_get_seq_num(header_, &seq_num_);
+
+  <METHOD_UNIT_MAP_READ>
+  <METHOD_HANDLER_CALLBACK_INVOKE>
+  <METHOD_UNIT_MAP_WRITE>
+
+out:
+  <METHOD_HANDLER_ARGS_FREE>
+
+  return ret_;
+}
+)__c_cb";
+
+/**
+ * <ARG> The argument.
+ * <PREFIX> The prefix of the interface.
+ * <NAME> The name of the interface
+ */
+constexpr const char CB_INTERFACE_METHOD_DELEGATE_PARCEL_READ[] =
+R"__c_cb(
+ret_ = <PREFIX>_<NAME>_create(&<ARG>);
+if (ret_ != RPC_PORT_ERROR_NONE) {
+  _E("Failed to create handle. error(%d)", ret_);
+  goto out;
+}
+
+<PREFIX>_<NAME>_set_port(<ARG>, callback_port_);
+rpc_port_parcel_read(parcel, &<ARG>->parcelable, <ARG>);
+ret_ = get_last_result();
+if (ret_ != RPC_PORT_ERROR_NONE) {
+  _E("Failed to read data. error(%d)", ret_);
+  goto out;
+}
+)__c_cb";
+
+/**
+ * <ARG> The name of the value.
+ * <PREFIX> The prefix of the structure.
+ * <NAME> The name of the structure.
+ */
+constexpr const char CB_INTERFACE_METHOD_USER_DEFINED_PARCEL_READ[] =
+R"__c_cb(
+ret_ = <PREFIX>_<NAME>_create(&<ARG>);
+if (ret_ != RPC_PORT_ERROR_NONE) {
+  _E("Failed to create handle. error(%d)", ret_);
+  goto out;
+}
+
+rpc_port_parcel_read(parcel, &<ARG>->parcelable, <ARG>);
+ret_ = get_last_result();
+if (ret_ != RPC_PORT_ERROR_NONE) {
+  _E("Failed to read data. error(%d)", ret_);
+  goto out;
+}
+)__c_cb";
+
+/**
+ * <ARG> The name of the value.
+ */
+constexpr const char CB_INTERFACE_METHOD_BUNDLE_PARCEL_READ[] =
+R"__c_cb(
+rpc_port_parcel_read_bundle(parcel, &<ARG>);
+if (<ARG> == nullptr) {
+  _E("Failed to read data");
+  ret_ = RPC_PORT_ERROR_OUT_OF_MEMORY;
+  goto out;
+}
+)__c_cb";
+
+/**
+ * <ARG> The name of the value.
+ */
+constexpr const char CB_INTERFACE_METHOD_STRING_PARCEL_READ[] =
+R"__c_cb(
+rpc_port_parcel_read_string(parcel, &<ARG>);
+if (<ARG> == nullptr) {
+  _E("Failed to read data");
+  ret_ = RPC_PORT_ERROR_OUT_OF_MEMORY;
+  goto out;
+}
+)__c_cb";
+
+/**
+ * <PARCEL_TYPE> The type of the parcel.
+ * <ARG> The name of the value.
+ */
+constexpr const char CB_INTERFACE_METHOD_BASE_PARCEL_READ[] =
+R"__c_cb(
+rpc_port_parcel_read_<PARCEL_TYPE>(parcel, &<ARG>);
+)__c_cb";
+
+/**
+ * <RES_SET> The implemention to set the result of the callback function.
+ * <METHOD_NAME> The name of the method of the interface.
+ * <METHOD_ARGS> The arguments of the method.
+ */
+constexpr const char CB_INTERFACE_METHOD_CALLBACK_INVOKE[] =
+R"__c_cb(
+if (context_->callback.<METHOD_NAME>)
+  <RES_SET>context_->callback.<METHOD_NAME>(context_<METHOD_ARGS>, context_->user_data);
+)__c_cb";
+
+/**
+ * <UPPERCASE_PREFIX> The uppercase prefix of the interface.
+ * <UPPERCASE_NAME> The uppercase name of the interface.
+ */
+constexpr const char CB_INTERFACE_METHOD_PARCEL_WRITE_PRE[] =
+R"__c_cb(
+ret_ = rpc_port_parcel_create(&parcel_);
+if (ret_ != RPC_PORT_ERROR_NONE) {
+  _E("Failed to create parcel handle. error(%d)", ret_);
+  goto out;
+}
+
+rpc_port_parcel_get_header(parcel_, &header_);
+rpc_port_parcel_header_set_tag(header_, TIDL_VERSION);
+rpc_port_parcel_header_set_seq_num(header_, seq_num_);
+
+map_ = rpc_port_unit_map_create();
+if (map_ == nullptr) {
+  _E("Failed to create unit map");
+  rpc_port_parcel_destroy(parcel_);
+  ret_ = RPC_PORT_ERROR_OUT_OF_MEMORY;
+  goto out;
+}
+
+rpc_port_unit_map_write_int(map_, "[METHOD]",  <UPPERCASE_PREFIX>_<UPPERCASE_NAME>_METHOD_RESULT_);
+)__c_cb";
+
+constexpr const char CB_INTERFACE_METHOD_PARCEL_WRITE_POST[] =
+R"__c_cb(
+
+rpc_port_parcel_write(parcel_, &map_->parcelable, map_);
+rpc_port_unit_map_destroy(map_);
+
+ret_ = rpc_port_parcel_send(parcel_, port);
+rpc_port_parcel_destroy(parcel_);
+
+)__c_cb";
+
+/**
+ * <ARG> The argument.
+ * <PREFIX> The prefix of the structure.
+ * <NAME> The name of the structure.
+ */
+constexpr const char CB_INTERFACE_METHOD_USER_DEFINED_FREE[] =
+R"__c_cb(
+if (<ARG>)
+  <PREFIX>_<NAME>_destroy(<ARG>);
+)__c_cb";
+
+/**
+ * <ARG> The argument.
+ */
+constexpr const char CB_INTERFACE_METHOD_BUNDLE_FREE[] =
+R"__c_cb(
+if (<ARG>)
+  bundle_free(<ARG>);
+)__c_cb";
+
+/**
+ * <ARG> The argument.
+ */
+constexpr const char CB_INTERFACE_METHOD_STRING_FREE[] =
+R"__c_cb(
+if (<ARG>)
+  free(<ARG>);
+)__c_cb";
+
+/**
+ * <NAME> The name of the interface.
+ * <METHOD_HANDLERS> The declarations of method handlers.
+ */
+constexpr const char CB_INTERFACE_METHOD_TABLE[] =
+R"__c_cb(
+static rpc_port_stub_method_handler __<NAME>_method_table[] = {
+  <METHOD_HANDLERS>
+};
+)__c_cb";
+
+/**
+ * <ENUM_VALUE> The enumeration value of the method.
+ * <PREFIX> The prefix of the interface.
+ * <NAME> The name of the interface.
+ * <METHOD_NAME> The method name of the interface.
+ */
+constexpr const char CB_INTERFACE_METHOD_HANDLER[] =
+R"__c_cb(
+[<ENUM_VALUE>] = __<PREFIX>_<NAME>_method_<METHOD_NAME>_handler,
+)__c_cb";
+
+/**
+ * <PREFIX> The prefix of the interface.
+ * <NAME> The name of the interface.
+ * <ACCESS_CONTROL_SET> The implmentation to set the access control the stub handle.
+ */
+constexpr const char CB_INTERFACE_BASE[] =
+R"__c_cb(
+static void __<PREFIX>_<NAME>_add_callback_port(rpc_port_h callback_port)
+{
+  g_rec_mutex_lock(&__<NAME>.mutex);
+  __<NAME>.callback_ports = g_list_append(__<NAME>.callback_ports, callback_port);
+  g_rec_mutex_unlock(&__<NAME>.mutex);
+}
+
+static void __<PREFIX>_<NAME>_remove_callback_port(rpc_port_h callback_port)
+{
+  g_rec_mutex_lock(&__<NAME>.mutex);
+  __<NAME>.callback_ports = g_list_remove(__<NAME>.callback_ports, callback_port);
+  g_rec_mutex_unlock(&__<NAME>.mutex);
+}
+
+static void __<PREFIX>_<NAME>_connected_event_cb(const char *sender, const char *instance, void *user_data)
+{
+  <PREFIX>_<NAME>_context_h context;
+  rpc_port_h callback_port = nullptr;
+  int ret;
+
+  _W("sender(%s), instance(%s)", sender, instance);
+  ret = rpc_port_stub_get_port(__<NAME>.stub, RPC_PORT_PORT_CALLBACK, instance, &callback_port);
+  if (ret != RPC_PORT_ERROR_NONE) {
+    _E("Failed to get callback port. error(%d)", ret);
+    return;
+  }
+
+  context = __<PREFIX>_<NAME>_context_create(sender, instance, callback_port);
+  if (context == nullptr)
+    return;
+
+  __<PREFIX>_<NAME>_add_context(context);
+  __<PREFIX>_<NAME>_add_callback_port(context->callback_port);
+  context->callback.create(context, context->user_data);
+}
+
+static void __<PREFIX>_<NAME>_disconnected_event_cb(const char *sender, const char *instance, void *user_data)
+{
+  <PREFIX>_<NAME>_context_h context;
+
+
+  _W("sender(%s), instance(%s)", sender, instance);
+  context = __<PREFIX>_<NAME>_find_context(instance);
+  if (context == nullptr)
+    return;
+
+  __<PREFIX>_<NAME>_remove_callback_port(context->callback_port);
+  context->callback.terminate(context, context->user_data);
+  __<PREFIX>_<NAME>_remove_context(context);
+  __<PREFIX>_<NAME>_context_destroy(context);
+}
+
+static int __<PREFIX>_<NAME>_received_event_cb(const char *sender, const char *instance, rpc_port_h port, void *user_data)
+{
+  <PREFIX>_<NAME>_context_h context;
+  rpc_port_parcel_h parcel;
+  int ret;
+
+  _W("sender(%s), instance(%s)", sender, instance);
+  context = __<PREFIX>_<NAME>_find_context(instance);
+  if (context == nullptr) {
+    _E("Failed to find context. instance(%s)", instance);
+    return RPC_PORT_ERROR_INVALID_PARAMETER;
+  }
+
+  context->port = port;
+  ret = rpc_port_parcel_create_from_port(&parcel, port);
+  if (ret != RPC_PORT_ERROR_NONE) {
+    _E("Failed to create parcel handle from port. error(%d)", ret);
+    return ret;
+  }
+
+#ifdef TIDL_THREAD_ENABLE
+  ret = __<PREFIX>_<NAME>_context_push(context, parcel);
+#else
+  ret = __<PREFIX>_<NAME>_context_handle_request(context, parcel);
+  rpc_port_parcel_destroy(parcel);
+#endif /* TIDL_THREAD_ENABLE */
+
+  return ret;
+}
+
+static int __<PREFIX>_<NAME>_set_access_control(void)
+{
+  int ret = RPC_PORT_ERROR_NONE;
+
+  <ACCESS_CONTROL_SET>
+
+  return ret;
+}
+
+int <PREFIX>_<NAME>_register(<PREFIX>_<NAME>_callback_s *callback, void *user_data)
+{
+  int ret;
+
+  if (callback == nullptr || callback->create == nullptr || callback->terminate == nullptr) {
+    _E("Invalid parameter");
+    return RPC_PORT_ERROR_INVALID_PARAMETER;
+  }
+
+  if (__<NAME>.stub) {
+    _E("Already exists");
+    return RPC_PORT_ERROR_NONE;
+  }
+
+  g_rec_mutex_init(&__<NAME>.mutex);
+  __<NAME>.callback = *callback;
+  __<NAME>.user_data = user_data;
+
+  ret = rpc_port_stub_create(&__<NAME>.stub, "<NAME>");
+  if (ret != RPC_PORT_ERROR_NONE) {
+    _E("Failed to create stub handle. error(%d)", ret);
+    g_rec_mutex_clear(&__<NAME>.mutex);
+    return ret;
+  }
+
+  ret = rpc_port_stub_add_received_event_cb(__<NAME>.stub, __<PREFIX>_<NAME>_received_event_cb, &__<NAME>);
+  if (ret != RPC_PORT_ERROR_NONE) {
+    _E("Failed to add received event callback");
+    <PREFIX>_<NAME>_unregister();
+    return ret;
+  }
+
+  ret = rpc_port_stub_add_connected_event_cb(__<NAME>.stub, __<PREFIX>_<NAME>_connected_event_cb, &__<NAME>);
+  if (ret != RPC_PORT_ERROR_NONE) {
+    _E("Failed to add connected event callback");
+    <PREFIX>_<NAME>_unregister();
+    return ret;
+  }
+
+  ret = rpc_port_stub_add_disconnected_event_cb(__<NAME>.stub, __<PREFIX>_<NAME>_disconnected_event_cb, &__<NAME>);
+  if (ret != RPC_PORT_ERROR_NONE) {
+    _E("Failed to add disconnected event callback");
+    <PREFIX>_<NAME>_unregister();
+    return ret;
+  }
+
+  ret = __<PREFIX>_<NAME>_set_access_control();
+  if (ret != RPC_PORT_ERROR_NONE) {
+    _E("Failed to add privileges");
+    <PREFIX>_<NAME>_unregister();
+    return ret;
+  }
+
+  ret = rpc_port_stub_listen(__<NAME>.stub);
+  if (ret != RPC_PORT_ERROR_NONE) {
+    _E("Failed to listen events. error(%d)", ret);
+    <PREFIX>_<NAME>_unregister();
+    return ret;
+  }
+
+  return RPC_PORT_ERROR_NONE;
+}
+
+int <PREFIX>_<NAME>_unregister(void)
+{
+  if (__<NAME>.stub == nullptr)
+    return RPC_PORT_ERROR_NONE;
+
+  g_rec_mutex_lock(&__<NAME>.mutex);
+  g_rec_mutex_unlock(&__<NAME>.mutex);
+  g_rec_mutex_clear(&__<NAME>.mutex);
+
+  if (__<NAME>.contexts) {
+    g_list_free_full(__<NAME>.contexts, __<PREFIX>_<NAME>_context_destroy);
+    __<NAME>.contexts = nullptr;
+  }
+
+  if (__<NAME>.stub) {
+    rpc_port_stub_destroy(__<NAME>.stub);
+    __<NAME>.stub = nullptr;
+  }
+
+  return RPC_PORT_ERROR_NONE;
+}
+
+int <PREFIX>_<NAME>_foreach_context(<PREFIX>_<NAME>_context_cb callback, void *user_data)
+{
+  <PREFIX>_<NAME>_context_h context;
+  GList *iter;
+
+  if (callback == nullptr) {
+    _E("Invalid parameter");
+    return RPC_PORT_ERROR_INVALID_PARAMETER;
+  }
+
+  g_rec_mutex_lock(&__<NAME>.mutex);
+  iter = __<NAME>.contexts;
+  while (iter) {
+    context = iter->data;
+    if (!callback(context, user_data))
+      break;
+
+    iter = g_list_next(iter);
+  }
+  g_rec_mutex_unlock(&__<NAME>.mutex);
+
+  return RPC_PORT_ERROR_NONE;
+}
+
+int <PREFIX>_<NAME>_get_client_number(unsigned int *client_number)
+{
+  if (client_number == nullptr) {
+    _E("Invalid parameter");
+    return RPC_PORT_ERROR_INVALID_PARAMETER;
+  }
+
+  if (__<NAME>.stub == nullptr) {
+    _E("Invalid context");
+    return RPC_PORT_ERROR_INVALID_PARAMETER;
+  }
+
+  g_rec_mutex_lock(&__<NAME>.mutex);
+  *client_number = g_list_length(__<NAME>.contexts);
+  g_rec_mutex_unlock(&__<NAME>.mutex);
+
+  return RPC_PORT_ERROR_NONE;
+}
+)__c_cb";
+
+/**
+ * <PREFIX> The prefix of the interface.
+ * <NAME> The name of the interface.
+ */
+constexpr const char CB_INTERFACE_CALLBACK_PORT_CHECK[] =
+R"__c_cb(
+static bool __<PREFIX>_<NAME>_exist_callback_port(rpc_port_h callback_port)
+{
+  rpc_port_h port;
+  GList *iter;
+
+  g_rec_mutex_lock(&__<NAME>.mutex);
+  iter = __<NAME>.callback_ports;
+  while (iter) {
+    port = iter->data;
+    if (port == callback_port) {
+      g_rec_mutex_unlock(&__<NAME>.mutex);
+      return true;
+    }
+
+    iter = g_list_next(iter);
+  }
+  g_rec_mutex_unlock(&__<NAME>.mutex);
+
+  return false;
+}
+)__c_cb";
+
+/**
+ * <NAME> The name of the interface.
+ * <PRIVILEGE> The privilege name.
+ */
+constexpr const char CB_INTERFACE_PRIVILEGE_ADD[] =
+R"__c_cb(
+ret = rpc_port_stub_add_privilege(__<NAME>.stub, "<PRIVILEGE>");
+if (ret != RPC_PORT_ERROR_NONE) {
+  _E("Failed to add privilege. error(%d)", ret);
+  return ret;
+}
+)__c_cb";
+
+/**
+ * <NAME> The name of the interface.
+ */
+constexpr const char CB_INTERFACE_TRUSTED_SET[] =
+R"__c_cb(
+ret = rpc_port_stub_set_trusted(__<NAME>.stub, true);
+if (ret != RPC_PORT_ERROR_NONE) {
+  _E("Failed to set trusted mode. error(%d)", ret);
+  return ret;
+}
+)__c_cb";
+
+#endif  // IDLC_C_GEN_C_STUB_BODY_GENERATOR_CB_H_
diff --git a/idlc/gen/version2/c_stub_header_generator.cc b/idlc/gen/version2/c_stub_header_generator.cc
new file mode 100644 (file)
index 0000000..20b451f
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "idlc/gen/version2/c_stub_header_generator.hh"
+
+namespace {
+#include "idlc/gen/version2/c_stub_header_generator_cb.hh"
+}
+
+namespace tidl {
+namespace version2 {
+
+CStubHeaderGenerator::CStubHeaderGenerator(std::shared_ptr<Document> doc)
+    : CHeaderGeneratorBase(doc) {}
+
+void CStubHeaderGenerator::OnInitGen(std::ofstream& stream) {
+  GenVersion(stream);
+  GenPragmaOnce(stream);
+  GenIncludeDefaultHeaders(stream, false);
+  GenExplicitLinkageOpen(stream);
+  GenStructureHandles(stream);
+  GenInterfaceHandles(stream);
+  GenStructures(stream);
+  GenInterfaceCallbacks(stream);
+  GenInterfaces(stream);
+}
+
+void CStubHeaderGenerator::OnFiniGen(std::ofstream& stream) {
+  GenExplicitLinkageClose(stream);
+}
+
+void CStubHeaderGenerator::GenInterfaceHandles(std::ofstream& stream) {
+  for (auto& b : GetDocument().GetBlocks()) {
+    if (b->GetType() != Block::TYPE_INTERFACE)
+      continue;
+
+    auto& iface = static_cast<const Interface&>(*b);
+    GenInterfaceContextHandle(stream, iface);
+    for (const auto& d : iface.GetDeclarations()) {
+      if (d->GetMethodType() != Declaration::MethodType::DELEGATE)
+        continue;
+
+      GenInterfaceDelegateHandle(stream, iface, *d);
+    }
+  }
+}
+
+// @see #CB_INTERFACE_CONTEXT_HANDLE
+void CStubHeaderGenerator::GenInterfaceContextHandle(std::ofstream& stream,
+    const Interface& iface) {
+  std::string code(ReplaceAll(CB_INTERFACE_CONTEXT_HANDLE, {
+      { "<PREFIX>", GetHandlePrefix() },
+      { "<NAME>", iface.GetID() }
+  }));
+
+  stream << SmartIndent(code);
+}
+
+// @see #CB_INTERFACE_DELEGATE_HANDLE
+void CStubHeaderGenerator::GenInterfaceDelegateHandle(std::ofstream& stream,
+    const Interface& iface, const Declaration& decl) {
+  std::string code(ReplaceAll(CB_INTERFACE_DELEGATE_HANDLE, {
+      { "<PREFIX>", GetHandlePrefix() },
+      { "<NAME>", iface.GetID() },
+      { "<DELEGATE_NAME>", decl.GetID() }
+  }));
+
+  stream << SmartIndent(code);
+}
+
+void CStubHeaderGenerator::GenInterfaceCallbacks(std::ofstream& stream) {
+  for (auto& b : GetDocument().GetBlocks()) {
+    if (b->GetType() != Block::TYPE_INTERFACE)
+      continue;
+
+    auto& iface = static_cast<const Interface&>(*b);
+    GenInterfaceCallbackBase(stream, iface);
+    for (const auto& d : iface.GetDeclarations()) {
+      if (d->GetMethodType() == Declaration::MethodType::DELEGATE)
+        continue;
+
+      GenInterfaceMethodCallbackBase(stream, iface, *d);
+    }
+  }
+}
+
+// @see #CB_INTERFACE_CALLBACK_BASE
+void CStubHeaderGenerator::GenInterfaceCallbackBase(std::ofstream& stream,
+    const Interface& iface) {
+  std::string code(ReplaceAll(CB_INTERFACE_CALLBACK_BASE, {
+      { "<PREFIX>", GetHandlePrefix() },
+      { "<NAME>", iface.GetID() }
+  }));
+
+  stream << SmartIndent(code);
+}
+
+std::string CStubHeaderGenerator::GenMethodParams(const Interface& iface,
+    const Declaration& decl) {
+  std::string params;
+  for (const auto& p : decl.GetParameters()) {
+    params += ", ";
+    auto& param_type = p->GetParameterType();
+    auto& type = param_type.GetBaseType();
+    params += GetParamTypeString(param_type.GetDirection(), type, iface) +
+        p->GetID();
+  }
+
+  return params;
+}
+
+// @see #CB_INTERFACE_METHOD_CALLBACK_BASE
+void CStubHeaderGenerator::GenInterfaceMethodCallbackBase(std::ofstream& stream,
+    const Interface& iface, const Declaration& decl) {
+  std::string code(ReplaceAll(CB_INTERFACE_METHOD_CALLBACK_BASE, {
+      { "<RETURN_TYPE>", GetReturnTypeString(decl.GetType()) },
+      { "<PREFIX>", GetHandlePrefix() },
+      { "<NAME>", iface.GetID() },
+      { "<METHOD_NAME>", decl.GetID() },
+      { "<METHOD_PARAMS>", GenMethodParams(iface, decl) }
+  }));
+
+  stream << SmartIndent(code);
+}
+
+void CStubHeaderGenerator::GenInterfaces(std::ofstream& stream) {
+  for (auto& i : GetDocument().GetBlocks()) {
+    if (i->GetType() != Block::TYPE_INTERFACE)
+      continue;
+
+    const Interface &iface = static_cast<const Interface&>(*i);
+    GenInterface(stream, iface);
+  }
+}
+
+void CStubHeaderGenerator::GenInterface(std::ofstream& stream,
+    const Interface& iface) {
+  GenInterfaceContextBase(stream, iface);
+  for (const auto& d : iface.GetDeclarations()) {
+    if (d->GetMethodType() != Declaration::MethodType::DELEGATE)
+      continue;
+
+    GenInterfaceDelegateBase(stream, iface, *d);
+  }
+
+  GenInterfaceBase(stream, iface);
+}
+
+// @see #CB_INTERFACE_CONTEXT_BASE
+void CStubHeaderGenerator::GenInterfaceContextBase(std::ofstream& stream,
+    const Interface& iface) {
+  std::string code(ReplaceAll(CB_INTERFACE_CONTEXT_BASE, {
+      { "<PREFIX>", GetHandlePrefix() },
+      { "<NAME>", iface.GetID() }
+  }));
+
+  stream << SmartIndent(code);
+}
+
+std::string CStubHeaderGenerator::GenDelegateParams(const Interface& iface,
+    const Declaration& decl) {
+  std::string params;
+  for (const auto& p : decl.GetParameters()) {
+    params += ", ";
+    auto& param_type = p->GetParameterType();
+    auto& type = param_type.GetBaseType();
+    params += GetParamTypeString(param_type.GetDirection(), type, iface) +
+        p->GetID();
+  }
+
+  return params;
+}
+
+// @see #CB_INTERFACE_DELEGATE_BASE
+void CStubHeaderGenerator::GenInterfaceDelegateBase(std::ofstream& stream,
+    const Interface& iface, const Declaration& decl) {
+  std::string code(ReplaceAll(CB_INTERFACE_DELEGATE_BASE, {
+      { "<PREFIX>", GetHandlePrefix() },
+      { "<NAME>", iface.GetID() },
+      { "<DELEGATE_NAME>", decl.GetID() },
+      { "<DELEGATE_PARAMS>", GenDelegateParams(iface, decl) }
+  }));
+
+  stream << SmartIndent(code);
+}
+
+// @see #CB_INTERFACE_METHOD_CALLBACK_DECL
+std::string CStubHeaderGenerator::GenMethodCallbackDecls(const Interface& iface) {
+  std::string method_callback_decls;
+  for (const auto& d : iface.GetDeclarations()) {
+    if (d->GetMethodType() == Declaration::MethodType::DELEGATE)
+      continue;
+
+    std::string method_callback_decl(ReplaceAll(
+        CB_INTERFACE_METHOD_CALLBACK_DECL, {
+            { "<PREFIX>", GetHandlePrefix() },
+            { "<NAME>", iface.GetID() },
+            { "<METHOD_NAME>", d->GetID() }
+        }));
+
+    method_callback_decl = RemoveLine(method_callback_decl);
+    method_callback_decls += RemoveLine(method_callback_decl, 2);
+  }
+
+  return method_callback_decls;
+}
+
+// @see #CB_INTERFACE_BASE
+void CStubHeaderGenerator::GenInterfaceBase(std::ofstream& stream,
+    const Interface& iface) {
+  std::string code(ReplaceAll(CB_INTERFACE_BASE, {
+      { "<PREFIX>", GetHandlePrefix() },
+      { "<NAME>", iface.GetID() },
+      { "<METHOD_CALLBACK_DECLS>", GenMethodCallbackDecls(iface) }
+  }));
+
+  stream << SmartIndent(code);
+}
+
+}  // namespace version2
+}  // namespace tidl
diff --git a/idlc/gen/version2/c_stub_header_generator.hh b/idlc/gen/version2/c_stub_header_generator.hh
new file mode 100644 (file)
index 0000000..edfd88c
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef IDLC_C_GEN_C_STUB_HEADER_GENERATOR_HH_
+#define IDLC_C_GEN_C_STUB_HEADER_GENERATOR_HH_
+
+#include <memory>
+#include <string>
+
+#include "idlc/gen/version2/c_header_generator_base.hh"
+
+namespace tidl {
+namespace version2 {
+
+class CStubHeaderGenerator : public CHeaderGeneratorBase {
+ public:
+  explicit CStubHeaderGenerator(std::shared_ptr<Document> doc);
+  virtual ~CStubHeaderGenerator() = default;
+
+  void OnInitGen(std::ofstream& stream) override;
+  void OnFiniGen(std::ofstream& stream) override;
+
+ private:
+  void GenInterfaceHandles(std::ofstream& stream);
+  void GenInterfaceContextHandle(std::ofstream& stream, const Interface& iface);
+  void GenInterfaceDelegateHandle(std::ofstream& stream, const Interface& iface,
+      const Declaration& decl);
+
+  void GenInterfaceCallbacks(std::ofstream& stream);
+  void GenInterfaceCallbackBase(std::ofstream& stream, const Interface& iface);
+  void GenInterfaceMethodCallbackBase(std::ofstream& stream,
+      const Interface& iface, const Declaration& decl);
+
+  void GenInterfaces(std::ofstream& stream);
+  void GenInterface(std::ofstream& stream, const Interface& iface);
+
+  void GenInterfaceContextBase(std::ofstream& stream, const Interface& iface);
+  void GenInterfaceDelegateBase(std::ofstream& stream, const Interface& iface,
+      const Declaration& decl);
+  void GenInterfaceBase(std::ofstream& stream, const Interface& iface);
+
+  std::string GenDelegateParams(const Interface& iface,
+      const Declaration& decl);
+  std::string GenMethodParams(const Interface& iface, const Declaration& decl);
+  std::string GenMethodCallbackDecls(const Interface& iface);
+};
+
+}  // namespace version2
+}  // namespace tidl
+
+#endif  // IDLC_C_GEN_C_STUB_HEADER_GENERATOR_HH_
\ No newline at end of file
diff --git a/idlc/gen/version2/c_stub_header_generator_cb.hh b/idlc/gen/version2/c_stub_header_generator_cb.hh
new file mode 100644 (file)
index 0000000..2258e7a
--- /dev/null
@@ -0,0 +1,368 @@
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef IDLC_C_GEN_C_STUB_HEADER_GENERATOR_CB_H_
+#define IDLC_C_GEN_C_STUB_HEADER_GENERATOR_CB_H_
+
+/**
+ * <PREFIX> The prefix of the interface.
+ * <NAME> The name of the interface.
+ */
+constexpr const char CB_INTERFACE_CONTEXT_HANDLE[] =
+R"__c_cb(
+/**
+ * @brief The <PREFIX>_<NAME>_context handle.
+ */
+typedef struct <PREFIX>_<NAME>_context_s *<PREFIX>_<NAME>_context_h;
+)__c_cb";
+
+/**
+ * <PREFIX> The prefix of the interface.
+ * <NAME> The name of the interface.
+ */
+constexpr const char CB_INTERFACE_CONTEXT_BASE[] =
+R"__c_cb(
+/**
+ * @brief Sets the tag to the context handle.
+ *
+ * @param[in] context The context handle
+ * @param[in] tag The tag
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #RPC_PORT_ERROR_NONE Successful
+ * @retval #RPC_PORT_ERROR_INVALID_PARAMETER Invalid parameter
+ * @see <PREFIX>_<NAME>_context_get_tag()
+ */
+int <PREFIX>_<NAME>_context_set_tag(<PREFIX>_<NAME>_context_h context, void *tag);
+
+/**
+ * @brief Gets the tag from the context handle.
+ *
+ * @param[in] context The context handle
+ * @param[out] tag The tag
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #RPC_PORT_ERROR_NONE Successful
+ * @retval #RPC_PORT_ERROR_INVALID_PARAMETER Invalid parameter
+ * @see <PREFIX>_<NAME>_context_set_tag()
+ */
+int <PREFIX>_<NAME>_context_get_tag(<PREFIX>_<NAME>_context_h context, void **tag);
+
+/**
+ * @brief Gets the sender ID from the context handle.
+ * @details The @a sender should be released using free().
+ *
+ * @param[in] context The context handle
+ * @param[out] sender The sender ID of the context handle
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #RPC_PORT_ERROR_NONE Successful
+ * @retval #RPC_PORT_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #RPC_PORT_ERROR_OUT_OF_MEMORY Out of memory
+ */
+int <PREFIX>_<NAME>_context_get_sender(<PREFIX>_<NAME>_context_h context, char **sender);
+
+/**
+ * @brief Gets the instance ID from the context handle.
+ * @details The @a instance should be released using free().
+ *
+ * @param[in] context The context handle
+ * @param[out] instance The instance ID of the context handle
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #RPC_PORT_ERROR_NONE Successful
+ * @retval #RPC_PORT_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #RPC_PORT_ERROR_OUT_OF_MEMORY Out of memory
+ */
+int <PREFIX>_<NAME>_context_get_instance(<PREFIX>_<NAME>_context_h context, char **instance);
+
+/**
+ * @brief Disconnects from the proxy.
+ *
+ * @param[in] context The context handle
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #RPC_PORT_ERROR_NONE Successful
+ * @retval #RPC_PORT_ERROR_INVALID_PARAMETER Invalid parameter
+ */
+int <PREFIX>_<NAME>_context_disconnect(<PREFIX>_<NAME>_context_h context);
+)__c_cb";
+
+/**
+ * <PREFIX> The prefix of the interface.
+ * <NAME> The name of the interface.
+ * <DELEGATE_NAME> The name of the delegate of the interface.
+ */
+constexpr const char CB_INTERFACE_DELEGATE_HANDLE[] =
+R"__c_cb(
+/**
+ * @brief The <PREFIX>_<NAME>_<DELEGATE_NAME> handle.
+ */
+typedef struct <PREFIX>_<NAME>_<DELEGATE_NAME>_s *<PREFIX>_<NAME>_<DELEGATE_NAME>_h;
+)__c_cb";
+
+/**
+ * <PREFIX> The prefix of the interface.
+ * <NAME> The name of the interface.
+ * <DELEGATE_NAME> The name of the delegate.
+ * <DELEGATE_PARAMS> The parameters of the callback function.
+ */
+constexpr const char CB_INTERFACE_DELEGATE_BASE[] =
+R"__c_cb(
+/**
+ * @brief Creates a <PREFIX>_<NAME>_<DELEGATE_NAME> handle.
+ *
+ * @param[out] h The <PREFIX>_<NAME>_<DELEGATE_NAME> handle
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #RPC_PORT_ERROR_NONE Successful
+ * @retval #RPC_PORT_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #RPC_PORT_ERROR_OUT_OF_MEMORY Out of memory
+ * @see <PREFIX>_<NAME>_<DELEGATE_NAME>_destroy()
+ */
+int <PREFIX>_<NAME>_<DELEGATE_NAME>_create(<PREFIX>_<NAME>_<DELEGATE_NAME>_h *h);
+
+/**
+ * @brief Destroys the <PREFIX>_<NAME>_<DELEGATE_NAME> handle.
+ *
+ * @param[in] h The <PREFIX>_<NAME>_<DELEGATE_NAME> handle
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #RPC_PORT_ERROR_NONE Successful
+ * @retval #RPC_PORT_ERROR_INVALID_PARAMETER Invalid parameter
+ * @see <PREFIX>_<NAME>_<DELEGATE_NAME>_clone()
+ */
+int <PREFIX>_<NAME>_<DELEGATE_NAME>_destroy(<PREFIX>_<NAME>_<DELEGATE_NAME>_h h);
+
+/**
+ * @brief Creates and returns a copy of the given <PREFIX>_<NAME>_<DELEGATE_NAME> handle.
+ *
+ * @remarks A new created <PREFIX>_<NAME>_<DELEGATE_NAME> should be released using
+ *          the <PREFIX>_<NAME>_<DELEGATE_NAME>_destroy() if it's no longer needed.
+ * @param[in] h The <PREFIX>_<NAME>_<DELEGATE_NAME> handle
+ * @param[out] clone If successful, a new created <PREFIX>_<NAME>_<DELEGATE_NAME> handle will be returned
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #RPC_PORT_ERROR_NONE Successful
+ * @retval #RPC_PORT_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #RPC_PORT_ERROR_OUT_OF_MEMORY Out of memory
+ * @see <PREFIX>_<NAME>_<DELEGATE_NAME>_destroy()
+ */
+int <PREFIX>_<NAME>_<DELEGATE_NAME>_clone(<PREFIX>_<NAME>_<DELEGATE_NAME>_h h, <PREFIX>_<NAME>_<DELEGATE_NAME>_h *clone);
+
+/**
+ * @brief Gets the ID of the <PREFIX>_<NAME>_<DELEGATE_NAME> handle.
+ *
+ * @param[in] h The <PREFIX>_<NAME>_<DELEGATE_NAME> handle
+ * @param[out] id The ID
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #RPC_PORT_ERROR_NONE Successful
+ * @retval #RPC_PORT_ERROR_INVALID_PARAMETER Invalid parameter
+ */
+int <PREFIX>_<NAME>_<DELEGATE_NAME>_get_id(<PREFIX>_<NAME>_<DELEGATE_NAME>_h h, int *id);
+
+/**
+ * @brief Gets the sequence ID of the <PREFIX>_<NAME>_<DELEGATE_NAME> handle.
+ *
+ * @param[in] h The <PREFIX>_<NAME>_<DELEGATE_NAME> handle
+ * @param[out] seq_id The Sequence ID
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #RPC_PORT_ERROR_NONE Successful
+ * @retval #RPC_PORT_ERROR_INVALID_PARAMETER Invalid parameter
+ */
+int <PREFIX>_<NAME>_<DELEGATE_NAME>_get_seq_id(<PREFIX>_<NAME>_<DELEGATE_NAME>_h h, int *seq_id);
+
+/**
+ * @brief Checks whether the delegate is for one-time or not.
+ *
+ * @param[in] h The <PREFIX>_<NAME>_<DELEGATE_NAME> handle
+ * @param[out] once The flag, it's true, the handle is for one-time
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #RPC_PORT_ERROR_NONE Successful
+ * @retval #RPC_PORT_ERROR_INVALID_PARAMETER Invalid parameter
+ */
+int <PREFIX>_<NAME>_<DELEGATE_NAME>_is_once(<PREFIX>_<NAME>_<DELEGATE_NAME>_h h, bool *once);
+
+/**
+ * @brief Gets the tag from the <PREFIX>_<NAME>_<DELEGATE_NAME> handle.
+ *
+ * @remarks The @a tag should be released using free().
+ * @param[in] h The <PREFIX>_<NAME>_<DELEGATE_NAME> handle
+ * @param[out] tag The tag
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #RPC_PORT_ERROR_NONE Successful
+ * @retval #RPC_PORT_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #RPC_PORT_ERROR_OUT_OF_MEMORY Out of memory
+ */
+int <PREFIX>_<NAME>_<DELEGATE_NAME>_get_tag(<PREFIX>_<NAME>_<DELEGATE_NAME>_h h, char **tag);
+
+/**
+ * @brief Invokes the callback function of the <PREFIX>_<NAME>_<DELEGATE_NAME> handle.
+ *
+ * @param[in] h The <PREFIX>_<NAME>_<DELEGATE_NAME> handle
+ * @param[in] ...
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #RPC_PORT_ERROR_NONE Successful
+ * @retval #RPC_PORT_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #RPC_PORT_ERROR_OUT_OF_MEMORY Out of memory
+ * @retval #RPC_PORT_ERROR_IO_ERROR I/O error
+ */
+int <PREFIX>_<NAME>_<DELEGATE_NAME>_invoke(<PREFIX>_<NAME>_<DELEGATE_NAME>_h h<DELEGATE_PARAMS>);
+)__c_cb";
+
+/**
+ * <PREFIX> The prefix of the interface.
+ * <NAME> The name of the interface.
+ */
+constexpr const char CB_INTERFACE_CALLBACK_BASE[] =
+R"__c_cb(
+/**
+ * @brief Called when the proxy is connected.
+ * @details The callback function is called when the proxy is connected to the stub.
+ *
+ * @param[in] context The context handle
+ * @param[in] user_data The user data passed from the registration function
+ * @see #<PREFIX>_<NAME>_callback_s
+ */
+typedef void (*<PREFIX>_<NAME>_create_cb)(<PREFIX>_<NAME>_context_h context, void *user_data);
+
+/**
+ * @brief Called when the proxy is disconnected.
+ * @details The callback function is called when the proxy is disconnected from the stub.
+ *
+ * @param[in] context The context handle
+ * @param[in] user_data The user data passed from the registration function
+ * @see #<PREFIX>_<NAME>_callback_s
+ */
+typedef void (*<PREFIX>_<NAME>_terminate_cb)(<PREFIX>_<NAME>_context_h context, void *user_data);
+
+/**
+ * @brief Called to get the proxy context once for each connected proxy.
+ *
+ * @param[in] context The context handle
+ * @param[in] user_data The user data passed from the registration function
+ * @return @c true to continue with the next iteration of the loop,
+ *         otherwise @c false to break out of the loop
+ * @pre <PREFIX>_<NAME>_foreach_context() will invoke this callback.
+ * @see <PREFIX>_<NAME>_foreach_context()
+ */
+typedef bool (*<PREFIX>_<NAME>_context_cb)(<PREFIX>_<NAME>_context_h context, void *user_data);
+)__c_cb";
+
+/**
+ * <RETURN_TYPE> The return type of the method.
+ * <PREFIX> The prefix of the interface.
+ * <NAME> The name of the interface.
+ * <METHOD_NAME> The name of the method of the interface.
+ * <METHOD_PARAMS> The parameters of the method.
+ */
+constexpr const char CB_INTERFACE_METHOD_CALLBACK_BASE[] =
+R"__c_cb(
+/**
+ * @brief Called when the request of the proxy is delivered.
+ *
+ * @param[in] context The context handle
+ * @param[in] user_data The user data passed from the registration function
+ * @see #<PREFIX>_<NAME>_callback_s;
+ */
+typedef <RETURN_TYPE> (*<PREFIX>_<NAME>_<METHOD_NAME>_cb)(<PREFIX>_<NAME>_context_h context<METHOD_PARAMS>, void *user_data);
+)__c_cb";
+
+/**
+ * <PREFIX> The prefix of the interface.
+ * <NAME> The name of the interface.
+ * <METHOD_CALLBACK_DECLS> The declarations of the method callback functions.
+ */
+constexpr const char CB_INTERFACE_BASE[] =
+R"__c_cb(
+/**
+ * @brief The structure type containing the set of callback functions for handling stub events.
+ * @details It is one of the input parameters of the <PREFIX>_<NAME>_register() function.
+ *
+ * @see <PREFIX>_<NAME>_create_cb
+ * @see <PREFIX>_<NAME>_terminate_cb
+ */
+typedef struct {
+  <PREFIX>_<NAME>_create_cb create;  /**< This callback function is invoked when the proxy is connected. */
+  <PREFIX>_<NAME>_terminate_cb terminate;  /**< This callback function is invoked when the proxy is disconnected. */
+  <METHOD_CALLBACK_DECLS>
+} <PREFIX>_<NAME>_callback_s;
+
+/**
+ * @brief Registers the set of the callback functions and the port.
+ * @details This function registers the set of the callback functions to handle stub events.
+ *          And, the rpc_port_stub_listen() is called internally to handle events.
+ *
+ * @param[in] callback The set of callback functions to handle stub events
+ * @param[in] user_data The user data to be passed to the callback function
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #RPC_PORT_ERROR_NONE Successful
+ * @retval #RPC_PORT_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #RPC_PORT_ERROR_OUT_OF_MEMORY Out of memory
+ * @retval #RPC_PORT_ERROR_IO_ERROR I/O error
+ * @retval #RPC_PORT_ERROR_PERMISSION_DENIED Permission denied
+ * @see <PREFIX>_<NAME>_unregister()
+ * @see #<PREFIX>_<NAME>_callback_s
+ */
+int <PREFIX>_<NAME>_register(<PREFIX>_<NAME>_callback_s *callback, void *user_data);
+
+/**
+ * @brief Unregisters the registered port.
+ */
+int <PREFIX>_<NAME>_unregister(void);
+
+/**
+ * @brief Retrieves the connected context handles.
+ *
+ * @param[in] callback The callback function
+ * @param[in] user_data The user data to be passed to the callback function
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #RPC_PORT_ERROR_NONE Successful
+ * @retval #RPC_PORT_ERROR_INVALID_PARAMETER Invalid parameter
+ * @see <PREFIX>_<NAME>_context_cb()
+ */
+int <PREFIX>_<NAME>_foreach_context(<PREFIX>_<NAME>_context_cb callback, void *user_data);
+
+/**
+ * @brief Gets the number of connected clients.
+ *
+ * @param[out] client_number The client number
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #RPC_PORT_ERROR_NONE Successful
+ * @retval #RPC_PORT_ERROR_INVALID_PARAMETER Invalid parameter
+ */
+int <PREFIX>_<NAME>_get_client_number(unsigned int *client_number);
+)__c_cb";
+
+/**
+ * <PREFIX> The prefix of the interface.
+ * <NAME> The name of the interface.
+ * <METHOD_NAME> The name of the method of the interface.
+ */
+constexpr const char CB_INTERFACE_METHOD_CALLBACK_DECL[] =
+R"__c_cb(
+<PREFIX>_<NAME>_<METHOD_NAME>_cb <METHOD_NAME>;  /**< This callback function is invoked when the <METHOD_NAME> request is delivered. */
+)__c_cb";
+
+#endif  // IDLC_C_GEN_C_STUB_HEADER_GENERATOR_CB_H_
\ No newline at end of file
index 889eca5..839f803 100644 (file)
@@ -40,6 +40,8 @@
 #include "idlc/gen/dart_stub_gen.h"
 #include "idlc/gen/version2/c_proxy_header_generator.hh"
 #include "idlc/gen/version2/c_proxy_body_generator.hh"
+#include "idlc/gen/version2/c_stub_header_generator.hh"
+#include "idlc/gen/version2/c_stub_body_generator.hh"
 #include "idlc/gen/version2/c_group_header_generator.hh"
 #include "idlc/gen/version2/c_group_body_generator.hh"
 #include "idlc/gen_cion/c_cion_proxy_header_gen.h"
@@ -243,14 +245,29 @@ void GenerateStubCodes(std::shared_ptr<tidl::Options> options,
     switch (options->GetLanguage()) {
     case tidl::Options::LANGUAGE_TYPE_C:
     {
-      tidl::CStubHeaderGen stub_header(ps.GetDoc());
-      stub_header.EnableNamespace(options->HasNamespace());
-      stub_header.EnableProxy(false);
-      stub_header.Run(options->GetOutput() + ".h");
-      tidl::CStubBodyGen stub_body(ps.GetDoc(), options);
-      stub_body.EnableNamespace(options->HasNamespace());
-      stub_body.EnableProxy(false);
-      stub_body.Run(options->GetOutput() + ".c");
+      if (ps.GetVersion() == 2) {
+        tidl::version2::CStubHeaderGenerator stub_header(ps.GetDoc());
+        stub_header.EnableNamespace(options->HasNamespace());
+        stub_header.SetChannelType(
+          static_cast<tidl::Generator::ChannelType>(options->GetType()));
+        stub_header.EnableProxy(false);
+        stub_header.Run(options->GetOutput() + ".h");
+        tidl::version2::CStubBodyGenerator stub_body(ps.GetDoc(), options);
+        stub_body.EnableNamespace(options->HasNamespace());
+        stub_body.SetChannelType(
+          static_cast<tidl::Generator::ChannelType>(options->GetType()));
+        stub_body.EnableProxy(false);
+        stub_body.Run(options->GetOutput() + ".c");
+      } else {
+        tidl::CStubHeaderGen stub_header(ps.GetDoc());
+        stub_header.EnableNamespace(options->HasNamespace());
+        stub_header.EnableProxy(false);
+        stub_header.Run(options->GetOutput() + ".h");
+        tidl::CStubBodyGen stub_body(ps.GetDoc(), options);
+        stub_body.EnableNamespace(options->HasNamespace());
+        stub_body.EnableProxy(false);
+        stub_body.Run(options->GetOutput() + ".c");
+      }
       break;
     }
     case tidl::Options::LANGUAGE_TYPE_CPP:
@@ -452,11 +469,15 @@ void GenerateProxyCodes(std::shared_ptr<tidl::Options> options,
         tidl::version2::CProxyHeaderGenerator proxy_header(ps.GetDoc());
         proxy_header.EnableNamespace(options->HasNamespace());
         proxy_header.EnableProxy(true);
+        proxy_header.SetChannelType(
+          static_cast<tidl::Generator::ChannelType>(options->GetType()));
         proxy_header.Run(options->GetOutput() + ".h");
 
         tidl::version2::CProxyBodyGenerator proxy_body(ps.GetDoc(), options);
         proxy_body.EnableNamespace(options->HasNamespace());
         proxy_body.EnableProxy(true);
+        proxy_body.SetChannelType(
+          static_cast<tidl::Generator::ChannelType>(options->GetType()));
         proxy_body.Run(options->GetOutput() + ".c");
       } else {
         tidl::CProxyHeaderGen proxy_header(ps.GetDoc());