Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/LibreOffice/desktop/source/pkgchk/unopkg/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 26 kB image not shown  

Quelle  unopkg_app.cxx   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * 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/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you 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 .
 */



#include <dp_misc.h>
#include "unopkg_main.h"
#include "unopkg_shared.h"
#include <dp_identifier.hxx>
#include <tools/extendapplicationenvironment.hxx>
#include <rtl/bootstrap.hxx>
#include <rtl/textenc.h>
#include <rtl/ustring.hxx>
#include <osl/process.h>
#include <osl/conditn.hxx>
#include <unotools/tempfile.hxx>
#include <cppuhelper/implbase.hxx>
#include <cppuhelper/exc_hlp.hxx>
#include <comphelper/anytostring.hxx>
#include <comphelper/logging.hxx>
#include <comphelper/sequence.hxx>
#include <com/sun/star/deployment/DeploymentException.hpp>
#include <com/sun/star/deployment/ExtensionManager.hpp>

#include <com/sun/star/deployment/ui/PackageManagerDialog.hpp>
#include <com/sun/star/lang/IllegalArgumentException.hpp>
#include <com/sun/star/logging/ConsoleHandler.hpp>
#include <com/sun/star/logging/FileHandler.hpp>
#include <com/sun/star/logging/LogLevel.hpp>
#include <com/sun/star/logging/SimpleTextFormatter.hpp>
#include <com/sun/star/logging/XLogger.hpp>
#include <com/sun/star/ucb/CommandAbortedException.hpp>
#include <com/sun/star/ucb/CommandFailedException.hpp>
#include <com/sun/star/ui/dialogs/XDialogClosedListener.hpp>
#if defined(UNX)
  #include <unistd.h>
#endif
#include <iostream>
#include <utility>
#include <vector>


using namespace ::com::sun::star;
using namespace ::com::sun::star::logging;
using namespace ::com::sun::star::uno;
using namespace ::unopkg;

namespace {

struct ExtensionName
{
    OUString m_str;
    explicit ExtensionName( OUString str ) : m_str(std::move( str )) {}
    bool operator () ( Reference<deployment::XPackage> const & e ) const
    {
        return m_str == dp_misc::getIdentifier(e)
             ||  m_str == e->getName();
    }
};


const char16_t s_usingText [] =
u"\n"
"using: " APP_NAME " add extension-path...\n"
" " APP_NAME " validate extension-identifier...\n"
" " APP_NAME " remove extension-identifier...\n"
" " APP_NAME " list extension-identifier...\n"
" " APP_NAME " reinstall \n"
" " APP_NAME " gui\n"
" " APP_NAME " -V\n"
" " APP_NAME " -h\n"
"\n"
"sub-commands:\n"
" add add extension\n"
" validate checks the prerequisites of an installed extension and\n"
" registers it if possible\n"
" remove remove extensions by identifier\n"
" reinstall expert feature: reinstall all deployed extensions\n"
" list list information about deployed extensions\n"
" gui raise Extensions dialog\n"
"\n"
"options:\n"
" -h, --help this help\n"
" -V, --version version information\n"
" -v, --verbose verbose output\n"
" -f, --force force overwriting existing extensions\n"
" -s, --suppress-license prevents showing the license\n"
" --log-file custom log file; default: /log.txt\n"
" --shared expert feature: operate on shared installation\n"
" deployment context;\n"
" run only when no concurrent Office\n"
" process(es) are running!\n"
" --bundled expert feature: operate on bundled extensions. Only\n"
" works with list, validate, reinstall;\n"
" --deployment-context expert feature: explicit deployment context\n"
" \n"
"\n"
"To learn more about extensions, see:\n"
"https://wiki.documentfoundation.org/Documentation/DevGuide/Extensions\n\n";


const OptionInfo s_option_infos [] = {
    { RTL_CONSTASCII_STRINGPARAM("help"), 'h'false },
    { RTL_CONSTASCII_STRINGPARAM("version"), 'V'false },
    { RTL_CONSTASCII_STRINGPARAM("verbose"), 'v'false },
    { RTL_CONSTASCII_STRINGPARAM("force"), 'f'false },
    { RTL_CONSTASCII_STRINGPARAM("log-file"), '\0'true },
    { RTL_CONSTASCII_STRINGPARAM("shared"), '\0'false },
    { RTL_CONSTASCII_STRINGPARAM("deployment-context"), '\0'true },
    { RTL_CONSTASCII_STRINGPARAM("bundled"), '\0'false},
    { RTL_CONSTASCII_STRINGPARAM("suppress-license"), 's'false},

    { nullptr, 0, '\0'false }
};

void logFatal(
    comphelper::EventLogger const * logger, sal_Int32 level, OUString const & message,
    OUString const & argument)
{
    if (logger == nullptr) {
        // Best effort; potentially loses data due to conversion failures (stray surrogate halves)
        // and embedded null characters:
        std::cerr
            << OUStringToOString(message.replaceFirst("$1$", argument), RTL_TEXTENCODING_UTF8)
            << '\n';
    } else {
        logger->log(level, message, argument);
    }
}

class DialogClosedListenerImpl :
    public ::cppu::WeakImplHelper< ui::dialogs::XDialogClosedListener >
{
    osl::Condition & m_rDialogClosedCondition;

public:
    explicit DialogClosedListenerImpl( osl::Condition & rDialogClosedCondition )
        : m_rDialogClosedCondition( rDialogClosedCondition ) {}

    // XEventListener (base of XDialogClosedListener)
    virtual void SAL_CALL disposing( lang::EventObject const & Source ) override;

    // XDialogClosedListener
    virtual void SAL_CALL dialogClosed(
        ui::dialogs::DialogClosedEvent const & aEvent ) override;
};

// XEventListener (base of XDialogClosedListener)
void DialogClosedListenerImpl::disposing( lang::EventObject const & )
{
    // nothing to do
}

// XDialogClosedListener
void DialogClosedListenerImpl::dialogClosed(
    ui::dialogs::DialogClosedEvent const & )
{
    m_rDialogClosedCondition.set();
}

// If a package had been installed with a pre OOo 2.2, it could not normally be
// found via its identifier; similarly (and for ease of use), a package
// installed with OOo 2.2 or later could not normally be found via its file
// name.
Reference<deployment::XPackage> findPackage(
    OUString const & repository,
    Reference<deployment::XExtensionManager> const & manager,
    Reference<ucb::XCommandEnvironment > const & environment,
    std::u16string_view idOrFileName )
{
    const Sequence< Reference<deployment::XPackage> > ps(
        manager->getDeployedExtensions(repository,
            Reference<task::XAbortChannel>(), environment ) );
    for ( auto const & package : ps )
        if ( dp_misc::getIdentifier( package ) == idOrFileName )
            return package;
    for ( auto const & package : ps )
        if ( package->getName() == idOrFileName )
            return package;
    return Reference<deployment::XPackage>();
}

// anon namespace

extern "C" int unopkg_main()
{
    tools::extendApplicationEnvironment();
    bool bShowFailedMsg = true;
    OUString subCommand;
    bool option_shared = false;
    bool option_force = false;
    bool option_verbose = false;
    bool option_bundled = false;
    bool option_suppressLicense = false;
    bool option_help = false;
    bool subcmd_gui = false;
    OUString logFile;
    OUString repository;
    OUString cmdArg;
    std::vector<OUString> cmdPackages;
    Reference<XLogHandler> xFileHandler;
    Reference<XLogHandler> xConsoleHandler;
    std::unique_ptr<comphelper::EventLogger> logger;
    std::unique_ptr<utl::TempFileNamed> pUserProfileTempDir;

    OptionInfo const * info_shared = getOptionInfo(
        s_option_infos, u"shared"_ustr );
    OptionInfo const * info_force = getOptionInfo(
        s_option_infos, u"force"_ustr );
    OptionInfo const * info_verbose = getOptionInfo(
        s_option_infos, u"verbose"_ustr );
    OptionInfo const * info_log = getOptionInfo(
        s_option_infos, u"log-file"_ustr );
    OptionInfo const * info_context = getOptionInfo(
        s_option_infos, u"deployment-context"_ustr );
    OptionInfo const * info_help = getOptionInfo(
        s_option_infos, u"help"_ustr );
    OptionInfo const * info_version = getOptionInfo(
        s_option_infos, u"version"_ustr );
    OptionInfo const * info_bundled = getOptionInfo(
        s_option_infos, u"bundled"_ustr );
    OptionInfo const * info_suppressLicense = getOptionInfo(
        s_option_infos, u"suppress-license"_ustr );


    Reference<XComponentContext> xComponentContext;
    Reference<XComponentContext> xLocalComponentContext;

    try {
        sal_uInt32 nPos = 0;
        sal_uInt32 nCount = osl_getCommandArgCount();
        if (nCount == 0 || isOption( info_help, &nPos ))
        {
            dp_misc::writeConsole(s_usingText);
            return 0;
        }
        else if (isOption( info_version, &nPos )) {
            dp_misc::writeConsole(u"\n" APP_NAME " Version 3.3\n");
            return 0;
        }
        //consume all bootstrap variables which may occur before the sub-command
        while(isBootstrapVariable(&nPos))
            ;

        if(nPos >= nCount)
            return 0;
        //get the sub-command
        osl_getCommandArg( nPos, &subCommand.pData );
        ++nPos;
        subCommand = subCommand.trim();
        bool subcmd_add = subCommand == "add";
        subcmd_gui = subCommand == "gui";

        // sub-command options and packages:
        while (nPos < nCount)
        {
            if (readArgument( &cmdArg, info_log, &nPos )) {
                logFile = makeAbsoluteFileUrl(
                    cmdArg.trim(), getProcessWorkingDir() );
            }
            else if (!readOption( &option_verbose, info_verbose, &nPos ) &&
                     !readOption( &option_shared, info_shared, &nPos ) &&
                     !readOption( &option_force, info_force, &nPos ) &&
                     !readOption( &option_bundled, info_bundled, &nPos ) &&
                     !readOption( &option_suppressLicense, info_suppressLicense, &nPos ) &&
                     !readOption( &option_help, info_help, &nPos ) &&
                     !readArgument( &repository, info_context, &nPos ) &&
                     !isBootstrapVariable(&nPos))
            {
                osl_getCommandArg( nPos, &cmdArg.pData );
                ++nPos;
                cmdArg = cmdArg.trim();
                if (!cmdArg.isEmpty())
                {
                    if (cmdArg[ 0 ] == '-')
                    {
                        // is option:
                        dp_misc::writeConsoleError(Concat2View(
                                 "\nERROR: unexpected option " +
                                 cmdArg +
                                 "!\n Use " APP_NAME " " +
                                 toString(info_help) +
                                 " to print all options.\n"));
                        return 1;
                    }
                    else
                    {
                        // is package:
                        cmdPackages.push_back(
                            subcmd_add || subcmd_gui
                            ? makeAbsoluteFileUrl(
                                cmdArg, getProcessWorkingDir() )
                            : cmdArg );
                    }
                }
            }
        }

        // tdf#129917 Use temp user profile when installing shared extensions
        if (option_shared)
        {
            pUserProfileTempDir.reset(new utl::TempFileNamed(nullptr, true));
            pUserProfileTempDir->EnableKillingFile();
        }

        xComponentContext = getUNO(option_verbose, subcmd_gui,
                                   pUserProfileTempDir ? pUserProfileTempDir->GetURL() : u""_ustr,
                                   xLocalComponentContext);

        // Initialize logging. This will log errors to the console and
        // also to file if the --log-file parameter was provided.
        logger.reset(new comphelper::EventLogger(xLocalComponentContext, "unopkg"));
        const Reference<XLogger> xLogger(logger->getLogger());
        xLogger->setLevel(LogLevel::WARNING);
        Reference<XLogFormatter> xLogFormatter(SimpleTextFormatter::create(xLocalComponentContext));
        Sequence < beans::NamedValue > aSeq { { u"Formatter"_ustr, Any(xLogFormatter) } };

        xConsoleHandler.set(ConsoleHandler::createWithSettings(xLocalComponentContext, aSeq));
        xLogger->addLogHandler(xConsoleHandler);
        xConsoleHandler->setLevel(LogLevel::WARNING);
        xLogger->setLevel(LogLevel::WARNING);


        if (!logFile.isEmpty())
        {
            Sequence < beans::NamedValue > aSeq2 { { u"Formatter"_ustr, Any(xLogFormatter) }, {u"FileURL"_ustr, Any(logFile)} };
            xFileHandler.set(css::logging::FileHandler::createWithSettings(xLocalComponentContext, aSeq2));
            xFileHandler->setLevel(LogLevel::WARNING);
            xLogger->addLogHandler(xFileHandler);
        }

        if (option_verbose)
        {
            xLogger->setLevel(LogLevel::INFO);
            xConsoleHandler->setLevel(LogLevel::INFO);
            if (xFileHandler.is())
                xFileHandler->setLevel(LogLevel::INFO);
        }

        if (repository.isEmpty())
        {
            if (option_shared)
                repository = "shared";
            else if (option_bundled)
                repository = "bundled";
            else
                repository = "user";
        }
        else
        {
            if ( repository == "shared" ) {
                option_shared = true;
            }
            else if (option_shared)
            {
                logger->log(LogLevel::WARNING, "Explicit context given! Ignoring option '$1$'",  toString(info_shared));
            }
        }
#if defined(UNX)
        if ( geteuid() == 0 )
        {
            if ( !(option_shared || option_bundled || option_help) )
            {
                logger->log(LogLevel::SEVERE, "Cannot run $1$ as root without $2$ or $3$ option.",
                           APP_NAME, toString(info_shared), toString(info_bundled));
                return 1;
            }
        }
#endif

        if (subCommand == "reinstall")
        {
            //We must prevent that services and types are loaded by UNO,
            //otherwise we cannot delete the registry data folder.
            OUString extensionUnorc;
            if (repository == "user")
                extensionUnorc = "$UNO_USER_PACKAGES_CACHE/registry/com.sun.star.comp.deployment.component.PackageRegistryBackend/unorc";
            else if (repository == "shared")
                extensionUnorc = "$SHARED_EXTENSIONS_USER/registry/com.sun.star.comp.deployment.component.PackageRegistryBackend/unorc";
            else if (repository == "bundled")
                extensionUnorc = "$BUNDLED_EXTENSIONS_USER/registry/com.sun.star.comp.deployment.component.PackageRegistryBackend/unorc";
            else
                OSL_ASSERT(false);

            ::rtl::Bootstrap::expandMacros(extensionUnorc);
            oslFileError e = osl_removeFile(extensionUnorc.pData);
            if (e != osl_File_E_None && e != osl_File_E_NOENT)
                throw Exception("Could not delete " + extensionUnorc, nullptr);
        }

        Reference<deployment::XExtensionManager> xExtensionManager(
            deployment::ExtensionManager::get( xComponentContext ) );

        Reference<css::ucb::XCommandEnvironment> xCmdEnv(
            createCmdEnv(xComponentContext, option_force, option_verbose, option_suppressLicense));

        //synchronize bundled/shared extensions
        //Do not synchronize when command is "reinstall". This could add types and services to UNO and
        //prevent the deletion of the registry data folder
        //syncing is done in XExtensionManager.reinstall
        if (!subcmd_gui && subCommand != "reinstall"
            && ! dp_misc::office_is_running())
            dp_misc::syncRepositories(false, xCmdEnv);

        if ( subcmd_add || subCommand == "remove" )
        {
            for (const OUString & cmdPackage : cmdPackages)
            {
                if (subcmd_add)
                {
                    beans::NamedValue nvSuppress(
                        u"SUPPRESS_LICENSE"_ustr, option_suppressLicense ?
                        Any(u"1"_ustr):Any(u"0"_ustr));
                    xExtensionManager->addExtension(
                            cmdPackage, Sequence<beans::NamedValue>(&nvSuppress, 1),
                            repository, Reference<task::XAbortChannel>(), xCmdEnv);
                }
                else
                {
                    try
                    {
                        xExtensionManager->removeExtension(
                            cmdPackage, cmdPackage, repository,
                            Reference<task::XAbortChannel>(), xCmdEnv );
                    }
                    catch (const lang::IllegalArgumentException &)
                    {
                        Reference<deployment::XPackage> p(
                             findPackage(repository,
                                xExtensionManager, xCmdEnv, cmdPackage ) );
                        if ( !p.is())
                            throw;
                        else if (p.is())
                            xExtensionManager->removeExtension(
                                ::dp_misc::getIdentifier(p), p->getName(),
                                repository,
                                Reference<task::XAbortChannel>(), xCmdEnv );
                    }
                }
            }
        }
        else if ( subCommand == "reinstall" )
        {
            xExtensionManager->reinstallDeployedExtensions(
                false, repository, Reference<task::XAbortChannel>(), xCmdEnv);
        }
        else if ( subCommand == "list" )
        {
            std::vector<Reference<deployment::XPackage> > vecExtUnaccepted;
            ::comphelper::sequenceToContainer(vecExtUnaccepted,
                    xExtensionManager->getExtensionsWithUnacceptedLicenses(
                        repository, xCmdEnv));

            //This vector tells what XPackage  in allExtensions has an
            //unaccepted license.
            std::vector<bool> vecUnaccepted;
            std::vector<Reference<deployment::XPackage> > allExtensions;
            if (cmdPackages.empty())
            {
                Sequence< Reference<deployment::XPackage> >
                    packages = xExtensionManager->getDeployedExtensions(
                        repository, Reference<task::XAbortChannel>(), xCmdEnv );

                std::vector<Reference<deployment::XPackage> > vec_packages;
                ::comphelper::sequenceToContainer(vec_packages, packages);

                //First copy the extensions with the unaccepted license
                //to vector allExtensions.
                allExtensions.resize(vecExtUnaccepted.size() + vec_packages.size());

                std::vector<Reference<deployment::XPackage> >::iterator i_all_ext =
                      std::copy(vecExtUnaccepted.begin(), vecExtUnaccepted.end(),
                                  allExtensions.begin());
                //Now copy those we got from getDeployedExtensions
                std::copy(vec_packages.begin(), vec_packages.end(), i_all_ext);

                //Now prepare the vector which tells what extension has an
                //unaccepted license
                vecUnaccepted.resize(vecExtUnaccepted.size() + vec_packages.size());
                std::fill_n(vecUnaccepted.begin(), vecExtUnaccepted.size(), true);
                std::fill_n(vecUnaccepted.begin() + vecExtUnaccepted.size(),
                      vec_packages.size(), false);

                dp_misc::writeConsole(
                    Concat2View("All deployed " + repository + " extensions:\n\n"));
            }
            else
            {
                //The user provided the names (ids or file names) of the extensions
                //which shall be listed
                for (const OUString & cmdPackage : cmdPackages)
                {
                    Reference<deployment::XPackage> extension;
                    try
                    {
                        extension = xExtensionManager->getDeployedExtension(
                            repository, cmdPackage, cmdPackage, xCmdEnv );
                    }
                    catch (const lang::IllegalArgumentException &)
                    {
                        extension = findPackage(repository,
                            xExtensionManager, xCmdEnv, cmdPackage );
                    }

                    //Now look if the requested extension has an unaccepted license
                    bool bUnacceptedLic = false;
                    if (!extension.is())
                    {
                        std::vector<Reference<deployment::XPackage> >::const_iterator
                            i = std::find_if(
                                vecExtUnaccepted.begin(),
                                vecExtUnaccepted.end(), ExtensionName(cmdPackage));
                        if (i != vecExtUnaccepted.end())
                        {
                            extension = *i;
                            bUnacceptedLic = true;
                        }
                    }

                    if (!extension.is())
                        throw lang::IllegalArgumentException(
                            "There is no such extension deployed: " +
                            cmdPackage,nullptr,-1);
                    allExtensions.push_back(extension);
                    vecUnaccepted.push_back(bUnacceptedLic);
                }

            }

            printf_packages(allExtensions, vecUnaccepted, xCmdEnv );
        }
        else if ( subCommand == "validate" )
        {
            std::vector<Reference<deployment::XPackage> > vecExtUnaccepted;
            ::comphelper::sequenceToContainer(
                vecExtUnaccepted, xExtensionManager->getExtensionsWithUnacceptedLicenses(
                    repository, xCmdEnv));

            for (const OUString & cmdPackage : cmdPackages)
            {
                Reference<deployment::XPackage> extension;
                try
                {
                    extension = xExtensionManager->getDeployedExtension(
                        repository, cmdPackage, cmdPackage, xCmdEnv );
                }
                catch (const lang::IllegalArgumentException &)
                {
                    extension = findPackage(
                        repository, xExtensionManager, xCmdEnv, cmdPackage );
                }

                if (!extension.is())
                {
                    std::vector<Reference<deployment::XPackage> >::const_iterator
                        i = std::find_if(
                            vecExtUnaccepted.begin(),
                            vecExtUnaccepted.end(), ExtensionName(cmdPackage));
                    if (i != vecExtUnaccepted.end())
                    {
                        extension = *i;
                    }
                }

                if (extension.is())
                    xExtensionManager->checkPrerequisitesAndEnable(
                        extension, Reference<task::XAbortChannel>(), xCmdEnv);
            }
        }
        else if ( subCommand == "gui" )
        {
            Reference<ui::dialogs::XAsynchronousExecutableDialog> xDialog(
                deployment::ui::PackageManagerDialog::createAndInstall(
                    xComponentContext,
                    !cmdPackages.empty() ? cmdPackages[0] : OUString() ));

            osl::Condition dialogEnded;
            dialogEnded.reset();

            Reference< ui::dialogs::XDialogClosedListener > xListener(
                new DialogClosedListenerImpl( dialogEnded ) );

            xDialog->startExecuteModal(xListener);
            dialogEnded.wait();
            return 0;
        }
        else
        {
            logger->log(LogLevel::SEVERE,
                       "Unknown sub-command: '$1$'. Use $2$ $3$ to print all options.",
                       subCommand, APP_NAME, toString(info_help));
            return 1;
        }

        logger->log(LogLevel::INFO, "$1$ done.", APP_NAME);
        //Force to release all bridges which connect us to the child processes
        dp_misc::disposeBridges(xLocalComponentContext);
        css::uno::Reference<css::lang::XComponent>(
            xLocalComponentContext, css::uno::UNO_QUERY_THROW)->dispose();
        return 0;
    }
    catch (const ucb::CommandFailedException &e)
    {
        logFatal(logger.get(), LogLevel::SEVERE, u"Exception occurred: $1$"_ustr, e.Message);
    }
    catch (const ucb::CommandAbortedException &)
    {
        logFatal(logger.get(), LogLevel::SEVERE, u"$1$ aborted."_ustr, u"" APP_NAME ""_ustr);
        bShowFailedMsg = false;
    }
    catch (const deployment::DeploymentException & exc)
    {
        logFatal(logger.get(), LogLevel::SEVERE, u"Exception occurred: $1$"_ustr, exc.Message);
        logFatal(
            logger.get(), LogLevel::INFO, u" Cause: $1$"_ustr, comphelper::anyToString(exc.Cause));
    }
    catch (const LockFileException & e)
    {
        // No logger since it requires UNO which we don't have here
        dp_misc::writeConsoleError(Concat2View(e.Message + "\n"));
        bShowFailedMsg = false;
    }
    catch (const css::uno::Exception & e ) {
        Any exc( ::cppu::getCaughtException() );

        logFatal(logger.get(), LogLevel::SEVERE, u"Exception occurred: $1$"_ustr, e.Message);
        logFatal(logger.get(), LogLevel::INFO, u" Cause: $1$"_ustr, comphelper::anyToString(exc));
    }
    if (bShowFailedMsg)
        logFatal(logger.get(), LogLevel::SEVERE, u"$1$ failed."_ustr, u"" APP_NAME ""_ustr);
    dp_misc::disposeBridges(xLocalComponentContext);
    if (xLocalComponentContext.is()) {
        css::uno::Reference<css::lang::XComponent>(
            xLocalComponentContext, css::uno::UNO_QUERY_THROW)->dispose();
    }
    return 1;
}


/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5
C=88 H=97 G=92

¤ Dauer der Verarbeitung: 0.3 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.