<commit_before>// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

#include "core/optimizer/initializer.h"
#include "core/optimizer/matmul_add_fusion.h"
#include "core/graph/graph_utils.h"
#include <deque>

using namespace ONNX_NAMESPACE;
using namespace ::onnxruntime::common;
namespace onnxruntime {

Status MatMulAddFusion::ApplyImpl(Graph& graph, bool& modified, int graph_level) const {
  GraphViewer graph_viewer(graph);
  const auto& node_topology_list = graph_viewer.GetNodesInTopologicalOrder();
  std::deque<onnxruntime::NodeIndex> removed_nodes;

  for (auto node_index : node_topology_list) {
    auto& node = *graph.GetNode(node_index);
    ORT_RETURN_IF_ERROR(Recurse(node, modified, graph_level));

    if (!graph_utils::IsSupportedOptypeVersionAndDomain(node, "MatMul", {1, 9}) ||
        !graph_utils::IsSupportedProvider(node, GetCompatibleExecutionProviders()) ||
        node.GetOutputEdgesCount() != 1) {
      continue;
    }

    auto next_node_itr = node.OutputNodesBegin();
    if (next_node_itr == node.OutputNodesEnd()) {
      continue;
    }

    const Node& next_node = (*next_node_itr);
    if (!graph_utils::IsSupportedOptypeVersionAndDomain(next_node, "Add", {7}) ||
        next_node.GetExecutionProviderType() != node.GetExecutionProviderType()) {
      continue;
    }

    Node& matmul_node = node;
    Node& add_node = const_cast<Node&>(next_node);
    std::vector<NodeArg> input_args;
    std::vector<NodeArg> output_args;
    auto matmul_input_defs = matmul_node.MutableInputDefs();
    auto add_input_defs = add_node.MutableInputDefs();

    // Gemm only support float, so the inputs of MatMul
    auto matmul_type = matmul_input_defs[0]->Type();
    auto add_type = add_input_defs[0]->Type();
    if ((*matmul_type) != "tensor(float)" || (*add_type) != "tensor(float)") {
      continue;
    }

    // Gemm only support Matrix, need to check the shape of MatMul and Add
    auto matmul_a_shape = matmul_input_defs[0]->Shape();
    auto matmul_b_shape = matmul_input_defs[1]->Shape();
    if (nullptr == matmul_a_shape || nullptr == matmul_b_shape) {
      continue;
    }
    if (1 == matmul_a_shape->dim_size() && 2 == matmul_b_shape->dim_size()) {
      // MatMul has shape [K] * [K, N], reset it to [1, K] * [K, N], so that it can work for Gemm
      auto mutable_matmul_a_shape = const_cast<ONNX_NAMESPACE::TensorShapeProto*>(matmul_a_shape);
      auto dim_0 = mutable_matmul_a_shape->mutable_dim(0);
      auto dim_1 = (const_cast<ONNX_NAMESPACE::TensorShapeProto*>(matmul_a_shape))->add_dim();
      (*dim_1) = (*dim_0);
      dim_0->set_dim_value(1);
    }
    if (2 != matmul_a_shape->dim_size() || 2 != matmul_b_shape->dim_size()) {
      // Gemm only support Matrix
      continue;
    }

    auto matmul_output_name = matmul_node.OutputDefs()[0]->Name();
    auto gemm_input_defs = matmul_input_defs;
    if (matmul_output_name == add_input_defs[0]->Name()) {
      // matmul output as Add_A, should use Add_B as input C for gemm
      // Gemm only support unidirectional broadcast on C
      if (add_input_defs[1]->Shape()->dim_size() > 2) {
        continue;
      }
      gemm_input_defs.push_back(add_input_defs[1]);
    } else {
      // matmul output as Add_B, should use Add_A as input C for gemm
      // Gemm only support unidirectional broadcast on C
      if (add_input_defs[0]->Shape()->dim_size() > 2) {
        continue;
      }
      gemm_input_defs.push_back(add_input_defs[0]);
    }

    Node& gemm_node = graph.AddNode(graph.GenerateNodeName("gemm"),
                                    "Gemm",
                                    "fused Matmul and Add " + add_node.OpType(),
                                    gemm_input_defs,
                                    add_node.MutableOutputDefs());

    // Assign provider to this new node. Provider should be same as the provider for old node.
    gemm_node.SetExecutionProviderType(matmul_node.GetExecutionProviderType());

    removed_nodes.push_front(matmul_node.Index());
    removed_nodes.push_front(add_node.Index());
  }

  // Have to remove node in reversed order for now to walk around the issue in RemoveNode
  for (onnxruntime::NodeIndex removed_node : removed_nodes) {
    graph.RemoveNode(removed_node);
  }

  if (!removed_nodes.empty()) {
    modified = true;
  }

  return Status::OK();
}
}  // namespace onnxruntime
<commit_msg>Enable float16 MatMul+Add -> GEMM fusion for performance boost (#1506)<commit_after>// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

#include "core/optimizer/initializer.h"
#include "core/optimizer/matmul_add_fusion.h"
#include "core/graph/graph_utils.h"
#include <deque>

using namespace ONNX_NAMESPACE;
using namespace ::onnxruntime::common;
namespace onnxruntime {

Status MatMulAddFusion::ApplyImpl(Graph& graph, bool& modified, int graph_level) const {
  GraphViewer graph_viewer(graph);
  const auto& node_topology_list = graph_viewer.GetNodesInTopologicalOrder();
  std::deque<onnxruntime::NodeIndex> removed_nodes;

  for (auto node_index : node_topology_list) {
    auto& node = *graph.GetNode(node_index);
    ORT_RETURN_IF_ERROR(Recurse(node, modified, graph_level));

    if (!graph_utils::IsSupportedOptypeVersionAndDomain(node, "MatMul", {1, 9}) ||
        !graph_utils::IsSupportedProvider(node, GetCompatibleExecutionProviders()) ||
        node.GetOutputEdgesCount() != 1) {
      continue;
    }

    auto next_node_itr = node.OutputNodesBegin();
    if (next_node_itr == node.OutputNodesEnd()) {
      continue;
    }

    const Node& next_node = (*next_node_itr);
    if (!graph_utils::IsSupportedOptypeVersionAndDomain(next_node, "Add", {7}) ||
        next_node.GetExecutionProviderType() != node.GetExecutionProviderType()) {
      continue;
    }

    Node& matmul_node = node;
    Node& add_node = const_cast<Node&>(next_node);
    std::vector<NodeArg> input_args;
    std::vector<NodeArg> output_args;
    auto matmul_input_defs = matmul_node.MutableInputDefs();
    auto add_input_defs = add_node.MutableInputDefs();

    // Gemm requires that inputs be the same data type and both floating point (float32/float16).
    auto matmul_type = matmul_input_defs[0]->Type();
    auto add_type = add_input_defs[0]->Type();
    if ((*matmul_type) != (*add_type)) {
      continue;
    }
    if ((*matmul_type) != "tensor(float)" && (*matmul_type) != "tensor(float16)") {
      continue;
    }

    // Gemm only support Matrix, need to check the shape of MatMul and Add
    auto matmul_a_shape = matmul_input_defs[0]->Shape();
    auto matmul_b_shape = matmul_input_defs[1]->Shape();
    if (nullptr == matmul_a_shape || nullptr == matmul_b_shape) {
      continue;
    }
    if (1 == matmul_a_shape->dim_size() && 2 == matmul_b_shape->dim_size()) {
      // MatMul has shape [K] * [K, N], reset it to [1, K] * [K, N], so that it can work for Gemm
      auto mutable_matmul_a_shape = const_cast<ONNX_NAMESPACE::TensorShapeProto*>(matmul_a_shape);
      auto dim_0 = mutable_matmul_a_shape->mutable_dim(0);
      auto dim_1 = (const_cast<ONNX_NAMESPACE::TensorShapeProto*>(matmul_a_shape))->add_dim();
      (*dim_1) = (*dim_0);
      dim_0->set_dim_value(1);
    }
    if (2 != matmul_a_shape->dim_size() || 2 != matmul_b_shape->dim_size()) {
      // Gemm only support Matrix
      continue;
    }

    auto matmul_output_name = matmul_node.OutputDefs()[0]->Name();
    auto gemm_input_defs = matmul_input_defs;
    if (matmul_output_name == add_input_defs[0]->Name()) {
      // matmul output as Add_A, should use Add_B as input C for gemm
      // Gemm only support unidirectional broadcast on C
      if (add_input_defs[1]->Shape()->dim_size() > 2) {
        continue;
      }
      gemm_input_defs.push_back(add_input_defs[1]);
    } else {
      // matmul output as Add_B, should use Add_A as input C for gemm
      // Gemm only support unidirectional broadcast on C
      if (add_input_defs[0]->Shape()->dim_size() > 2) {
        continue;
      }
      gemm_input_defs.push_back(add_input_defs[0]);
    }

    Node& gemm_node = graph.AddNode(graph.GenerateNodeName("gemm"),
                                    "Gemm",
                                    "fused Matmul and Add " + add_node.OpType(),
                                    gemm_input_defs,
                                    add_node.MutableOutputDefs());

    // Assign provider to this new node. Provider should be same as the provider for old node.
    gemm_node.SetExecutionProviderType(matmul_node.GetExecutionProviderType());

    removed_nodes.push_front(matmul_node.Index());
    removed_nodes.push_front(add_node.Index());
  }

  // Have to remove node in reversed order for now to walk around the issue in RemoveNode
  for (onnxruntime::NodeIndex removed_node : removed_nodes) {
    graph.RemoveNode(removed_node);
  }

  if (!removed_nodes.empty()) {
    modified = true;
  }

  return Status::OK();
}
}  // namespace onnxruntime
<|endoftext|>


<commit_before>/** @mainpage TraceMiner 2
 *
 *  @author Norman Dunbar
 *  @copyright MIT Licence
 *
 * @tableofcontents
 *
 *  @section Introduction
 *
 * TraceMiner 2 is a new improved version of the old TraceMiner utility. It has
 * been completely rewritten in C++ rather than the old style vanilla C. This has made
 * things surprisingly easier to do in the new versions and has got around a whole pile
 * of crud and hacks in the previous version. There's no manual configuration required
 * before compiling for example.
 *
 * @section sec-free-source-code Free Source Code
 *
 * The source code for TraceMiner2 lives in GitHub at
 * https://github.com/NormanDunbar/TraceMiner2/.
 *
 * Feel free to clone the repository and make any desired changes you wish.
 *
 * You may, if you just want to compile and use the code, download the source as a
 * zip file from https://github.com/NormanDunbar/TraceMiner2/archive/master.zip.
 *
 * @section sec-compiling Compiling
 *
 * The source should be downloaded. Then simply compile all the *.cpp files using a C++
 * compiler that knows about the Standard Template Library (aka STL). This is the only
 * "weird" thing used by TraceMiner2. No other special libraries such as Boost, for
 * example, are required.
 *
 * @subsection sub-sec-with-codeblocks With CodeBlocks
 *
 * There's a CodeBlocks project file, `TraceMiner2.cbp`, located in the main source folder.
 * You may need to change some paths etc to use it. In my own setup, I have configured the
 * free Borland/Embarcadero C++ compiler, version 10.1, to be used. Get yours at
 * https://www.embarcadero.com/free-tools/ccompiler/start-for-free. CodeBlocks itself is
 * available at https://www.codeblocks.org.
 *
 * Once compiled, look here for your executable:
 *
 * @code
 * TraceMiner2-master\TraceMiner2\bin\release
 * @endcode
 *
 * @subsection sub-sec-with-borland With Borland/Embarcadero C++ 10.1
 *
 * Unzip the download zip file, then:
 *
 * @code
 * cd TraceMiner2-master\TraceMiner2
 * mkdir bin
 * bcc32c -o bin\TraceMiner2.exe *.cpp
 * @endcode
 *
 * Once compiled, look your executable will be:
 *
 * @code
 * TraceMiner2-master\TraceMiner2\bin\TraceMiner2.exe
 * @endcode
 *
 * Get a free copy of the compiler at https://www.embarcadero.com/free-tools/ccompiler/start-for-free.
 *
 * @subsection sub-sec-with-gpp With G++
 *
 * You can use the supplied Makefile.gnu, or just compile all the *.cpp files, as follows:
 *
 * @code
 * cd TraceMiner2-master/TraceMiner2
 * mkdir bin
 * g++ -o bin/TraceMiner2 *.cpp
 * @endcode
 *
 * The executable will be wherever you pointed it to be created with the '-o' option.
 *
 * @subsection sec-makefile With a Makefile
 *
 * @code
 * cd TraceMiner2-master
 * make -f makefile.gnu
 * @endcode
 *
 * Once compiled, look here for your executable:
 *
 * @code
 * TraceMiner2-master/TraceMiner2/bin
 * @endcode
 *
 * @section sec-execution Execution
 *
 * There is one mandatory parameter required, the trace file name. This must have the extension
 * ".trc" as generated by Oracle. The report file will have the ".trc" changed to ".txt" or
 * ".html" depending on whether you have requested a plain text or HTML report format.
 *
 * The report file will be created in the same location as the trace file and defaults to HTML format. This
 * is simply because the textual format is pretty dire with wide lines in many cases.
 *
 * If you choose to run in verbose mode, and you probably shouldn't, the output file for that
 * detail will be the same as the trace file name, but with the ".trc" extension replaced by
 * ".dbg". Once again, the output file will be in the same location as the trace file.
 *
 * The optional parameters are as follows:
 *
 * @li --verbose or -v - indicates that you wish to generate lots of output for debugging purposes.
 * @li --quiet or -q - indicates that you do not wish to see "Cursor: #cccc created at line: nnnn" messages.
 * on the screen while parsing is taking place. Any ERRORs or PARSE ERRORS will still be displayed.
 * @li --help -h or -? - indicates that you want help. The program will exit after displaying the
 * usage details.
 * @li --text or -t - indicates that you wish to have the report formatted in plain text as opposed to
 * HTML text. Good luck with that option! ;-)
 * @li --depth=n or -d=n - indicates the maximum depth of recursive cursors that you wish to report on
 * which is useful when a PL/SQL calls is at depth=0, you wouold be interested in depth=1, for example.
 * @li --pagesize=nn or -p=nn - indicates how many EXEC statements you wish to display in each HTML table
 * in the report. This meakes scrolling to the headings in long report files a lot easier!
 * @li --feedback=nn or -f=nn - indicates how often you want feedback on progress reading the trace file. Zero
 * disables feedback. The default is every 100,000 lines read. Useful on larger trace files.
 *
 * @section sec-mit-licence MIT Licence
 *
 * MIT License
 *
 * Copyright (c) 2017 Norman Dunbar
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/** @file TraceMiner2.cpp
 * @brief This is where it all starts. The main() function lives here.
 */

#include "TraceMiner2.h"
#include "utilities.h"
#include "favicon.h"

// Version number.
const float version = 0.07;

// Various flags set according to the passed parameters.
tmOptions options;

int main(int argc, char *argv[])
{
    // Make sure that cout/cerr gets comma/dot separated thousands etc.
    cout.imbue(locale(cout.getloc(), new ThousandsSeparator<char>(',')));
    cerr.imbue(locale(cerr.getloc(), new ThousandsSeparator<char>(',')));

    // Parse command line args and bale if problems detected.
    bool allOk = options.parseArgs(argc, argv);
    if (!allOk) {
        return 1;
    }

    // Show help and exit requested?
    if (options.help()) {
        return 0;
    }

    if (options.html()) {
        // Create a (new) CSS file, if HTML requested and
        // there isn't one already.
        string cssFile = options.cssFileName();
        if (fileExists(cssFile)) {
            cout << "File exists: " << cssFile << endl;
        } else {
            allOk = createCSSFile(cssFile);
            if (!allOk) {
                return 1;
            }
        }

        // Likewise, a 'favicon.ico' icon file too.
        string favIconFile = filePath(cssFile) + directorySeparator + "favicon.ico";
        if (fileExists(favIconFile)) {
            cout << "File exists: " << favIconFile << endl;
        } else {
            allOk = createFaviconFile(favIconFile);
            if (allOk) {
                cout << "TraceMiner2: 'favicon' file [" << favIconFile << "] created ok." << endl;
            } else {
                cout << "TraceMiner2: 'favicon' file [" << favIconFile << "] creation failed." << endl;
                return 1;
            }
        }
    }

    // This is it, here is where we hit the big time! :)
    tmTraceFile *traceFile = new tmTraceFile(&options);
    allOk = traceFile->parse();

    // All done.
    if (traceFile) {
        delete traceFile;
    }

    return allOk ? 0 : 1;
}
<commit_msg>Version upgraded to 0.08.<commit_after>/** @mainpage TraceMiner 2
 *
 *  @author Norman Dunbar
 *  @copyright MIT Licence
 *
 * @tableofcontents
 *
 *  @section Introduction
 *
 * TraceMiner 2 is a new improved version of the old TraceMiner utility. It has
 * been completely rewritten in C++ rather than the old style vanilla C. This has made
 * things surprisingly easier to do in the new versions and has got around a whole pile
 * of crud and hacks in the previous version. There's no manual configuration required
 * before compiling for example.
 *
 * @section sec-free-source-code Free Source Code
 *
 * The source code for TraceMiner2 lives in GitHub at
 * https://github.com/NormanDunbar/TraceMiner2/.
 *
 * Feel free to clone the repository and make any desired changes you wish.
 *
 * You may, if you just want to compile and use the code, download the source as a
 * zip file from https://github.com/NormanDunbar/TraceMiner2/archive/master.zip.
 *
 * @section sec-compiling Compiling
 *
 * The source should be downloaded. Then simply compile all the *.cpp files using a C++
 * compiler that knows about the Standard Template Library (aka STL). This is the only
 * "weird" thing used by TraceMiner2. No other special libraries such as Boost, for
 * example, are required.
 *
 * @subsection sub-sec-with-codeblocks With CodeBlocks
 *
 * There's a CodeBlocks project file, `TraceMiner2.cbp`, located in the main source folder.
 * You may need to change some paths etc to use it. In my own setup, I have configured the
 * free Borland/Embarcadero C++ compiler, version 10.1, to be used. Get yours at
 * https://www.embarcadero.com/free-tools/ccompiler/start-for-free. CodeBlocks itself is
 * available at https://www.codeblocks.org.
 *
 * Once compiled, look here for your executable:
 *
 * @code
 * TraceMiner2-master\TraceMiner2\bin\release
 * @endcode
 *
 * @subsection sub-sec-with-borland With Borland/Embarcadero C++ 10.1
 *
 * Unzip the download zip file, then:
 *
 * @code
 * cd TraceMiner2-master\TraceMiner2
 * mkdir bin
 * bcc32c -o bin\TraceMiner2.exe *.cpp
 * @endcode
 *
 * Once compiled, look your executable will be:
 *
 * @code
 * TraceMiner2-master\TraceMiner2\bin\TraceMiner2.exe
 * @endcode
 *
 * Get a free copy of the compiler at https://www.embarcadero.com/free-tools/ccompiler/start-for-free.
 *
 * @subsection sub-sec-with-gpp With G++
 *
 * You can use the supplied Makefile.gnu, or just compile all the *.cpp files, as follows:
 *
 * @code
 * cd TraceMiner2-master/TraceMiner2
 * mkdir bin
 * g++ -o bin/TraceMiner2 *.cpp
 * @endcode
 *
 * The executable will be wherever you pointed it to be created with the '-o' option.
 *
 * @subsection sec-makefile With a Makefile
 *
 * @code
 * cd TraceMiner2-master
 * make -f makefile.gnu
 * @endcode
 *
 * Once compiled, look here for your executable:
 *
 * @code
 * TraceMiner2-master/TraceMiner2/bin
 * @endcode
 *
 * @section sec-execution Execution
 *
 * There is one mandatory parameter required, the trace file name. This must have the extension
 * ".trc" as generated by Oracle. The report file will have the ".trc" changed to ".txt" or
 * ".html" depending on whether you have requested a plain text or HTML report format.
 *
 * The report file will be created in the same location as the trace file and defaults to HTML format. This
 * is simply because the textual format is pretty dire with wide lines in many cases.
 *
 * If you choose to run in verbose mode, and you probably shouldn't, the output file for that
 * detail will be the same as the trace file name, but with the ".trc" extension replaced by
 * ".dbg". Once again, the output file will be in the same location as the trace file.
 *
 * The optional parameters are as follows:
 *
 * @li --verbose or -v - indicates that you wish to generate lots of output for debugging purposes.
 * @li --quiet or -q - indicates that you do not wish to see "Cursor: #cccc created at line: nnnn" messages.
 * on the screen while parsing is taking place. Any ERRORs or PARSE ERRORS will still be displayed.
 * @li --help -h or -? - indicates that you want help. The program will exit after displaying the
 * usage details.
 * @li --text or -t - indicates that you wish to have the report formatted in plain text as opposed to
 * HTML text. Good luck with that option! ;-)
 * @li --depth=n or -d=n - indicates the maximum depth of recursive cursors that you wish to report on
 * which is useful when a PL/SQL calls is at depth=0, you wouold be interested in depth=1, for example.
 * @li --pagesize=nn or -p=nn - indicates how many EXEC statements you wish to display in each HTML table
 * in the report. This meakes scrolling to the headings in long report files a lot easier!
 * @li --feedback=nn or -f=nn - indicates how often you want feedback on progress reading the trace file. Zero
 * disables feedback. The default is every 100,000 lines read. Useful on larger trace files.
 *
 * @section sec-mit-licence MIT Licence
 *
 * MIT License
 *
 * Copyright (c) 2017 Norman Dunbar
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/** @file TraceMiner2.cpp
 * @brief This is where it all starts. The main() function lives here.
 */

#include "TraceMiner2.h"
#include "utilities.h"
#include "favicon.h"

// Version number.
const float version = 0.08;

// Various flags set according to the passed parameters.
tmOptions options;

int main(int argc, char *argv[])
{
    // Make sure that cout/cerr gets comma/dot separated thousands etc.
    cout.imbue(locale(cout.getloc(), new ThousandsSeparator<char>(',')));
    cerr.imbue(locale(cerr.getloc(), new ThousandsSeparator<char>(',')));

    // Parse command line args and bale if problems detected.
    bool allOk = options.parseArgs(argc, argv);
    if (!allOk) {
        return 1;
    }

    // Show help and exit requested?
    if (options.help()) {
        return 0;
    }

    if (options.html()) {
        // Create a (new) CSS file, if HTML requested and
        // there isn't one already.
        string cssFile = options.cssFileName();
        if (fileExists(cssFile)) {
            cout << "File exists: " << cssFile << endl;
        } else {
            allOk = createCSSFile(cssFile);
            if (!allOk) {
                return 1;
            }
        }

        // Likewise, a 'favicon.ico' icon file too.
        string favIconFile = filePath(cssFile) + directorySeparator + "favicon.ico";
        if (fileExists(favIconFile)) {
            cout << "File exists: " << favIconFile << endl;
        } else {
            allOk = createFaviconFile(favIconFile);
            if (allOk) {
                cout << "TraceMiner2: 'favicon' file [" << favIconFile << "] created ok." << endl;
            } else {
                cout << "TraceMiner2: 'favicon' file [" << favIconFile << "] creation failed." << endl;
                return 1;
            }
        }
    }

    // This is it, here is where we hit the big time! :)
    tmTraceFile *traceFile = new tmTraceFile(&options);
    allOk = traceFile->parse();

    // All done.
    if (traceFile) {
        delete traceFile;
    }

    return allOk ? 0 : 1;
}
<|endoftext|>


<commit_before>/*******************/
/* onleftclick.cpp */
/*******************/

#include "fctsys.h"
#include "common.h"
#include "eeschema_id.h"
#include "class_drawpanel.h"
#include "confirm.h"
#include "class_sch_screen.h"
#include "wxEeschemaStruct.h"

#include "general.h"
#include "protos.h"
#include "sch_bus_entry.h"
#include "sch_text.h"
#include "sch_marker.h"
#include "sch_junction.h"
#include "sch_line.h"
#include "sch_no_connect.h"
#include "sch_component.h"
#include "sch_sheet.h"

static wxArrayString s_CmpNameList;
static wxArrayString s_PowerNameList;

void SCH_EDIT_FRAME::OnLeftClick( wxDC* aDC, const wxPoint& aPosition )
{
    SCH_ITEM* item = GetScreen()->GetCurItem();
    wxPoint gridPosition = GetGridPosition( aPosition );

    if( ( m_ID_current_state == ID_SCH_NO_TOOL )
        || ( m_ID_current_state == 0 )
        || ( item && item->m_Flags ) )
    {
        DrawPanel->m_AutoPAN_Request = false;
        m_itemToRepeat = NULL;

        if( item && item->m_Flags )
        {
            switch( item->Type() )
            {
            case SCH_LABEL_T:
            case SCH_GLOBAL_LABEL_T:
            case SCH_HIERARCHICAL_LABEL_T:
            case SCH_TEXT_T:
            case SCH_SHEET_LABEL_T:
            case SCH_SHEET_T:
            case SCH_BUS_ENTRY_T:
            case SCH_JUNCTION_T:
            case SCH_COMPONENT_T:
            case SCH_FIELD_T:
                item->Place( this, aDC );
                GetScreen()->SetCurItem( NULL );
                GetScreen()->TestDanglingEnds();
                DrawPanel->Refresh( true );
                return;

            case SCH_SCREEN_T:
                DisplayError( this, wxT( "OnLeftClick err: unexpected type for Place" ) );
                item->m_Flags = 0;
                break;

            case SCH_LINE_T: // May already be drawing segment.
                break;

            default:
            {
                wxString msg;
                msg.Printf( wxT( "SCH_EDIT_FRAME::OnLeftClick err: m_Flags != 0, itmetype %d" ),
                            item->Type());
                DisplayError( this, msg );
                item->m_Flags = 0;
                break;
            }
            }
        }
        else
        {
            item = LocateAndShowItem( aPosition );
        }
    }

    switch( m_ID_current_state )
    {
    case 0:
    case ID_SCH_NO_TOOL:
        break;

    case ID_HIERARCHY_PUSH_POP_BUTT:
        if( ( item && item->m_Flags ) || ( g_RootSheet->CountSheets() == 0 ) )
            break;

        item = LocateAndShowItem( aPosition );

        if( item && ( item->Type() == SCH_SHEET_T ) )
        {
            m_CurrentSheet->Push( (SCH_SHEET*) item );
            DisplayCurrentSheet();
        }
        else
        {
            wxCHECK_RET( m_CurrentSheet->Last() != g_RootSheet,
                         wxT( "Cannot leave root sheet.  Bad Programmer!" ) );

            m_CurrentSheet->Pop();
            DisplayCurrentSheet();
        }

        break;

    case ID_NOCONN_BUTT:
        if( ( item == NULL ) || ( item->m_Flags == 0 ) )
        {
            m_itemToRepeat = AddNoConnect( aDC, gridPosition );
            GetScreen()->SetCurItem( m_itemToRepeat );
            DrawPanel->m_AutoPAN_Request = true;
        }
        else
        {
            item->Place( this, aDC );
            DrawPanel->m_AutoPAN_Request = false;
        }

        GetScreen()->TestDanglingEnds();
        DrawPanel->Refresh( true );
        break;

    case ID_JUNCTION_BUTT:
        if( ( item == NULL ) || ( item->m_Flags == 0 ) )
        {
            m_itemToRepeat = AddJunction( aDC, gridPosition, true );
            GetScreen()->SetCurItem( m_itemToRepeat );
            DrawPanel->m_AutoPAN_Request = true;
        }
        else
        {
            item->Place( this, aDC );
            DrawPanel->m_AutoPAN_Request = false;
        }

        GetScreen()->TestDanglingEnds();
        DrawPanel->Refresh( true );
        break;

    case ID_WIRETOBUS_ENTRY_BUTT:
    case ID_BUSTOBUS_ENTRY_BUTT:
        if( ( item == NULL ) || ( item->m_Flags == 0 ) )
        {
            item = CreateBusEntry( aDC, ( m_ID_current_state == ID_WIRETOBUS_ENTRY_BUTT ) ?
                                   WIRE_TO_BUS : BUS_TO_BUS );
            GetScreen()->SetCurItem( item );
            DrawPanel->m_AutoPAN_Request = true;
        }
        else
        {
            item->Place( this, aDC );
            GetScreen()->SetCurItem( NULL );
            GetScreen()->TestDanglingEnds();
            DrawPanel->Refresh( true );
            DrawPanel->m_AutoPAN_Request = false;
        }
        break;

    case ID_SCHEMATIC_DELETE_ITEM_BUTT:
        LocateAndDeleteItem( this, aDC );
        OnModify();
        GetScreen()->SetCurItem( NULL );
        GetScreen()->TestDanglingEnds();
        DrawPanel->Refresh( true );
        break;

    case ID_WIRE_BUTT:
        BeginSegment( aDC, LAYER_WIRE );
        DrawPanel->m_AutoPAN_Request = true;
        break;

    case ID_BUS_BUTT:
        BeginSegment( aDC, LAYER_BUS );
        DrawPanel->m_AutoPAN_Request = true;
        break;

    case ID_LINE_COMMENT_BUTT:
        BeginSegment( aDC, LAYER_NOTES );
        DrawPanel->m_AutoPAN_Request = true;
        break;

    case ID_TEXT_COMMENT_BUTT:
        if( ( item == NULL ) || ( item->m_Flags == 0 ) )
        {
            GetScreen()->SetCurItem( CreateNewText( aDC, LAYER_NOTES ) );
            DrawPanel->m_AutoPAN_Request = true;
        }
        else
        {
            item->Place( this, aDC );
            DrawPanel->m_AutoPAN_Request = false;
        }
        break;

    case ID_LABEL_BUTT:
        if( ( item == NULL ) || ( item->m_Flags == 0 ) )
        {
            GetScreen()->SetCurItem( CreateNewText( aDC, LAYER_LOCLABEL ) );
            DrawPanel->m_AutoPAN_Request = true;
        }
        else
        {
            item->Place( this, aDC );
            DrawPanel->m_AutoPAN_Request = false;
            GetScreen()->TestDanglingEnds();
            DrawPanel->Refresh( true );
        }
        break;

    case ID_GLABEL_BUTT:
    case ID_HIERLABEL_BUTT:
        if( (item == NULL) || (item->m_Flags == 0) )
        {
            if(m_ID_current_state == ID_GLABEL_BUTT)
                GetScreen()->SetCurItem( CreateNewText( aDC, LAYER_GLOBLABEL ) );

            if(m_ID_current_state == ID_HIERLABEL_BUTT)
                GetScreen()->SetCurItem( CreateNewText( aDC, LAYER_HIERLABEL ) );

            DrawPanel->m_AutoPAN_Request = true;
        }
        else
        {
            item->Place( this, aDC );
            DrawPanel->m_AutoPAN_Request = false;
            GetScreen()->TestDanglingEnds();
            DrawPanel->Refresh( true );
        }
        break;

    case ID_SHEET_SYMBOL_BUTT:
        if( ( item == NULL ) || ( item->m_Flags == 0 ) )
        {
            GetScreen()->SetCurItem( CreateSheet( aDC ) );
            DrawPanel->m_AutoPAN_Request = true;
        }
        else
        {
            item->Place( this, aDC );
            DrawPanel->m_AutoPAN_Request = false;
            GetScreen()->TestDanglingEnds();
            DrawPanel->Refresh( true );
        }
        break;

    case ID_IMPORT_HLABEL_BUTT:
    case ID_SHEET_LABEL_BUTT:
        if( ( item == NULL ) || ( item->m_Flags == 0 ) )
            item = LocateAndShowItem( aPosition );

        if( item == NULL )
            break;

        if( (item->Type() == SCH_SHEET_T) && (item->m_Flags == 0) )
        {
            if( m_ID_current_state == ID_IMPORT_HLABEL_BUTT )
                GetScreen()->SetCurItem( Import_PinSheet( (SCH_SHEET*) item, aDC ) );
            else
                GetScreen()->SetCurItem( Create_PinSheet( (SCH_SHEET*) item, aDC ) );
        }
        else if( (item->Type() == SCH_SHEET_LABEL_T) && (item->m_Flags != 0) )
        {
            item->Place( this, aDC );
            GetScreen()->TestDanglingEnds();
            DrawPanel->Refresh( true );
        }
        break;

    case ID_SCH_PLACE_COMPONENT:
        if( (item == NULL) || (item->m_Flags == 0) )
        {
            GetScreen()->SetCurItem( Load_Component( aDC, wxEmptyString, s_CmpNameList, true ) );
            DrawPanel->m_AutoPAN_Request = true;
        }
        else
        {
            item->Place( this, aDC );
            DrawPanel->m_AutoPAN_Request = false;
            GetScreen()->TestDanglingEnds();
            DrawPanel->Refresh( true );
        }
        break;

    case ID_PLACE_POWER_BUTT:
        if( ( item == NULL ) || ( item->m_Flags == 0 ) )
        {
            GetScreen()->SetCurItem( Load_Component( aDC, wxT( "power" ),
                                                     s_PowerNameList, false ) );
            DrawPanel->m_AutoPAN_Request = true;
        }
        else
        {
            item->Place( this, aDC );
            DrawPanel->m_AutoPAN_Request = false;
            GetScreen()->TestDanglingEnds();
            DrawPanel->Refresh( true );
        }
        break;

    default:
    {
        SetToolID( 0, wxCURSOR_ARROW, wxEmptyString );
        wxString msg( wxT( "SCH_EDIT_FRAME::OnLeftClick error state " ) );

        msg << m_ID_current_state;
        DisplayError( this, msg );
        break;
    }
    }
}

/**
 * Function OnLeftDClick
 * called on a double click event from the drawpanel mouse handler
 *  if an editable item is found (text, component)
 *      Call the suitable dialog editor.
 *  Id a create command is in progress:
 *      validate and finish the command
 */
void SCH_EDIT_FRAME::OnLeftDClick( wxDC* aDC, const wxPoint& aPosition )

{
    EDA_ITEM* item = GetScreen()->GetCurItem();
    wxPoint   pos = aPosition;

    switch( m_ID_current_state )
    {
    case ID_SCH_NO_TOOL:
    case 0:
        if( ( item == NULL ) || ( item->m_Flags == 0 ) )
        {
            item = LocateAndShowItem( aPosition );
        }

        if( ( item == NULL ) || ( item->m_Flags != 0 ) )
            break;

        switch( item->Type() )
        {
        case SCH_SHEET_T:
            m_CurrentSheet->Push( (SCH_SHEET*) item );
            DisplayCurrentSheet();
            break;

        case SCH_COMPONENT_T:
            InstallCmpeditFrame( this, (SCH_COMPONENT*) item );
            DrawPanel->MoveCursorToCrossHair();
            break;

        case SCH_TEXT_T:
        case SCH_LABEL_T:
        case SCH_GLOBAL_LABEL_T:
        case SCH_HIERARCHICAL_LABEL_T:
            EditSchematicText( (SCH_TEXT*) item );
            break;

        case SCH_FIELD_T:
            EditCmpFieldText( (SCH_FIELD*) item, aDC );
            DrawPanel->MoveCursorToCrossHair();
            break;

        case SCH_MARKER_T:
            ( (SCH_MARKER*) item )->DisplayMarkerInfo( this );
            break;

        default:
            break;
        }

        break;

    case ID_BUS_BUTT:
    case ID_WIRE_BUTT:
    case ID_LINE_COMMENT_BUTT:
        if( item && item->IsNew() )
            EndSegment( aDC );

        break;
    }
}
<commit_msg>Fix developer warning message to only show on debug build.  Fixes lp:624926<commit_after>/*******************/
/* onleftclick.cpp */
/*******************/

#include "fctsys.h"
#include "common.h"
#include "eeschema_id.h"
#include "class_drawpanel.h"
#include "confirm.h"
#include "class_sch_screen.h"
#include "wxEeschemaStruct.h"

#include "general.h"
#include "protos.h"
#include "sch_bus_entry.h"
#include "sch_text.h"
#include "sch_marker.h"
#include "sch_junction.h"
#include "sch_line.h"
#include "sch_no_connect.h"
#include "sch_component.h"
#include "sch_sheet.h"

static wxArrayString s_CmpNameList;
static wxArrayString s_PowerNameList;

void SCH_EDIT_FRAME::OnLeftClick( wxDC* aDC, const wxPoint& aPosition )
{
    SCH_ITEM* item = GetScreen()->GetCurItem();
    wxPoint gridPosition = GetGridPosition( aPosition );

    if( ( m_ID_current_state == ID_SCH_NO_TOOL )
        || ( m_ID_current_state == 0 )
        || ( item && item->m_Flags ) )
    {
        DrawPanel->m_AutoPAN_Request = false;
        m_itemToRepeat = NULL;

        if( item && item->m_Flags )
        {
            switch( item->Type() )
            {
            case SCH_LABEL_T:
            case SCH_GLOBAL_LABEL_T:
            case SCH_HIERARCHICAL_LABEL_T:
            case SCH_TEXT_T:
            case SCH_SHEET_LABEL_T:
            case SCH_SHEET_T:
            case SCH_BUS_ENTRY_T:
            case SCH_JUNCTION_T:
            case SCH_COMPONENT_T:
            case SCH_FIELD_T:
                item->Place( this, aDC );
                GetScreen()->SetCurItem( NULL );
                GetScreen()->TestDanglingEnds();
                DrawPanel->Refresh( true );
                return;

            case SCH_LINE_T:    // May already be drawing segment.
                break;

            default:
                wxFAIL_MSG( wxT( "SCH_EDIT_FRAME::OnLeftClick error.  Item type <" ) +
                            item->GetClass() + wxT( "> is already being edited." ) );
                item->SetFlags( 0 );
            }
        }
        else
        {
            item = LocateAndShowItem( aPosition );
        }
    }

    switch( m_ID_current_state )
    {
    case 0:
    case ID_SCH_NO_TOOL:
        break;

    case ID_HIERARCHY_PUSH_POP_BUTT:
        if( ( item && item->m_Flags ) || ( g_RootSheet->CountSheets() == 0 ) )
            break;

        item = LocateAndShowItem( aPosition );

        if( item && ( item->Type() == SCH_SHEET_T ) )
        {
            m_CurrentSheet->Push( (SCH_SHEET*) item );
            DisplayCurrentSheet();
        }
        else
        {
            wxCHECK_RET( m_CurrentSheet->Last() != g_RootSheet,
                         wxT( "Cannot leave root sheet.  Bad Programmer!" ) );

            m_CurrentSheet->Pop();
            DisplayCurrentSheet();
        }

        break;

    case ID_NOCONN_BUTT:
        if( ( item == NULL ) || ( item->m_Flags == 0 ) )
        {
            m_itemToRepeat = AddNoConnect( aDC, gridPosition );
            GetScreen()->SetCurItem( m_itemToRepeat );
            DrawPanel->m_AutoPAN_Request = true;
        }
        else
        {
            item->Place( this, aDC );
            DrawPanel->m_AutoPAN_Request = false;
        }

        GetScreen()->TestDanglingEnds();
        DrawPanel->Refresh( true );
        break;

    case ID_JUNCTION_BUTT:
        if( ( item == NULL ) || ( item->m_Flags == 0 ) )
        {
            m_itemToRepeat = AddJunction( aDC, gridPosition, true );
            GetScreen()->SetCurItem( m_itemToRepeat );
            DrawPanel->m_AutoPAN_Request = true;
        }
        else
        {
            item->Place( this, aDC );
            DrawPanel->m_AutoPAN_Request = false;
        }

        GetScreen()->TestDanglingEnds();
        DrawPanel->Refresh( true );
        break;

    case ID_WIRETOBUS_ENTRY_BUTT:
    case ID_BUSTOBUS_ENTRY_BUTT:
        if( ( item == NULL ) || ( item->m_Flags == 0 ) )
        {
            item = CreateBusEntry( aDC, ( m_ID_current_state == ID_WIRETOBUS_ENTRY_BUTT ) ?
                                   WIRE_TO_BUS : BUS_TO_BUS );
            GetScreen()->SetCurItem( item );
            DrawPanel->m_AutoPAN_Request = true;
        }
        else
        {
            item->Place( this, aDC );
            GetScreen()->SetCurItem( NULL );
            GetScreen()->TestDanglingEnds();
            DrawPanel->Refresh( true );
            DrawPanel->m_AutoPAN_Request = false;
        }
        break;

    case ID_SCHEMATIC_DELETE_ITEM_BUTT:
        LocateAndDeleteItem( this, aDC );
        OnModify();
        GetScreen()->SetCurItem( NULL );
        GetScreen()->TestDanglingEnds();
        DrawPanel->Refresh( true );
        break;

    case ID_WIRE_BUTT:
        BeginSegment( aDC, LAYER_WIRE );
        DrawPanel->m_AutoPAN_Request = true;
        break;

    case ID_BUS_BUTT:
        BeginSegment( aDC, LAYER_BUS );
        DrawPanel->m_AutoPAN_Request = true;
        break;

    case ID_LINE_COMMENT_BUTT:
        BeginSegment( aDC, LAYER_NOTES );
        DrawPanel->m_AutoPAN_Request = true;
        break;

    case ID_TEXT_COMMENT_BUTT:
        if( ( item == NULL ) || ( item->m_Flags == 0 ) )
        {
            GetScreen()->SetCurItem( CreateNewText( aDC, LAYER_NOTES ) );
            DrawPanel->m_AutoPAN_Request = true;
        }
        else
        {
            item->Place( this, aDC );
            DrawPanel->m_AutoPAN_Request = false;
        }
        break;

    case ID_LABEL_BUTT:
        if( ( item == NULL ) || ( item->m_Flags == 0 ) )
        {
            GetScreen()->SetCurItem( CreateNewText( aDC, LAYER_LOCLABEL ) );
            DrawPanel->m_AutoPAN_Request = true;
        }
        else
        {
            item->Place( this, aDC );
            DrawPanel->m_AutoPAN_Request = false;
            GetScreen()->TestDanglingEnds();
            DrawPanel->Refresh( true );
        }
        break;

    case ID_GLABEL_BUTT:
    case ID_HIERLABEL_BUTT:
        if( (item == NULL) || (item->m_Flags == 0) )
        {
            if(m_ID_current_state == ID_GLABEL_BUTT)
                GetScreen()->SetCurItem( CreateNewText( aDC, LAYER_GLOBLABEL ) );

            if(m_ID_current_state == ID_HIERLABEL_BUTT)
                GetScreen()->SetCurItem( CreateNewText( aDC, LAYER_HIERLABEL ) );

            DrawPanel->m_AutoPAN_Request = true;
        }
        else
        {
            item->Place( this, aDC );
            DrawPanel->m_AutoPAN_Request = false;
            GetScreen()->TestDanglingEnds();
            DrawPanel->Refresh( true );
        }
        break;

    case ID_SHEET_SYMBOL_BUTT:
        if( ( item == NULL ) || ( item->m_Flags == 0 ) )
        {
            GetScreen()->SetCurItem( CreateSheet( aDC ) );
            DrawPanel->m_AutoPAN_Request = true;
        }
        else
        {
            item->Place( this, aDC );
            DrawPanel->m_AutoPAN_Request = false;
            GetScreen()->TestDanglingEnds();
            DrawPanel->Refresh( true );
        }
        break;

    case ID_IMPORT_HLABEL_BUTT:
    case ID_SHEET_LABEL_BUTT:
        if( ( item == NULL ) || ( item->m_Flags == 0 ) )
            item = LocateAndShowItem( aPosition );

        if( item == NULL )
            break;

        if( (item->Type() == SCH_SHEET_T) && (item->m_Flags == 0) )
        {
            if( m_ID_current_state == ID_IMPORT_HLABEL_BUTT )
                GetScreen()->SetCurItem( Import_PinSheet( (SCH_SHEET*) item, aDC ) );
            else
                GetScreen()->SetCurItem( Create_PinSheet( (SCH_SHEET*) item, aDC ) );
        }
        else if( (item->Type() == SCH_SHEET_LABEL_T) && (item->m_Flags != 0) )
        {
            item->Place( this, aDC );
            GetScreen()->TestDanglingEnds();
            DrawPanel->Refresh( true );
        }
        break;

    case ID_SCH_PLACE_COMPONENT:
        if( (item == NULL) || (item->m_Flags == 0) )
        {
            GetScreen()->SetCurItem( Load_Component( aDC, wxEmptyString, s_CmpNameList, true ) );
            DrawPanel->m_AutoPAN_Request = true;
        }
        else
        {
            item->Place( this, aDC );
            DrawPanel->m_AutoPAN_Request = false;
            GetScreen()->TestDanglingEnds();
            DrawPanel->Refresh( true );
        }
        break;

    case ID_PLACE_POWER_BUTT:
        if( ( item == NULL ) || ( item->m_Flags == 0 ) )
        {
            GetScreen()->SetCurItem( Load_Component( aDC, wxT( "power" ),
                                                     s_PowerNameList, false ) );
            DrawPanel->m_AutoPAN_Request = true;
        }
        else
        {
            item->Place( this, aDC );
            DrawPanel->m_AutoPAN_Request = false;
            GetScreen()->TestDanglingEnds();
            DrawPanel->Refresh( true );
        }
        break;

    default:
        SetToolID( ID_SCH_NO_TOOL, DrawPanel->GetDefaultCursor(), wxEmptyString );
        wxFAIL_MSG( wxT( "SCH_EDIT_FRAME::OnLeftClick invalid tool ID <" ) +
                    wxString::Format( wxT( "%d> selected." ), m_ID_current_state ) );
    }
}

/**
 * Function OnLeftDClick
 * called on a double click event from the drawpanel mouse handler
 *  if an editable item is found (text, component)
 *      Call the suitable dialog editor.
 *  Id a create command is in progress:
 *      validate and finish the command
 */
void SCH_EDIT_FRAME::OnLeftDClick( wxDC* aDC, const wxPoint& aPosition )

{
    EDA_ITEM* item = GetScreen()->GetCurItem();
    wxPoint   pos = aPosition;

    switch( m_ID_current_state )
    {
    case ID_SCH_NO_TOOL:
    case 0:
        if( ( item == NULL ) || ( item->m_Flags == 0 ) )
        {
            item = LocateAndShowItem( aPosition );
        }

        if( ( item == NULL ) || ( item->m_Flags != 0 ) )
            break;

        switch( item->Type() )
        {
        case SCH_SHEET_T:
            m_CurrentSheet->Push( (SCH_SHEET*) item );
            DisplayCurrentSheet();
            break;

        case SCH_COMPONENT_T:
            InstallCmpeditFrame( this, (SCH_COMPONENT*) item );
            DrawPanel->MoveCursorToCrossHair();
            break;

        case SCH_TEXT_T:
        case SCH_LABEL_T:
        case SCH_GLOBAL_LABEL_T:
        case SCH_HIERARCHICAL_LABEL_T:
            EditSchematicText( (SCH_TEXT*) item );
            break;

        case SCH_FIELD_T:
            EditCmpFieldText( (SCH_FIELD*) item, aDC );
            DrawPanel->MoveCursorToCrossHair();
            break;

        case SCH_MARKER_T:
            ( (SCH_MARKER*) item )->DisplayMarkerInfo( this );
            break;

        default:
            break;
        }

        break;

    case ID_BUS_BUTT:
    case ID_WIRE_BUTT:
    case ID_LINE_COMMENT_BUTT:
        if( item && item->IsNew() )
            EndSegment( aDC );

        break;
    }
}
<|endoftext|>


<commit_before>#include "ComponentCamera.h"
#include "Application.h"

ComponentCamera::ComponentCamera(Object* obj_parent)
{
	parent = obj_parent;
	comp_type = ComponentType::camera;
	cam_frustum.SetViewPlaneDistances(1, 15);

	//Set frustum looking to GameObject Z axis
	ComponentTransform* parent_transform = parent->GetTransform();

	cam_frustum.SetPos(parent_transform->translation);
	cam_frustum.SetFront(parent_transform->GetMatrix().Col3(2));
	cam_frustum.SetUp(parent_transform->GetMatrix().Col3(1));

	cam_frustum.SetVerticalFovAndAspectRatio(90 * DEGTORAD, App->window->GetAspectRatio());
	cam_frustum.SetHorizontalFovAndAspectRatio(2 * math::Atan(math::Tan(cam_frustum.VerticalFov()/ 2) * App->window->GetAspectRatio()),App->window->GetAspectRatio());

}

ComponentCamera::~ComponentCamera()
{
}

void ComponentCamera::UpdateComponent()
{
	ComponentTransform* parent_transform = parent->GetTransform();
	cam_frustum.SetPos(parent_transform->translation);

	float color[4] = { 0.7f, 0.7f, 0.7f, 1 };
	cam_frustum.Draw(3.0f,color );

}

<commit_msg>frustum can rotate<commit_after>#include "ComponentCamera.h"
#include "Application.h"

ComponentCamera::ComponentCamera(Object* obj_parent)
{
	parent = obj_parent;
	comp_type = ComponentType::camera;
	cam_frustum.SetViewPlaneDistances(1, 15);

	//Set frustum looking to GameObject Z axis
	ComponentTransform* parent_transform = parent->GetTransform();

	cam_frustum.SetPos(parent_transform->translation);
	cam_frustum.SetFront(parent_transform->GetMatrix().Col3(2));
	cam_frustum.SetUp(parent_transform->GetMatrix().Col3(1));

	cam_frustum.SetVerticalFovAndAspectRatio(90 * DEGTORAD, App->window->GetAspectRatio());
	cam_frustum.SetHorizontalFovAndAspectRatio(2 * math::Atan(math::Tan(cam_frustum.VerticalFov()/ 2) * App->window->GetAspectRatio()),App->window->GetAspectRatio());

}

ComponentCamera::~ComponentCamera()
{
}

void ComponentCamera::UpdateComponent()
{
	ComponentTransform* parent_transform = parent->GetTransform();
	cam_frustum.SetPos(parent_transform->translation);

	cam_frustum.SetFront(parent_transform->GetMatrix().Col3(2));
	//cam_frustum.SetUp(parent_transform->GetMatrix().Col3(1));

	float color[4] = { 0.7f, 0.7f, 0.7f, 1 };
	cam_frustum.Draw(3.0f,color );

}

<|endoftext|>


<commit_before>#include "transmissionquickfilter.h"

TransmissionQuickFilter::TransmissionQuickFilter(int AnalysisId) : QuickFilterBlockInterface()
{
    // Dominant - ref/alt
    mFilters[0] = "[\"==\", [\"field\", \"b33e172643f14920cee93d25daaa3c7b\"], [\"value\", \"2\"]]";
    mActiveFilters[0] = false;
    // Recessif - alt/alt
    mFilters[1] = "[\"==\", [\"field\", \"b33e172643f14920cee93d25daaa3c7b\"], [\"value\", \"1\"]]";
    mActiveFilters[1] = false;
    // Composite - alt1/alt2
    mFilters[2] = "[\"==\", [\"field\", \"b33e172643f14920cee93d25daaa3c7b\"], [\"value\", \"3\"]]";
    mActiveFilters[2] = false;
}

bool TransmissionQuickFilter::isVisible()
{
    // This filter is always availble in the UI
    return true;
}

QString TransmissionQuickFilter::getFilter()
{
    QStringList filter;
    for (int idx=0; idx < mActiveFilters.count(); idx++)
    {
        if (mActiveFilters[idx])
        {
            filter << mFilters[idx];
        }
    }

    if (filter.count() > 1)
        return QString("[\"OR\", [%1]]").arg(filter.join(","));
    else if (filter.count() == 1)
        return filter[0];
    return "";
}

void TransmissionQuickFilter::setFilter(int id, QVariant value)
{
    mActiveFilters[id] = value.toBool();
}

void TransmissionQuickFilter::clear()
{
    mActiveFilters[0] = false;
    mActiveFilters[1] = false;
    mActiveFilters[2] = false;
}
<commit_msg>fix htz composite filter (solo sample)<commit_after>#include "transmissionquickfilter.h"

TransmissionQuickFilter::TransmissionQuickFilter(int AnalysisId) : QuickFilterBlockInterface()
{
    // Dominant - ref/alt
    mFilters[0] = "[\"==\", [\"field\", \"b33e172643f14920cee93d25daaa3c7b\"], [\"value\", \"2\"]]";
    mActiveFilters[0] = false;
    // Recessif - alt/alt
    mFilters[1] = "[\"==\", [\"field\", \"b33e172643f14920cee93d25daaa3c7b\"], [\"value\", \"1\"]]";
    mActiveFilters[1] = false;
    // Composite - alt1/alt2
    mFilters[2] = "[\"==\", [\"field\", \"212a9e5be0a47eea6ed028af9992e1bb\"], [\"value\", true]]";
    mActiveFilters[2] = false;
}

bool TransmissionQuickFilter::isVisible()
{
    // This filter is always availble in the UI
    return true;
}

QString TransmissionQuickFilter::getFilter()
{
    QStringList filter;
    for (int idx=0; idx < mActiveFilters.count(); idx++)
    {
        if (mActiveFilters[idx])
        {
            filter << mFilters[idx];
        }
    }

    if (filter.count() > 1)
        return QString("[\"OR\", [%1]]").arg(filter.join(","));
    else if (filter.count() == 1)
        return filter[0];
    return "";
}

void TransmissionQuickFilter::setFilter(int id, QVariant value)
{
    mActiveFilters[id] = value.toBool();
}

void TransmissionQuickFilter::clear()
{
    mActiveFilters[0] = false;
    mActiveFilters[1] = false;
    mActiveFilters[2] = false;
}
<|endoftext|>


<commit_before>#include "core/meta/MetaPopulationFactory.hpp"
#include "core/PopulationNode.hpp"
#include "core/Apportionment.hpp"
#include "core/ObjectiveFunction.hpp"
#include "core/meta/MetaPopulationObjective.hpp"
#include "core/meta/MetaPopulationApportionment.hpp"
#include "core/meta/MetaPopulationToString.hpp"
#include "loci/PopulationLocus.hpp"
#include "exception/InvalidBlanketException.hpp"

#include <set>

std::vector<PopulationNode*> MetaPopulationFactory::getAllHierarchicalNodes(
	std::vector<PopulationNode*> nodes
) {
	std::set<Locus*> constructiveLoci;
	std::vector<PopulationNode*> unmatchedNodes;
	for (unsigned int i = 0; i < nodes.size(); i++) {
		constructiveLoci = nodes[i]->getConstructiveLoci();
		for (auto k : constructiveLoci)
			unmatchedNodes.push_back(
				((PopulationLocus*)k)->getNode()
			);
	}

	return unmatchedNodes;
}

bool MetaPopulationFactory::isCompleteBlanket(
	std::vector<PopulationNode*> nodes
) {
	std::vector<PopulationNode*> unmatchedNodes =
		MetaPopulationFactory::getAllHierarchicalNodes(nodes);

	for (unsigned int i = 0; i < unmatchedNodes.size(); i++)
		for (unsigned int k = 0; k < nodes.size(); k++)
			if (unmatchedNodes[i] == nodes[k])
				unmatchedNodes.erase(
					unmatchedNodes.begin() + i--
				);

	return unmatchedNodes.empty();
}

bool MetaPopulationFactory::isSingleBlanket(
	std::vector<PopulationNode*> nodes
) {
	std::vector<PopulationNode*> unmatchedNodes =
		MetaPopulationFactory::getAllHierarchicalNodes(nodes);
	unsigned int rootNodes = 0;

	for (unsigned int i = 0; i < nodes.size(); i++) {
		bool matched = false;
		for (unsigned int k = 0; k < unmatchedNodes.size(); k++)
			if (nodes[i] == unmatchedNodes[k]) {
				matched = true;
				break;
			}
		if (matched) rootNodes++;
	}

	return rootNodes == 1;
}

bool MetaPopulationFactory::isValidBlanket(
	PopulationNode * topNode,
	std::vector<PopulationNode*> secondaryNodes
) {
	std::vector<PopulationNode*> nodes = secondaryNodes;
	nodes.push_back(topNode);

	if (!MetaPopulationFactory::isCompleteBlanket(nodes)) return false;
	if (!MetaPopulationFactory::isSingleBlanket(nodes)) return false;

	return true;
}

PopulationNode * MetaPopulationFactory::createMeta(
	PopulationNode * metaNode,
	std::vector<ObjectiveFunction *> flattenedObjectives,
	ToStringFunction * flattenedToString,
	PopulationNode * topNode,
	std::tuple<
		ApportionmentFunction *,
		AggregationFunction *
	> topNodeApportionment,
	std::vector<std::tuple<
		PopulationNode *,
		ApportionmentFunction *,
		AggregationFunction *
	>> secondaryNodes
) {
	std::vector<PopulationNode*> secondaryPopNodes;
	for (unsigned int i = 0; i < secondaryNodes.size(); i++)
		secondaryPopNodes.push_back(std::get<0>(secondaryNodes[i]));
	if (!MetaPopulationFactory::isValidBlanket(topNode, secondaryPopNodes))
		throw InvalidBlanketException();

	std::vector<Locus*> newLoci;
	newLoci.push_back(new PopulationLocus(topNode));
	for (unsigned int i = 0; i < secondaryNodes.size(); i++)
		newLoci.push_back(new PopulationLocus(
			std::get<0>(secondaryNodes[i])
		));

	metaNode->setLoci(newLoci);

	// The normal varieties won't work on a meta-population anyways
	metaNode->setObjectives({});
	metaNode->setToString(new MetaPopulationToString(flattenedToString));

	for (unsigned int i = 0; i < flattenedObjectives.size(); i++)
		metaNode->addObjective((ObjectiveFunction*)
			new MetaPopulationObjective(flattenedObjectives[i])
		);

	topNode->addObjective(new MetaPopulationApportionment(
		metaNode,
		std::get<0>(topNodeApportionment),
		std::get<1>(topNodeApportionment)
	));

	for (unsigned int i = 0; i < secondaryNodes.size(); i++)
		std::get<0>(secondaryNodes[i])->addObjective(
			(ObjectiveFunction*)new MetaPopulationApportionment(
				metaNode,
				std::get<1>(secondaryNodes[i]),
				std::get<2>(secondaryNodes[i])
			)
		);

	return metaNode;
}
<commit_msg>[MetaPopulationFactory]: Fixed logic error in root counter<commit_after>#include "core/meta/MetaPopulationFactory.hpp"
#include "core/PopulationNode.hpp"
#include "core/Apportionment.hpp"
#include "core/ObjectiveFunction.hpp"
#include "core/meta/MetaPopulationObjective.hpp"
#include "core/meta/MetaPopulationApportionment.hpp"
#include "core/meta/MetaPopulationToString.hpp"
#include "loci/PopulationLocus.hpp"
#include "exception/InvalidBlanketException.hpp"

#include <set>

std::vector<PopulationNode*> MetaPopulationFactory::getAllHierarchicalNodes(
	std::vector<PopulationNode*> nodes
) {
	std::set<Locus*> constructiveLoci;
	std::vector<PopulationNode*> unmatchedNodes;
	for (unsigned int i = 0; i < nodes.size(); i++) {
		constructiveLoci = nodes[i]->getConstructiveLoci();
		for (auto k : constructiveLoci)
			unmatchedNodes.push_back(
				((PopulationLocus*)k)->getNode()
			);
	}

	return unmatchedNodes;
}

bool MetaPopulationFactory::isCompleteBlanket(
	std::vector<PopulationNode*> nodes
) {
	std::vector<PopulationNode*> unmatchedNodes =
		MetaPopulationFactory::getAllHierarchicalNodes(nodes);

	for (unsigned int i = 0; i < unmatchedNodes.size(); i++)
		for (unsigned int k = 0; k < nodes.size(); k++)
			if (unmatchedNodes[i] == nodes[k])
				unmatchedNodes.erase(
					unmatchedNodes.begin() + i--
				);

	return unmatchedNodes.empty();
}

bool MetaPopulationFactory::isSingleBlanket(
	std::vector<PopulationNode*> nodes
) {
	std::vector<PopulationNode*> unmatchedNodes =
		MetaPopulationFactory::getAllHierarchicalNodes(nodes);
	unsigned int rootNodes = 0;

	for (unsigned int i = 0; i < nodes.size(); i++) {
		bool matched = false;
		for (unsigned int k = 0; k < unmatchedNodes.size(); k++)
			if (nodes[i] == unmatchedNodes[k]) {
				matched = true;
				break;
			}
		if (!matched) rootNodes++;
	}

	return rootNodes == 1;
}

bool MetaPopulationFactory::isValidBlanket(
	PopulationNode * topNode,
	std::vector<PopulationNode*> secondaryNodes
) {
	std::vector<PopulationNode*> nodes = secondaryNodes;
	nodes.push_back(topNode);

	if (!MetaPopulationFactory::isCompleteBlanket(nodes)) return false;
	if (!MetaPopulationFactory::isSingleBlanket(nodes)) return false;

	return true;
}

PopulationNode * MetaPopulationFactory::createMeta(
	PopulationNode * metaNode,
	std::vector<ObjectiveFunction *> flattenedObjectives,
	ToStringFunction * flattenedToString,
	PopulationNode * topNode,
	std::tuple<
		ApportionmentFunction *,
		AggregationFunction *
	> topNodeApportionment,
	std::vector<std::tuple<
		PopulationNode *,
		ApportionmentFunction *,
		AggregationFunction *
	>> secondaryNodes
) {
	std::vector<PopulationNode*> secondaryPopNodes;
	for (unsigned int i = 0; i < secondaryNodes.size(); i++)
		secondaryPopNodes.push_back(std::get<0>(secondaryNodes[i]));
	if (!MetaPopulationFactory::isValidBlanket(topNode, secondaryPopNodes))
		throw InvalidBlanketException();

	std::vector<Locus*> newLoci;
	newLoci.push_back(new PopulationLocus(topNode));
	for (unsigned int i = 0; i < secondaryNodes.size(); i++)
		newLoci.push_back(new PopulationLocus(
			std::get<0>(secondaryNodes[i])
		));

	metaNode->setLoci(newLoci);

	// The normal varieties won't work on a meta-population anyways
	metaNode->setObjectives({});
	metaNode->setToString(new MetaPopulationToString(flattenedToString));

	for (unsigned int i = 0; i < flattenedObjectives.size(); i++)
		metaNode->addObjective((ObjectiveFunction*)
			new MetaPopulationObjective(flattenedObjectives[i])
		);

	topNode->addObjective(new MetaPopulationApportionment(
		metaNode,
		std::get<0>(topNodeApportionment),
		std::get<1>(topNodeApportionment)
	));

	for (unsigned int i = 0; i < secondaryNodes.size(); i++)
		std::get<0>(secondaryNodes[i])->addObjective(
			(ObjectiveFunction*)new MetaPopulationApportionment(
				metaNode,
				std::get<1>(secondaryNodes[i]),
				std::get<2>(secondaryNodes[i])
			)
		);

	return metaNode;
}
<|endoftext|>


<commit_before>/*
    Copyright (C) 1998-2001 by Jorrit Tyberghein

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>

#define CS_SYSDEF_PROVIDE_ALLOCA
#include "cssysdef.h"
#include "csutil/scf.h"
#include "csutil/plugldr.h"
#include "csutil/csvector.h"
#include "csutil/util.h"
#include "csutil/snprintf.h"
#include "ivaria/reporter.h"
#include "iutil/objreg.h"
#include "iutil/cmdline.h"
#include "iutil/cfgmgr.h"
#include "iutil/plugin.h"
#include "iutil/vfs.h"

/**
 * Since every plugin can depend on another one, the plugin loader should be
 * able to sort them by their preferences. Thus, if some plugin A wants some
 * other plugins B and C to be loaded before him, the plugin loader should
 * sort the list of loaded plugins such that plugin A comes after B and C.
 *

 * Of course it is possible that some plugin A depends on B and B depends on A,
 * or even worse A on B, B on C and C on A. The sort algorithm should detect
 * this case and type an error message if it is detected.
 *

 * The algorithm works as follows. First, a dependency matrix is built. Here
 * is a example of a simple dependency matrix:
 *

 *                iEngine      iVFS     iGraphics3D iGraphics2D
 *             +-----------+-----------+-----------+-----------+
 * iEngine     |           |     X     |     X     |     X     |
 *             +-----------+-----------+-----------+-----------+
 * iVFS        |           |           |           |           |
 *             +-----------+-----------+-----------+-----------+
 * iGraphics3D |           |     X     |           |     X     |
 *             +-----------+-----------+-----------+-----------+
 * iGraphics2D |           |     X     |           |           |
 *             +-----------+-----------+-----------+-----------+
 *

 * Thus, we see that the iEngine plugin depends on iVFS, iGraphics3D and
 * iGraphics2D plugins (this is an abstract example, in reality the
 * things are simpler), iVFS does not depend on anything, iGraphics3D
 * wants the iVFS and the iGraphics2D plugins, and finally iGraphics2D
 * wants just the iVFS.
 *

 * The sort algorithm works as follows: we take each plugin, one by one
 * starting from first (iEngine) and examine each of them. If some plugin
 * depends on others, we recursively launch this algorithm on those plugins.
 * If we don't have any more dependencies, we put the plugin into the
 * load list and return to the previous recursion level. To detect loops
 * we need to maintain an "recurse list", thus if we found that iEngine
 * depends on iGraphics3D, iGraphics3D depends on iGraphics2D and we're
 * examining iGraphics2D for dependencies, we have the following
 * loop-detection array: iEngine, iGraphics3D, iGraphics2D. If we find that
 * iGraphics2D depends on anyone that is in the loop array, we found a loop.
 * If we find that the plugin depends on anyone that is already in the load
 * list, its not a loop but just an already-fullfilled dependency.
 * Thus, the above table will be traversed this way (to the left is the
 * load list, to the right is the loop detection list):
 *

 *
 []                                  [iEngine]
 *
 []                                  [iEngine,iVFS]
 *
 [iVFS]                              [iEngine]
 *
 [iVFS]                              [iEngine,iGraphics3D]
 *
 [iVFS]                              [iEngine,iGraphics3D,iGraphics2D]
 *
 [iVFS,iGraphics2D]                  [iEngine,iGraphics3D]
 *
 [iVFS,iGraphics2D,iGraphics3D]      [iEngine]
 *
 [iVFS,iGraphics2D,iGraphics3D,iEngine] []
 *

 * In this example we traversed all plugins in one go. If we didn't, we
 * just take the next one (iEngine, iVFS, iGraphics3D, iGraphics2D) and if
 * it is not already in the load list, recursively traverse it.
 */
bool csPluginList::Sort (iObjectRegistry* object_reg)
{
  int row, col, len = Length ();

  // Build the dependency matrix
  bool *matrix = (bool *)alloca (len * len * sizeof (bool));
  memset (matrix, 0, len * len * sizeof (bool));
  for (row = 0; row < len; row++)
  {
    const char *dep = iSCF::SCF->GetClassDependencies (Get (row).ClassID);
    while (dep && *dep)
    {
      char tmp [100];
      const char *comma = strchr (dep, ',');
      if (!comma)
        comma = strchr (dep, 0);
      size_t sl = comma - dep;
      if (sl >= sizeof (tmp))
        sl = sizeof (tmp) - 1;
      memcpy (tmp, dep, sl);
      while (sl && ((tmp [sl - 1] == ' ') || (tmp [sl - 1] == '\t')))
        sl--;
      tmp [sl] = 0;
      if (!sl)
        break;
      bool wildcard = tmp [sl - 1] == '.';
      for (col = 0; col < len; col++)
        if ((col != row)
         && (wildcard ? strncmp (tmp, Get (col).ClassID, sl) :
             strcmp (tmp, Get (col).ClassID)) == 0)
          matrix [row * len + col] = true;
      dep = comma;
      while (*dep == ',' || *dep == ' ' || *dep == '\t')
        dep++;
    }
  }

  // Go through dependency matrix and put all plugins into an array
  bool error = false;
  int *order = (int *)alloca (sizeof (int) * (len + 1));
  *order = 0;
  int *loop = (int *)alloca (sizeof (int) * (len + 1));
  *loop = 0;

  for (row = 0; row < len; row++)
    if (!RecurseSort (object_reg, row, order, loop, matrix))
      error = true;

  // Reorder plugin list according to "order" array
  csSome *newroot = (csSome *)malloc (len * sizeof (csSome));
  for (row = 0; row < len; row++)
    newroot [row] = root [order [row] - 1];
  free (root); root = newroot;

  return !error;
}

static int* strchr_int (int* str, int fnd)
{
  while (*str != fnd)
  {
    if (!*str) return NULL;
    str++;
  }
  return str;
}

bool csPluginList::RecurseSort (iObjectRegistry *object_reg,
	int row, int *order, int *loop, bool *matrix)
{
  // If the plugin is already in the load list, skip it
  if (strchr_int (order, row + 1))
    return true;

  int len = Length ();
  bool *dep = matrix + row * len;
  bool error = false;
  int *loopp = strchr_int (loop, 0);
  *loopp++ = row + 1; *loopp = 0;
  int col, x;
  for (col = 0; col < len; col++)
    if (*dep++)
    {
      // If the plugin is already loaded, skip
      if (strchr_int (order, col + 1))
        continue;

      int *already = strchr_int (loop, col + 1);
      if (already)
      {
	csReport (object_reg, CS_REPORTER_SEVERITY_ERROR,
	    "crystalspace.pluginloader.recursesort",
	    "Cyclic dependency detected!");
        int startx = int (already - loop);
        for (x = startx; loop [x]; x++)
	{
	  csReport (object_reg, CS_REPORTER_SEVERITY_ERROR,
	    "crystalspace.pluginloader.recursesort",
            "   %s %s",
            x == startx ? "+->" : loop [x + 1] ? "| |" : "<-+",
            Get (loop [x] - 1).ClassID);
	}
        error = true;
        break;
      }

      bool recurse_error = !RecurseSort (object_reg, col, order, loop, matrix);

      // Drop recursive loop dependency since it has already been ordered.
      *loopp = 0;

      if (recurse_error)
      {
        error = true;
        break;
      }
    }

  // Put current plugin into the list
  int *orderp = strchr_int (order, 0);
  *orderp++ = row + 1; *orderp = 0;

  return !error;
}

//--------------------------------------------------- The plugin loader -----//

csPluginLoader::csPluginLoader (iObjectRegistry* object_reg)
{
  csPluginLoader::object_reg = object_reg;
}

csPluginLoader::~csPluginLoader ()
{
}

bool csPluginLoader::LoadPlugins ()
{
  // Collect all options from command line
  iCommandLineParser* CommandLine = CS_QUERY_REGISTRY (object_reg,
  	iCommandLineParser);
  CS_ASSERT (CommandLine != NULL);

  // The list of plugins
  csPluginList PluginList;

  // Now eat all common-for-plugins command-line switches
  bool g3d_override = false;

  const char *val;
  if ((val = CommandLine->GetOption ("video")))
  {
    // Alternate videodriver
    char temp [100];
    cs_snprintf (temp, sizeof(temp), "crystalspace.graphics3d.%s", val);
    //sprintf (temp, "crystalspace.graphics3d.%s", val);
    csReport (object_reg, CS_REPORTER_SEVERITY_NOTIFY,
    	"crystalspace.pluginloader.loadplugins",
    	"Using alternative 3D driver: %s", temp);
    PluginList.Push (new csPluginLoadRec ("iGraphics3D", temp));
    g3d_override = true;
  }
  if ((val = CommandLine->GetOption ("canvas")))
  {
    if (!strchr (val, '.'))
    {
      char temp [100];
      cs_snprintf (temp, sizeof(temp), "crystalspace.graphics2d.%s", val);
      //sprintf (temp, "crystalspace.graphics2d.%s", val);
      CommandLine->ReplaceOption ("canvas", temp);
    }
  }

  // Eat all --plugin switches specified on the command line
  int n = 0;
  while ((val = CommandLine->GetOption ("plugin", n++)))
  {
    size_t sl = strlen (val);
    char temp [100];
    if (sl >= sizeof (temp)) sl = sizeof (temp) - 1;
    memcpy (temp, val, sl); temp [sl] = 0;
    char *tag = strchr (temp, ':');
    if (tag) *tag++ = 0;
    if (g3d_override && !strcmp ("iGraphics3D", tag)) continue;
    PluginList.Push (new csPluginLoadRec (tag, temp));
  }

  CommandLine->DecRef (); CommandLine = NULL;

  // Now load and initialize all plugins
  iConfigManager* Config = CS_QUERY_REGISTRY (object_reg, iConfigManager);
  iConfigIterator *plugin_list = Config->Enumerate ("System.Plugins.");
  if (plugin_list)
  {
    while (plugin_list->Next ())
    {
      const char *tag = plugin_list->GetKey (true);
      // If -video was used to override 3D driver, then respect it.
      if (g3d_override && strcmp (tag, "iGraphics3D") == 0)
        continue;
      const char *classID = plugin_list->GetStr ();
      if (classID)
        PluginList.Push (new csPluginLoadRec (tag, classID));
    }
    plugin_list->DecRef ();
  }

  iVFS* VFS = CS_QUERY_REGISTRY (object_reg, iVFS);

  // Check all requested plugins and see if there is already
  // a plugin with that tag present. If not we add it.
  int i;
  for (i = 0 ; i < requested_plugins.Length () ; i++)
  {
    csPluginLoadRec& req_plugin = requested_plugins.Get (i);
    int j;
    bool present = false;
    for (j = 0 ; j < PluginList.Length () ; j++)
    {
      csPluginLoadRec& plugin = PluginList.Get (j);
      if (plugin.Tag && !strcmp (plugin.Tag, req_plugin.Tag))
      {
        present = true;
	break;
      }
    }
    if (!present)
    {
      PluginList.Push (new csPluginLoadRec (req_plugin.Tag,
      	req_plugin.ClassID));
    }
  }

  // Sort all plugins by their dependency lists
  if (!PluginList.Sort (object_reg))
  {
    Config->DecRef ();
    if (VFS) VFS->DecRef ();
    return false;
  }

  iPluginManager* plugin_mgr = CS_QUERY_REGISTRY (object_reg, iPluginManager);

  // Load all plugins
  for (n = 0; n < PluginList.Length (); n++)
  {
    const csPluginLoadRec& r = PluginList.Get(n);
    // If plugin is VFS then skip if already loaded earlier.
    if (VFS && r.Tag && strcmp (r.Tag, "iVFS") == 0)
      continue;
    iBase *plg = plugin_mgr->LoadPlugin (r.ClassID, NULL, 0);
    if (plg)
    {
      if (!object_reg->Register (plg, r.Tag))
      {
        Config->DecRef ();
        plugin_mgr->DecRef ();
        if (VFS) VFS->DecRef ();
        if (r.Tag)
          csReport (object_reg, CS_REPORTER_SEVERITY_ERROR,
    	    "crystalspace.pluginloader.loadplugins",
    	    "Duplicate tag '%s' found for plugin '%s'!", r.Tag, r.ClassID);
        else
          csReport (object_reg, CS_REPORTER_SEVERITY_ERROR,
    	    "crystalspace.pluginloader.loadplugins",
    	    "Could not register plugin '%s'!", r.ClassID);
        return false;
      }
      plg->DecRef ();
    }
  }

  // flush all removed config files
  Config->FlushRemoved();

  Config->DecRef ();
  plugin_mgr->DecRef ();
  if (VFS) VFS->DecRef ();
  return true;
}

void csPluginLoader::RequestPlugin (const char *pluginName,
	const char* tagName)
{
  requested_plugins.Push (new csPluginLoadRec (tagName, pluginName));
}

<commit_msg>small fix<commit_after>/*
    Copyright (C) 1998-2001 by Jorrit Tyberghein

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>

#define CS_SYSDEF_PROVIDE_ALLOCA
#include "cssysdef.h"
#include "csutil/scf.h"
#include "csutil/plugldr.h"
#include "csutil/csvector.h"
#include "csutil/util.h"
#include "csutil/snprintf.h"
#include "ivaria/reporter.h"
#include "iutil/objreg.h"
#include "iutil/cmdline.h"
#include "iutil/cfgmgr.h"
#include "iutil/plugin.h"
#include "iutil/vfs.h"

/**
 * Since every plugin can depend on another one, the plugin loader should be
 * able to sort them by their preferences. Thus, if some plugin A wants some
 * other plugins B and C to be loaded before him, the plugin loader should
 * sort the list of loaded plugins such that plugin A comes after B and C.
 *

 * Of course it is possible that some plugin A depends on B and B depends on A,
 * or even worse A on B, B on C and C on A. The sort algorithm should detect
 * this case and type an error message if it is detected.
 *

 * The algorithm works as follows. First, a dependency matrix is built. Here
 * is a example of a simple dependency matrix:
 *

 *                iEngine      iVFS     iGraphics3D iGraphics2D
 *             +-----------+-----------+-----------+-----------+
 * iEngine     |           |     X     |     X     |     X     |
 *             +-----------+-----------+-----------+-----------+
 * iVFS        |           |           |           |           |
 *             +-----------+-----------+-----------+-----------+
 * iGraphics3D |           |     X     |           |     X     |
 *             +-----------+-----------+-----------+-----------+
 * iGraphics2D |           |     X     |           |           |
 *             +-----------+-----------+-----------+-----------+
 *

 * Thus, we see that the iEngine plugin depends on iVFS, iGraphics3D and
 * iGraphics2D plugins (this is an abstract example, in reality the
 * things are simpler), iVFS does not depend on anything, iGraphics3D
 * wants the iVFS and the iGraphics2D plugins, and finally iGraphics2D
 * wants just the iVFS.
 *

 * The sort algorithm works as follows: we take each plugin, one by one
 * starting from first (iEngine) and examine each of them. If some plugin
 * depends on others, we recursively launch this algorithm on those plugins.
 * If we don't have any more dependencies, we put the plugin into the
 * load list and return to the previous recursion level. To detect loops
 * we need to maintain an "recurse list", thus if we found that iEngine
 * depends on iGraphics3D, iGraphics3D depends on iGraphics2D and we're
 * examining iGraphics2D for dependencies, we have the following
 * loop-detection array: iEngine, iGraphics3D, iGraphics2D. If we find that
 * iGraphics2D depends on anyone that is in the loop array, we found a loop.
 * If we find that the plugin depends on anyone that is already in the load
 * list, its not a loop but just an already-fullfilled dependency.
 * Thus, the above table will be traversed this way (to the left is the
 * load list, to the right is the loop detection list):
 *

 *
 []                                  [iEngine]
 *
 []                                  [iEngine,iVFS]
 *
 [iVFS]                              [iEngine]
 *
 [iVFS]                              [iEngine,iGraphics3D]
 *
 [iVFS]                              [iEngine,iGraphics3D,iGraphics2D]
 *
 [iVFS,iGraphics2D]                  [iEngine,iGraphics3D]
 *
 [iVFS,iGraphics2D,iGraphics3D]      [iEngine]
 *
 [iVFS,iGraphics2D,iGraphics3D,iEngine] []
 *

 * In this example we traversed all plugins in one go. If we didn't, we
 * just take the next one (iEngine, iVFS, iGraphics3D, iGraphics2D) and if
 * it is not already in the load list, recursively traverse it.
 */
bool csPluginList::Sort (iObjectRegistry* object_reg)
{
  int row, col, len = Length ();

  // Build the dependency matrix
  bool *matrix = (bool *)alloca (len * len * sizeof (bool));
  memset (matrix, 0, len * len * sizeof (bool));
  for (row = 0; row < len; row++)
  {
    const char *dep = iSCF::SCF->GetClassDependencies (Get (row).ClassID);
    while (dep && *dep)
    {
      char tmp [100];
      const char *comma = strchr (dep, ',');
      if (!comma)
        comma = strchr (dep, 0);
      size_t sl = comma - dep;
      if (sl >= sizeof (tmp))
        sl = sizeof (tmp) - 1;
      memcpy (tmp, dep, sl);
      while (sl && ((tmp [sl - 1] == ' ') || (tmp [sl - 1] == '\t')))
        sl--;
      tmp [sl] = 0;
      if (!sl)
        break;
      bool wildcard = tmp [sl - 1] == '.';
      for (col = 0; col < len; col++)
        if ((col != row)
         && (wildcard ? strncmp (tmp, Get (col).ClassID, sl) :
             strcmp (tmp, Get (col).ClassID)) == 0)
          matrix [row * len + col] = true;
      dep = comma;
      while (*dep == ',' || *dep == ' ' || *dep == '\t')
        dep++;
    }
  }

  // Go through dependency matrix and put all plugins into an array
  bool error = false;
  int *order = (int *)alloca (sizeof (int) * (len + 1));
  *order = 0;
  int *loop = (int *)alloca (sizeof (int) * (len + 1));
  *loop = 0;

  for (row = 0; row < len; row++)
    if (!RecurseSort (object_reg, row, order, loop, matrix))
      error = true;

  // Reorder plugin list according to "order" array
  csSome *newroot = (csSome *)malloc (len * sizeof (csSome));
  for (row = 0; row < len; row++)
    newroot [row] = root [order [row] - 1];
  free (root); root = newroot;

  return !error;
}

static int* strchr_int (int* str, int fnd)
{
  while (*str != fnd)
  {
    if (!*str) return NULL;
    str++;
  }
  return str;
}

bool csPluginList::RecurseSort (iObjectRegistry *object_reg,
	int row, int *order, int *loop, bool *matrix)
{
  // If the plugin is already in the load list, skip it
  if (strchr_int (order, row + 1))
    return true;

  int len = Length ();
  bool *dep = matrix + row * len;
  bool error = false;
  int *loopp = strchr_int (loop, 0);
  *loopp++ = row + 1; *loopp = 0;
  int col, x;
  for (col = 0; col < len; col++)
    if (*dep++)
    {
      // If the plugin is already loaded, skip
      if (strchr_int (order, col + 1))
        continue;

      int *already = strchr_int (loop, col + 1);
      if (already)
      {
	csReport (object_reg, CS_REPORTER_SEVERITY_ERROR,
	    "crystalspace.pluginloader.recursesort",
	    "Cyclic dependency detected!");
        int startx = int (already - loop);
        for (x = startx; loop [x]; x++)
	{
	  csReport (object_reg, CS_REPORTER_SEVERITY_ERROR,
	    "crystalspace.pluginloader.recursesort",
            "   %s %s",
            x == startx ? "+->" : loop [x + 1] ? "| |" : "<-+",
            Get (loop [x] - 1).ClassID);
	}
        error = true;
        break;
      }

      bool recurse_error = !RecurseSort (object_reg, col, order, loop, matrix);

      // Drop recursive loop dependency since it has already been ordered.
      *loopp = 0;

      if (recurse_error)
      {
        error = true;
        break;
      }
    }

  // Put current plugin into the list
  int *orderp = strchr_int (order, 0);
  *orderp++ = row + 1; *orderp = 0;

  return !error;
}

//--------------------------------------------------- The plugin loader -----//

csPluginLoader::csPluginLoader (iObjectRegistry* object_reg)
{
  csPluginLoader::object_reg = object_reg;
}

csPluginLoader::~csPluginLoader ()
{
}

bool csPluginLoader::LoadPlugins ()
{
  // Collect all options from command line
  iCommandLineParser* CommandLine = CS_QUERY_REGISTRY (object_reg,
  	iCommandLineParser);
  CS_ASSERT (CommandLine != NULL);

  // The list of plugins
  csPluginList PluginList;

  // Now eat all common-for-plugins command-line switches
  bool g3d_override = false;

  const char *val;
  if ((val = CommandLine->GetOption ("video")))
  {
    // Alternate videodriver
    char temp [100];
    cs_snprintf (temp, sizeof(temp), "crystalspace.graphics3d.%s", val);
    //sprintf (temp, "crystalspace.graphics3d.%s", val);
    csReport (object_reg, CS_REPORTER_SEVERITY_NOTIFY,
    	"crystalspace.pluginloader.loadplugins",
    	"Using alternative 3D driver: %s", temp);
    PluginList.Push (new csPluginLoadRec ("iGraphics3D", temp));
    g3d_override = true;
  }
  if ((val = CommandLine->GetOption ("canvas")))
  {
    if (!strchr (val, '.'))
    {
      char temp [100];
      cs_snprintf (temp, sizeof(temp), "crystalspace.graphics2d.%s", val);
      //sprintf (temp, "crystalspace.graphics2d.%s", val);
      CommandLine->ReplaceOption ("canvas", temp);
    }
  }

  // Eat all --plugin switches specified on the command line
  int n = 0;
  while ((val = CommandLine->GetOption ("plugin", n++)))
  {
    size_t sl = strlen (val);
    char temp [100];
    if (sl >= sizeof (temp)) sl = sizeof (temp) - 1;
    memcpy (temp, val, sl); temp [sl] = 0;
    char *tag = strchr (temp, ':');
    if (tag) *tag++ = 0;
    if (g3d_override && tag && !strcmp ("iGraphics3D", tag)) continue;
    PluginList.Push (new csPluginLoadRec (tag, temp));
  }

  CommandLine->DecRef (); CommandLine = NULL;

  // Now load and initialize all plugins
  iConfigManager* Config = CS_QUERY_REGISTRY (object_reg, iConfigManager);
  iConfigIterator *plugin_list = Config->Enumerate ("System.Plugins.");
  if (plugin_list)
  {
    while (plugin_list->Next ())
    {
      const char *tag = plugin_list->GetKey (true);
      // If -video was used to override 3D driver, then respect it.
      if (g3d_override && strcmp (tag, "iGraphics3D") == 0)
        continue;
      const char *classID = plugin_list->GetStr ();
      if (classID)
        PluginList.Push (new csPluginLoadRec (tag, classID));
    }
    plugin_list->DecRef ();
  }

  iVFS* VFS = CS_QUERY_REGISTRY (object_reg, iVFS);

  // Check all requested plugins and see if there is already
  // a plugin with that tag present. If not we add it.
  int i;
  for (i = 0 ; i < requested_plugins.Length () ; i++)
  {
    csPluginLoadRec& req_plugin = requested_plugins.Get (i);
    int j;
    bool present = false;
    for (j = 0 ; j < PluginList.Length () ; j++)
    {
      csPluginLoadRec& plugin = PluginList.Get (j);
      if (plugin.Tag && !strcmp (plugin.Tag, req_plugin.Tag))
      {
        present = true;
	break;
      }
    }
    if (!present)
    {
      PluginList.Push (new csPluginLoadRec (req_plugin.Tag,
      	req_plugin.ClassID));
    }
  }

  // Sort all plugins by their dependency lists
  if (!PluginList.Sort (object_reg))
  {
    Config->DecRef ();
    if (VFS) VFS->DecRef ();
    return false;
  }

  iPluginManager* plugin_mgr = CS_QUERY_REGISTRY (object_reg, iPluginManager);

  // Load all plugins
  for (n = 0; n < PluginList.Length (); n++)
  {
    const csPluginLoadRec& r = PluginList.Get(n);
    // If plugin is VFS then skip if already loaded earlier.
    if (VFS && r.Tag && strcmp (r.Tag, "iVFS") == 0)
      continue;
    iBase *plg = plugin_mgr->LoadPlugin (r.ClassID, NULL, 0);
    if (plg)
    {
      if (!object_reg->Register (plg, r.Tag))
      {
        Config->DecRef ();
        plugin_mgr->DecRef ();
        if (VFS) VFS->DecRef ();
        if (r.Tag)
          csReport (object_reg, CS_REPORTER_SEVERITY_ERROR,
    	    "crystalspace.pluginloader.loadplugins",
    	    "Duplicate tag '%s' found for plugin '%s'!", r.Tag, r.ClassID);
        else
          csReport (object_reg, CS_REPORTER_SEVERITY_ERROR,
    	    "crystalspace.pluginloader.loadplugins",
    	    "Could not register plugin '%s'!", r.ClassID);
        return false;
      }
      plg->DecRef ();
    }
  }

  // flush all removed config files
  Config->FlushRemoved();

  Config->DecRef ();
  plugin_mgr->DecRef ();
  if (VFS) VFS->DecRef ();
  return true;
}

void csPluginLoader::RequestPlugin (const char *pluginName,
	const char* tagName)
{
  requested_plugins.Push (new csPluginLoadRec (tagName, pluginName));
}

<|endoftext|>