Repository.mk                             |    1 
 static/CustomTarget_unoembind.mk          |   10 
 static/Module_static.mk                   |    1 
 static/Package_unoembind.mk               |   18 +
 static/README.wasm.md                     |   18 -
 static/source/embindmaker/embindmaker.cxx |  335 +++++++++++++++++++-----------
 6 files changed, 260 insertions(+), 123 deletions(-)

New commits:
commit cbae6e581ad62771122d35742bd304be44fb982c
Author:     Stephan Bergmann <stephan.bergm...@allotropia.de>
AuthorDate: Thu Jan 25 16:59:49 2024 +0100
Commit:     Stephan Bergmann <stephan.bergm...@allotropia.de>
CommitDate: Thu Jan 25 18:31:42 2024 +0100

    Let embindmaker also generate a .js file with more natural names
    
    (i.e., Module.unoembind_uno.com.sun.star... vs. Module.com$sun$star$..., 
and see
    the updated examples in static/README.wasm.md for further shortening that to
    just css...)
    
    Change-Id: I6dc079caa8c93a4042a6a8aa2d8fcc8f76bf80f3
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162580
    Tested-by: Jenkins
    Reviewed-by: Stephan Bergmann <stephan.bergm...@allotropia.de>

diff --git a/Repository.mk b/Repository.mk
index 2eb8ae6936e8..f39f9dc656df 100644
--- a/Repository.mk
+++ b/Repository.mk
@@ -1036,6 +1036,7 @@ $(eval $(call 
gb_Helper_register_packages_for_install,ooo,\
        ) \
        resource_fonts \
        cui \
+       $(if $(filter EMSCRIPTEN,$(OS)),unoembind) \
 ))
 
 $(eval $(call gb_Helper_register_packages_for_install,ooo_fonts,\
diff --git a/static/CustomTarget_unoembind.mk b/static/CustomTarget_unoembind.mk
index 4bed6f585fa7..cccb36f1dce2 100644
--- a/static/CustomTarget_unoembind.mk
+++ b/static/CustomTarget_unoembind.mk
@@ -11,12 +11,16 @@ $(eval $(call 
gb_CustomTarget_CustomTarget,static/unoembind))
 
 $(eval $(call gb_CustomTarget_register_targets,static/unoembind, \
     bindings_uno.cxx \
+    bindings_uno.js \
 ))
 
-$(call gb_CustomTarget_get_workdir,static/unoembind)/bindings_uno.cxx: \
+$(call gb_CustomTarget_get_workdir,static/unoembind)/bindings_uno.cxx \
+$(call gb_CustomTarget_get_workdir,static/unoembind)/bindings_uno.js: \
         $(call gb_Executable_get_target_for_build,embindmaker) $(call 
gb_UnoApi_get_target,udkapi) \
         $(call gb_UnoApi_get_target,offapi)
-       $(call gb_Executable_get_command,embindmaker) uno +$(call 
gb_UnoApi_get_target,udkapi) \
-        +$(call gb_UnoApi_get_target,offapi) > $@
+       $(call gb_Executable_get_command,embindmaker) uno \
+        $(call gb_CustomTarget_get_workdir,static/unoembind)/bindings_uno.cxx \
+        $(call gb_CustomTarget_get_workdir,static/unoembind)/bindings_uno.js \
+        +$(call gb_UnoApi_get_target,udkapi) +$(call 
gb_UnoApi_get_target,offapi)
 
 # vim: set noet sw=4 ts=4:
diff --git a/static/Module_static.mk b/static/Module_static.mk
index 3b785c7ba4cb..c91441a6b924 100644
--- a/static/Module_static.mk
+++ b/static/Module_static.mk
@@ -19,6 +19,7 @@ ifeq (EMSCRIPTEN,$(OS))
 $(eval $(call gb_Module_add_targets,static,\
     CustomTarget_emscripten_fs_image \
     CustomTarget_unoembind \
+    Package_unoembind \
     StaticLibrary_unoembind \
     $(if $(ENABLE_QT5), \
         CustomTarget_wasm-qt5-mandelbrot_moc \
diff --git a/static/Package_unoembind.mk b/static/Package_unoembind.mk
new file mode 100644
index 000000000000..d1f82b970424
--- /dev/null
+++ b/static/Package_unoembind.mk
@@ -0,0 +1,18 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t; fill-column: 
100 -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Package_Package,unoembind,$(call 
gb_CustomTarget_get_workdir,static/unoembind)))
+
+$(eval $(call gb_Package_use_custom_target,unoembind,static/unoembind))
+
+$(eval $(call gb_Package_add_files,unoembind,$(LIBO_BIN_FOLDER), \
+    bindings_uno.js \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/static/README.wasm.md b/static/README.wasm.md
index f39a79247d00..2bfecb404a7e 100644
--- a/static/README.wasm.md
+++ b/static/README.wasm.md
@@ -223,29 +223,33 @@ improvement! ;)
 Some usage examples through javascript of the current implementation:
 ```js
 // inserts a string at the start of the Writer document.
+Module.init_unoembind_uno();
+let css = Module.unoembind_uno.com.sun.star;
 xModel = Module.getCurrentModelFromViewSh();
-xTextDocument = new Module.com$sun$star$text$XTextDocumentRef(xModel, 
Module.UnoReference_Query.UNO_QUERY);
+xTextDocument = new css.text.XTextDocument(xModel, 
Module.UnoReference_Query.UNO_QUERY);
 xText = xTextDocument.getText();
-xSimpleText = new Module.com$sun$star$text$XSimpleTextRef(xText, 
Module.UnoReference_Query.UNO_QUERY);
+xSimpleText = new css.text.XSimpleText(xText, 
Module.UnoReference_Query.UNO_QUERY);
 xTextCursor = xSimpleText.createTextCursor();
-xTextRange = new Module.com$sun$star$text$XTextRangeRef(xTextCursor, 
Module.UnoReference_Query.UNO_QUERY);
+xTextRange = new css.text.XTextRange(xTextCursor, 
Module.UnoReference_Query.UNO_QUERY);
 xTextRange.setString(new Module.OUString("string here!"));
 xModel.delete(); xTextDocument.delete(); xText.delete(); xSimpleText.delete(); 
xTextCursor.delete(); xTextRange.delete();
 ```
 
 ```js
 // changes each paragraph of the Writer document to a random color.
+Module.init_unoembind_uno();
+let css = Module.unoembind_uno.com.sun.star;
 xModel = Module.getCurrentModelFromViewSh();
-xTextDocument = new Module.com$sun$star$text$XTextDocumentRef(xModel, 
Module.UnoReference_Query.UNO_QUERY);
+xTextDocument = new css.text.XTextDocument(xModel, 
Module.UnoReference_Query.UNO_QUERY);
 xText = xTextDocument.getText();
-xEnumAccess = new Module.com$sun$star$container$XEnumerationAccessRef(xText, 
Module.UnoReference_Query.UNO_QUERY);
+xEnumAccess = new css.container.XEnumerationAccess(xText, 
Module.UnoReference_Query.UNO_QUERY);
 xParaEnumeration = xEnumAccess.createEnumeration();
 
 while (xParaEnumeration.hasMoreElements()) {
-    xParagraph = new Module.com$sun$star$text$XTextRangeRef();
+    xParagraph = new css.text.XTextRange();
     xParagraph.set(xParaEnumeration.nextElement(), 
Module.UnoReference_Query.UNO_QUERY);
     if (xParagraph.is()) {
-        xParaProps = new Module.com$sun$star$beans$XPropertySetRef(xParagraph, 
Module.UnoReference_Query.UNO_QUERY);
+        xParaProps = new css.beans.XPropertySet(xParagraph, 
Module.UnoReference_Query.UNO_QUERY);
         xParaProps.setPropertyValue(new Module.OUString("CharColor"), new 
Module.Any(Math.floor(Math.random() * 0xFFFFFF), Module.UnoType.long));
     }
 }
diff --git a/static/source/embindmaker/embindmaker.cxx 
b/static/source/embindmaker/embindmaker.cxx
index 184d635da5c0..ed326ce4ed99 100644
--- a/static/source/embindmaker/embindmaker.cxx
+++ b/static/source/embindmaker/embindmaker.cxx
@@ -11,7 +11,13 @@
 
 #include <cassert>
 #include <cstdlib>
+#include <fstream>
+#include <ios>
 #include <iostream>
+#include <map>
+#include <memory>
+#include <ostream>
+#include <string>
 #include <string_view>
 #include <utility>
 #include <vector>
@@ -20,9 +26,11 @@
 #include <codemaker/typemanager.hxx>
 #include <osl/file.hxx>
 #include <osl/process.h>
+#include <osl/thread.h>
 #include <rtl/process.h>
 #include <rtl/ref.hxx>
 #include <rtl/string.hxx>
+#include <rtl/textcvt.h>
 #include <rtl/ustrbuf.hxx>
 #include <rtl/ustring.hxx>
 #include <sal/main.h>
@@ -35,14 +43,32 @@ void badUsage()
 {
     std::cerr
         << "Usage:

"
-           "  embindmaker <prefix> <registries>

"
+           "  embindmaker <name> <cpp-ouptput> <js-output> <registries>

"
            "where each <registry> is '+' (primary) or ':' (secondary), 
followed by: either a
"
            "new- or legacy-format .rdb file, a single .idl file, or a root 
directory of an
"
-           ".idl file tree.  Embind code for all primary registries is written 
to stdout,"
-           "with <prefix> used as part of the name passed to 
EMSCRIPTEN_BINDINGS.
";
+           ".idl file tree.  For all primary registries, Embind code is 
written to
"
+           "<cpp-output> and corresponding JavaScript scaffolding code is 
written to
"
+           "<js-output>.  The <name> is used as part of some of the 
identifiers in those
"
+           "generated files.
";
     std::exit(EXIT_FAILURE);
 }
 
+std::string getPathnameArgument(sal_uInt32 argument)
+{
+    OUString arg;
+    rtl_getAppCommandArg(argument, &arg.pData);
+    OString path;
+    auto const enc = osl_getThreadTextEncoding();
+    if (!arg.convertToString(&path, enc,
+                             RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
+                                 | RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR))
+    {
+        std::cerr << "Cannot convert \"" << arg << "\" to system encoding " << 
enc << "
";
+        std::exit(EXIT_FAILURE);
+    }
+    return std::string(path);
+}
+
 std::pair<OUString, bool> parseRegistryArgument(sal_uInt32 argument)
 {
     OUString arg;
@@ -86,10 +112,17 @@ std::pair<OUString, bool> parseRegistryArgument(sal_uInt32 
argument)
     return { abs, primary };
 }
 
+struct Module
+{
+    std::map<OUString, std::shared_ptr<Module>> modules;
+    std::vector<OUString> interfaces;
+};
+
 void scan(rtl::Reference<unoidl::MapCursor> const& cursor, std::u16string_view 
prefix,
-          std::vector<OUString>& interfaces)
+          Module* module, std::vector<OUString>& interfaces)
 {
     assert(cursor.is());
+    assert(module != nullptr);
     for (;;)
     {
         OUString id;
@@ -102,10 +135,18 @@ void scan(rtl::Reference<unoidl::MapCursor> const& 
cursor, std::u16string_view p
         switch (ent->getSort())
         {
             case unoidl::Entity::SORT_MODULE:
+            {
+                auto& sub = module->modules[id];
+                if (!sub)
+                {
+                    sub = std::make_shared<Module>();
+                }
                 
scan(static_cast<unoidl::ModuleEntity*>(ent.get())->createCursor(),
-                     Concat2View(name + "."), interfaces);
+                     Concat2View(name + "."), sub.get(), interfaces);
                 break;
+            }
             case unoidl::Entity::SORT_INTERFACE_TYPE:
+                module->interfaces.emplace_back(name);
                 interfaces.emplace_back(name);
                 break;
             default:
@@ -118,16 +159,17 @@ OUString cppName(OUString const& name) { return "::" + 
name.replaceAll(u".", u":
 
 OUString jsName(OUString const& name) { return name.replace('.', '$'); }
 
-void dumpAttributes(OUString const& name, 
rtl::Reference<unoidl::InterfaceTypeEntity> const& entity)
+void dumpAttributes(std::ostream& out, OUString const& name,
+                    rtl::Reference<unoidl::InterfaceTypeEntity> const& entity)
 {
     for (auto const& attr : entity->getDirectAttributes())
     {
-        std::cout << "        .function(\"get" << attr.name << "\", &" << 
cppName(name) << "::get"
-                  << attr.name << ")
";
+        out << "        .function(\"get" << attr.name << "\", &" << 
cppName(name) << "::get"
+            << attr.name << ")
";
         if (!attr.readOnly)
         {
-            std::cout << "        .function(\"set" << attr.name << "\", &" << 
cppName(name)
-                      << "::set" << attr.name << ")
";
+            out << "        .function(\"set" << attr.name << "\", &" << 
cppName(name) << "::set"
+                << attr.name << ")
";
         }
     }
 }
@@ -201,7 +243,8 @@ bool passByReference(rtl::Reference<TypeManager> const& 
manager, OUString const&
     }
 }
 
-void dumpType(rtl::Reference<TypeManager> const& manager, std::u16string_view 
name, bool isConst)
+void dumpType(std::ostream& out, rtl::Reference<TypeManager> const& manager,
+              std::u16string_view name, bool isConst)
 {
     sal_Int32 k;
     std::vector<OString> args;
@@ -209,69 +252,69 @@ void dumpType(rtl::Reference<TypeManager> const& manager, 
std::u16string_view na
         b2u(codemaker::UnoType::decompose(u2b(resolveAllTypedefs(manager, 
name)), &k, &args)));
     if (isConst)
     {
-        std::cout << "const ";
+        out << "const ";
     }
     for (sal_Int32 i = 0; i != k; ++i)
     {
-        std::cout << "::css::uno::Sequence<";
+        out << "::css::uno::Sequence<";
     }
     switch (manager->getSort(n))
     {
         case codemaker::UnoType::Sort::Void:
-            std::cout << "void";
+            out << "void";
             break;
         case codemaker::UnoType::Sort::Boolean:
-            std::cout << "::sal_Bool";
+            out << "::sal_Bool";
             break;
         case codemaker::UnoType::Sort::Byte:
-            std::cout << "::sal_Int8";
+            out << "::sal_Int8";
             break;
         case codemaker::UnoType::Sort::Short:
-            std::cout << "::sal_Int16";
+            out << "::sal_Int16";
             break;
         case codemaker::UnoType::Sort::UnsignedShort:
-            std::cout << "::sal_uInt16";
+            out << "::sal_uInt16";
             break;
         case codemaker::UnoType::Sort::Long:
-            std::cout << "::sal_Int32";
+            out << "::sal_Int32";
             break;
         case codemaker::UnoType::Sort::UnsignedLong:
-            std::cout << "::sal_uInt32";
+            out << "::sal_uInt32";
             break;
         case codemaker::UnoType::Sort::Hyper:
-            std::cout << "::sal_Int64";
+            out << "::sal_Int64";
             break;
         case codemaker::UnoType::Sort::UnsignedHyper:
-            std::cout << "::sal_uInt64";
+            out << "::sal_uInt64";
             break;
         case codemaker::UnoType::Sort::Float:
-            std::cout << "float";
+            out << "float";
             break;
         case codemaker::UnoType::Sort::Double:
-            std::cout << "double";
+            out << "double";
             break;
         case codemaker::UnoType::Sort::Char:
-            std::cout << "::sal_Unicode";
+            out << "::sal_Unicode";
             break;
         case codemaker::UnoType::Sort::String:
-            std::cout << "::rtl::OUString";
+            out << "::rtl::OUString";
             break;
         case codemaker::UnoType::Sort::Type:
-            std::cout << "::css::uno::Type";
+            out << "::css::uno::Type";
             break;
         case codemaker::UnoType::Sort::Any:
-            std::cout << "::css::uno::Any";
+            out << "::css::uno::Any";
             break;
         case codemaker::UnoType::Sort::Enum:
         case codemaker::UnoType::Sort::PlainStruct:
         case codemaker::UnoType::Sort::Exception:
-            std::cout << cppName(n);
+            out << cppName(n);
             break;
         case codemaker::UnoType::Sort::PolymorphicStructTemplate:
-            std::cout << cppName(n);
+            out << cppName(n);
             if (!args.empty())
             {
-                std::cout << "<";
+                out << "<";
                 bool first = true;
                 for (auto const& arg : args)
                 {
@@ -281,17 +324,17 @@ void dumpType(rtl::Reference<TypeManager> const& manager, 
std::u16string_view na
                     }
                     else
                     {
-                        std::cout << ", ";
+                        out << ", ";
                     }
-                    dumpType(manager, b2u(arg), false);
+                    dumpType(out, manager, b2u(arg), false);
                 }
-                std::cout << ">";
+                out << ">";
             }
             break;
         case codemaker::UnoType::Sort::Interface:
-            std::cout << "::css::uno::Reference<";
-            std::cout << cppName(n);
-            std::cout << ">";
+            out << "::css::uno::Reference<";
+            out << cppName(n);
+            out << ">";
             break;
         default:
             throw CannotDumpException(OUString::Concat("unexpected entity \"") 
+ name
@@ -299,11 +342,11 @@ void dumpType(rtl::Reference<TypeManager> const& manager, 
std::u16string_view na
     }
     for (sal_Int32 i = 0; i != k; ++i)
     {
-        std::cout << ">";
+        out << ">";
     }
 }
 
-void dumpParameters(rtl::Reference<TypeManager> const& manager,
+void dumpParameters(std::ostream& out, rtl::Reference<TypeManager> const& 
manager,
                     unoidl::InterfaceTypeEntity::Method const& method, bool 
declarations)
 {
     bool first = true;
@@ -315,7 +358,7 @@ void dumpParameters(rtl::Reference<TypeManager> const& 
manager,
         }
         else
         {
-            std::cout << ", ";
+            out << ", ";
         }
         bool isConst;
         bool isRef;
@@ -332,58 +375,60 @@ void dumpParameters(rtl::Reference<TypeManager> const& 
manager,
         // For the embind wrapper, we define a pointer instead of a reference:
         if (declarations)
         {
-            dumpType(manager, param.type, isConst);
-            std::cout << " ";
+            dumpType(out, manager, param.type, isConst);
+            out << " ";
         }
         if (isRef)
         {
-            std::cout << "*";
+            out << "*";
         }
         if (declarations)
         {
-            std::cout << " ";
+            out << " ";
         }
-        std::cout << param.name;
+        out << param.name;
     }
 }
 
-void dumpWrapper(rtl::Reference<TypeManager> const& manager, OUString const& 
interfaceName,
-                 unoidl::InterfaceTypeEntity::Method const& method, bool 
forReference)
+void dumpWrapper(std::ostream& out, rtl::Reference<TypeManager> const& manager,
+                 OUString const& interfaceName, 
unoidl::InterfaceTypeEntity::Method const& method,
+                 bool forReference)
 {
-    std::cout << "        .function(\"" << method.name << "\", +[](";
+    out << "        .function(\"" << method.name << "\", +[](";
     if (forReference)
     {
-        std::cout << "::com::sun::star::uno::Reference<";
+        out << "::com::sun::star::uno::Reference<";
     }
-    std::cout << cppName(interfaceName);
+    out << cppName(interfaceName);
     if (forReference)
     {
-        std::cout << ">";
+        out << ">";
     }
-    std::cout << " * the_self";
+    out << " * the_self";
     if (!method.parameters.empty())
     {
-        std::cout << ", ";
+        out << ", ";
     }
-    dumpParameters(manager, method, true);
-    std::cout << ") { return the_self->";
+    dumpParameters(out, manager, method, true);
+    out << ") { return the_self->";
     if (forReference)
     {
-        std::cout << "get()->";
+        out << "get()->";
     }
-    std::cout << method.name << "(";
-    dumpParameters(manager, method, false);
-    std::cout << "); }, ::emscripten::allow_raw_pointers())
";
+    out << method.name << "(";
+    dumpParameters(out, manager, method, false);
+    out << "); }, ::emscripten::allow_raw_pointers())
";
 }
 
-void dumpMethods(rtl::Reference<TypeManager> const& manager, OUString const& 
name,
-                 rtl::Reference<unoidl::InterfaceTypeEntity> const& entity, 
bool forReference)
+void dumpMethods(std::ostream& out, rtl::Reference<TypeManager> const& manager,
+                 OUString const& name, 
rtl::Reference<unoidl::InterfaceTypeEntity> const& entity,
+                 bool forReference)
 {
     for (auto const& meth : entity->getDirectMethods())
     {
         if (forReference)
         {
-            dumpWrapper(manager, name, meth, true);
+            dumpWrapper(out, manager, name, meth, true);
         }
         else if (std::any_of(
                      meth.parameters.begin(), meth.parameters.end(), [](auto 
const& parameter) {
@@ -391,15 +436,45 @@ void dumpMethods(rtl::Reference<TypeManager> const& 
manager, OUString const& nam
                                 != 
unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN;
                      }))
         {
-            dumpWrapper(manager, name, meth, false);
+            dumpWrapper(out, manager, name, meth, false);
         }
         else
         {
-            std::cout << "        .function(\"" << meth.name << "\", &" << 
cppName(name)
-                      << "::" << meth.name << ")
";
+            out << "        .function(\"" << meth.name << "\", &" << 
cppName(name)
+                << "::" << meth.name << ")
";
         }
     }
 }
+
+void writeJsMap(std::ostream& out, Module const& module, std::string const& 
prefix)
+{
+    auto comma = false;
+    for (auto const& ifc : module.interfaces)
+    {
+        if (comma)
+        {
+            out << ",
";
+        }
+        out << prefix << "'" << ifc.copy(ifc.lastIndexOf('.') + 1) << "': 
Module." << jsName(ifc)
+            << "Ref";
+        comma = true;
+    }
+    for (auto const & [ id, sub ] : module.modules)
+    {
+        if (comma)
+        {
+            out << ",
";
+        }
+        out << prefix << "'" << id << "': {
";
+        writeJsMap(out, *sub, prefix + "    ");
+        out << prefix << "}";
+        comma = true;
+    }
+    if (comma)
+    {
+        out << "
";
+    }
+}
 }
 
 SAL_IMPLEMENT_MAIN()
@@ -407,14 +482,16 @@ SAL_IMPLEMENT_MAIN()
     try
     {
         auto const args = rtl_getAppCommandArgCount();
-        if (args == 0)
+        if (args < 3)
         {
             badUsage();
         }
-        OUString prefix;
-        rtl_getAppCommandArg(0, &prefix.pData);
+        OUString name;
+        rtl_getAppCommandArg(0, &name.pData);
+        auto const cppPathname = getPathnameArgument(1);
+        auto const jsPathname = getPathnameArgument(2);
         rtl::Reference<TypeManager> mgr(new TypeManager);
-        for (sal_uInt32 i = 1; i != args; ++i)
+        for (sal_uInt32 i = 3; i != args; ++i)
         {
             auto const & [ uri, primary ] = parseRegistryArgument(i);
             try
@@ -427,67 +504,99 @@ SAL_IMPLEMENT_MAIN()
                 std::exit(EXIT_FAILURE);
             }
         }
+        auto const module = std::make_shared<Module>();
         std::vector<OUString> interfaces;
         for (auto const& prov : mgr->getPrimaryProviders())
         {
-            scan(prov->createRootCursor(), u"", interfaces);
+            scan(prov->createRootCursor(), u"", module.get(), interfaces);
         }
-        std::cout << "#include <emscripten/bind.h>
"
-                     "#include <com/sun/star/uno/Any.hxx>
"
-                     "#include <com/sun/star/uno/Reference.hxx>
";
+        std::ofstream cppOut(cppPathname, std::ios_base::out | 
std::ios_base::trunc);
+        if (!cppOut)
+        {
+            std::cerr << "Cannot open \"" << cppPathname << "\" for writing
";
+            std::exit(EXIT_FAILURE);
+        }
+        cppOut << "#include <emscripten/bind.h>
"
+                  "#include <com/sun/star/uno/Any.hxx>
"
+                  "#include <com/sun/star/uno/Reference.hxx>
";
         for (auto const& ifc : interfaces)
         {
-            std::cout << "#include <" << ifc.replace('.', '/') << ".hpp>
";
+            cppOut << "#include <" << ifc.replace('.', '/') << ".hpp>
";
         }
-        std::cout << "
"
-                     "// TODO: This is a temporary workaround that likely 
causes the Embind UNO
"
-                     "// bindings to leak memory. Reference counting and 
cloning mechanisms of
"
-                     "// Embind should be investigated to figure out what 
exactly we need here:
"
-                     "namespace emscripten::internal {
";
+        cppOut << "
"
+                  "// TODO: This is a temporary workaround that likely causes 
the Embind UNO
"
+                  "// bindings to leak memory. Reference counting and cloning 
mechanisms of
"
+                  "// Embind should be investigated to figure out what exactly 
we need here:
"
+                  "namespace emscripten::internal {
";
         for (auto const& ifc : interfaces)
         {
-            std::cout << "    template<> void raw_destructor<" << cppName(ifc) 
<< ">("
-                      << cppName(ifc) << " *) {}
";
+            cppOut << "    template<> void raw_destructor<" << cppName(ifc) << 
">(" << cppName(ifc)
+                   << " *) {}
";
         }
-        std::cout << "}

"
-                     "EMSCRIPTEN_BINDINGS(uno_bindings_"
-                  << prefix << ") {
";
+        cppOut << "}

"
+                  "EMSCRIPTEN_BINDINGS(unoembind_"
+               << name << ") {
";
         for (auto const& ifc : interfaces)
         {
             auto const ent = mgr->getManager()->findEntity(ifc);
             assert(ent.is());
             assert(ent->getSort() == unoidl::Entity::SORT_INTERFACE_TYPE);
             rtl::Reference const 
ifcEnt(static_cast<unoidl::InterfaceTypeEntity*>(ent.get()));
-            std::cout << "    ::emscripten::class_<" << cppName(ifc) << ">(\"" 
<< jsName(ifc)
-                      << "\")
";
-            dumpAttributes(ifc, ifcEnt);
-            dumpMethods(mgr, ifc, ifcEnt, false);
-            std::cout << "        ;
"
-                         "    
::emscripten::class_<::com::sun::star::uno::Reference<"
-                      << cppName(ifc)
-                      << ">, 
::emscripten::base<::com::sun::star::uno::BaseReference>>(\""
-                      << jsName(ifc)
-                      << "Ref\")
"
-                         "        .constructor<>()
"
-                         "        
.constructor<::com::sun::star::uno::BaseReference, "
-                         "::com::sun::star::uno::UnoReference_Query>()
"
-                         "        .function(\"is\", 
&::com::sun::star::uno::Reference<"
-                      << cppName(ifc)
-                      << ">::is)
"
-                         "        .function(\"get\", 
&::com::sun::star::uno::Reference<"
-                      << cppName(ifc)
-                      << ">::get, ::emscripten::allow_raw_pointers())
"
-                         "        .function(\"set\", "
-                         
"::emscripten::select_overload<bool(::com::sun::star::uno::Any const "
-                         "&, "
-                         
"com::sun::star::uno::UnoReference_Query)>(&::com::sun::star::uno::"
-                         "Reference<"
-                      << cppName(ifc) << ">::set))
";
-            dumpAttributes(ifc, ifcEnt);
-            dumpMethods(mgr, ifc, ifcEnt, true);
-            std::cout << "        ;
";
+            cppOut << "    ::emscripten::class_<" << cppName(ifc) << ">(\"" << 
jsName(ifc)
+                   << "\")
";
+            dumpAttributes(cppOut, ifc, ifcEnt);
+            dumpMethods(cppOut, mgr, ifc, ifcEnt, false);
+            cppOut << "        ;
"
+                      "    
::emscripten::class_<::com::sun::star::uno::Reference<"
+                   << cppName(ifc)
+                   << ">, 
::emscripten::base<::com::sun::star::uno::BaseReference>>(\""
+                   << jsName(ifc)
+                   << "Ref\")
"
+                      "        .constructor<>()
"
+                      "        
.constructor<::com::sun::star::uno::BaseReference, "
+                      "::com::sun::star::uno::UnoReference_Query>()
"
+                      "        .function(\"is\", 
&::com::sun::star::uno::Reference<"
+                   << cppName(ifc)
+                   << ">::is)
"
+                      "        .function(\"get\", 
&::com::sun::star::uno::Reference<"
+                   << cppName(ifc)
+                   << ">::get, ::emscripten::allow_raw_pointers())
"
+                      "        .function(\"set\", "
+                      
"::emscripten::select_overload<bool(::com::sun::star::uno::Any const "
+                      "&, "
+                      
"com::sun::star::uno::UnoReference_Query)>(&::com::sun::star::uno::"
+                      "Reference<"
+                   << cppName(ifc) << ">::set))
";
+            dumpAttributes(cppOut, ifc, ifcEnt);
+            dumpMethods(cppOut, mgr, ifc, ifcEnt, true);
+            cppOut << "        ;
";
+        }
+        cppOut << "}
";
+        cppOut.close();
+        if (!cppOut)
+        {
+            std::cerr << "Failed to write \"" << cppPathname << "\"
";
+            std::exit(EXIT_FAILURE);
+        }
+        std::ofstream jsOut(jsPathname, std::ios_base::out | 
std::ios_base::trunc);
+        if (!jsOut)
+        {
+            std::cerr << "Cannot open \"" << jsPathname << "\" for writing
";
+            std::exit(EXIT_FAILURE);
+        }
+        jsOut << "Module.init_unoembind_" << name
+              << " = function() {
"
+                 "    Module.unoembind_"
+              << name << " = {
";
+        writeJsMap(jsOut, *module, "        ");
+        jsOut << "    };
"
+                 "};
";
+        jsOut.close();
+        if (!jsOut)
+        {
+            std::cerr << "Failed to write \"" << jsPathname << "\"
";
+            std::exit(EXIT_FAILURE);
         }
-        std::cout << "}
";
         return EXIT_SUCCESS;
     }
     catch (unoidl::FileFormatException const& e)

Reply via email to