Commit a635999d authored by Paul Asmuth's avatar Paul Asmuth
Browse files

add a minimal C api

parent 0c8b9b46
Loading
Loading
Loading
Loading
+33 −7
Original line number Diff line number Diff line
cmake_minimum_required(VERSION 2.8.8)
project(plotfx)
add_definitions("-DPLOTFX_VERSION='\"v0.2.0\"'")


# CMake Setup
# -----------------------------------------------------------------------------
cmake_minimum_required(VERSION 2.8.8)
enable_testing()

set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/extra/cmake")
@@ -10,6 +15,9 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/source)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/source/utils)
include_directories(${CMAKE_CURRENT_SOURCE_DIR})


# Dependencies
# -----------------------------------------------------------------------------
find_package(Threads)
find_package(Cairo)
find_package(Freetype)
@@ -18,9 +26,12 @@ find_package(Fontconfig)
find_package(PNG)
include_directories(${CAIRO_INCLUDE_DIRS} ${FREETYPE_INCLUDE_DIRS} ${HARFBUZZ_INCLUDE_DIRS} ${PNG_INCLUDE_DIRS})

add_definitions(-DPLOTFX_VERSION="v0.2.0")

add_library(plotfxlib STATIC
# Build: PlotFX Library
# -----------------------------------------------------------------------------
add_library(plotfx STATIC
    source/plotfx.cc
    source/plotfx_sdl.cc # TODO: only if SDL enabled
    source/plot.cc
    source/plot_area.cc
    source/plot_axis.cc
@@ -72,12 +83,27 @@ add_library(plotfxlib STATIC
    source/utils/UTF8.cc
    source/utils/wallclock.cc)

set(PLOTFX_LDFLAGS plotfxlib ${CAIRO_LIBRARIES} ${FREETYPE_LIBRARIES} ${HARFBUZZ_LIBRARIES} ${HARFBUZZ_ICU_LIBRARIES} ${PNG_LIBRARIES} ${FONTCONFIG_LIBRARIES})
set_target_properties(plotfx PROPERTIES
    PUBLIC_HEADER "source/plotfx.h;source/plotfx_sdl.h")

set(PLOTFX_LDFLAGS plotfx ${CAIRO_LIBRARIES} ${FREETYPE_LIBRARIES} ${HARFBUZZ_LIBRARIES} ${HARFBUZZ_ICU_LIBRARIES} ${PNG_LIBRARIES} ${FONTCONFIG_LIBRARIES})


# Build: CLI
# -----------------------------------------------------------------------------
add_executable(plotfx-cli source/plotfx_cli.cc)
target_link_libraries(plotfx-cli ${PLOTFX_LDFLAGS})
set_target_properties(plotfx-cli PROPERTIES OUTPUT_NAME plotfx)


# Installation
# -----------------------------------------------------------------------------
install(TARGETS plotfx ARCHIVE DESTINATION lib PUBLIC_HEADER DESTINATION include/plotfx)
install(TARGETS plotfx-cli DESTINATION bin)

add_executable(plotfx source/plotfx_cli.cc)
target_link_libraries(plotfx ${PLOTFX_LDFLAGS})
install(TARGETS plotfx DESTINATION bin)

# Testing
# -----------------------------------------------------------------------------
file(GLOB unit_test_files "tests/unit/**/test_*.cc")
foreach(unit_test_path ${unit_test_files})
  get_filename_component(unit_test_name ${unit_test_path} NAME_WE)

source/plotfx.cc

0 → 100644
+92 −0
Original line number Diff line number Diff line
/**
 * This file is part of the "plotfx" project
 *   Copyright (c) 2018 Paul Asmuth
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 
 * * Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 * 
 * * Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 * 
 * * Neither the name of the copyright holder nor the names of its
 *   contributors may be used to endorse or promote products derived from
 *   this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include "plotfx.h"
#include "document.h"
#include <iostream>
#include <fstream>
#include <sstream>

using namespace plotfx;

plotfx_t* plotfx_init() {
  auto ctx = std::make_unique<Context>();
  return ctx.release();
}

int plotfx_configure(
    plotfx_t* ctx,
    const char* config) {
  auto& doc = static_cast<Context*>(ctx)->document;
  doc.reset(new Document());

  if (auto rc = document_load(config, doc.get()); !rc) {
    ctx_seterr(ctx, rc);
    return ERROR;
  }

  return OK;
}

int plotfx_configure_file(
    plotfx_t* ctx,
    const char* path) {
  std::stringstream config_buf;
  {
    std::ifstream config_file(path);
    if (!config_file.is_open()) {
      ctx_seterrf(ctx, StringUtil::format("file not found: $0", path));
      return ERROR;
    }

    config_buf << config_file.rdbuf();
  }

  return plotfx_configure(ctx, config_buf.str().c_str());
}

int plotfx_render_file(plotfx_t* ctx, const char* path, const char* format) {
  const auto& doc = static_cast<const Context*>(ctx)->document;
  if (!doc) {
    ctx_seterrf(ctx, "no configuration loaded");
    return ERROR;
  }

  if (auto rc = document_render(*doc, format, path); !rc) {
    ctx_seterr(ctx, rc);
    return ERROR;
  }

  return OK;
}

const char* plotfx_geterror(const plotfx_t* ctx) {
  return static_cast<const Context*>(ctx)->error.c_str();
}
+120 −16
Original line number Diff line number Diff line
@@ -29,20 +29,124 @@
 */
#pragma once
#include <stdlib.h>
#include <vector>
#include <string>

namespace plotfx {
struct Context;

enum Status : int {
  OK = 0,
  ERROR,
  ERROR_IO,
  ERROR_NOT_IMPLEMENTED,
  ERROR_INVALID_ARGUMENT,
  ERROR_INVALID_ELEM
};

} // namespace plotfx

/**
 * The PlotFX C API
 *
 * How to use:
 *  1) Call `plotfx_init_*` to create a new context, for example `plotfx_init_svgfile`
 *  2) Call `plotfx_configure` and pass the configuration string
 *  3) Optional: Call `plotfx_setvar` to override/set dynamic variables
 *  4) Call `plotfx_submit`
 *  5) Optional: Retrieve the result using `plotfx_getimage`
 *  6) Optional: Repeat steps 2..6
 *  7) Once you're done with the PlotFX context, free it using `plotfx_destroy`
 */
#ifdef __cplusplus
extern "C" {
#endif

typedef void plotfx_t;

/**
 * Initialize a new PlotFX context.
 *
 * @returns: A plotfx context that must be free'd using `plotfx_destroy`
 */
plotfx_t* plotfx_init();

/**
 * Render the context to an file. If format is nullptr, the filetype is inferred
 * from the filename.
 *
 * @returns: One (1) on success and zero (0) if an error has occured
 */
int plotfx_render_file(plotfx_t* ctx, const char* path, const char* format);

/**
 * Render the context to an SVG file. The result image will
 * be written to the provided filesystem path once you call `plotfx_Submit`
 *
 * @returns: One (1) on success and zero (0) if an error has occured
 */
int plotfx_render_svgfile(plotfx_t* ctx, const char* path);

/**
 * Free a PlotFX context
 */
void plotfx_destroy(plotfx_t* ctx);

/**
 * Set the configuration of the PlotFX context. Please refer to the documentation
 * for the syntax and available properties in the PlotFX configuration file.
 *
 * @returns: One (1) on success and zero (0) if an error has occured
 */
int plotfx_configure(
    plotfx_t* ctx,
    const char* config);

/**
 * Set the configuration of the PlotFX context. Please refer to the documentation
 * for the syntax and available properties in the PlotFX configuration file.
 *
 * @returns: One (1) on success and zero (0) if an error has occured
 */
int plotfx_configure_file(
    plotfx_t* ctx,
    const char* path);

/**
 * Retrieve the last error message. The returned pointer is valid until the next
 * `plotfx_*` method is called on the context.
 */
const char* plotfx_geterror(const plotfx_t* ctx);

/**
 * Set a variable in the given PlotFX context.
 *
 * NOTE: If you use this to override a variable that is also set in the
 * configuration file, the order in which you call the `plotfx_configure` and
 * `plotfx_setvar` methods is significant.
 */
void plotfx_setvar_f64(
    plotfx_t* ctx,
    const char* name,
    size_t name_len,
    double value);

/**
 * Set a variable in the given PlotFX context.
 */
void plotfx_setvar_f64v(
    plotfx_t* ctx,
    const char* name,
    size_t name_len,
    const double* values,
    size_t value_count);

/**
 * Set a variable in the given PlotFX context.
 */
void plotfx_setvar_str(
    plotfx_t* ctx,
    const char* name,
    size_t name_len,
    const char* value,
    size_t value_len);

/**
 * Set a variable in the given PlotFX context.
 */
void plotfx_setvar_strv(
    plotfx_t* ctx,
    const char* name,
    size_t name_len,
    const char** values,
    const size_t* value_lens,
    size_t value_count);

#ifdef __cplusplus
} // extern C
#endif
+27 −25
Original line number Diff line number Diff line
@@ -31,21 +31,11 @@
 */
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <regex>
#include <iostream>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/file.h>
#include "plotfx.h"
#include "source/document.h"
#include "graphics/layer.h"
#include "graphics/layer_svg.h"
#include "graphics/layer_pixmap.h"
#include <utils/flagparser.h>
#include <utils/fileutil.h>
#include <utils/return_code.h>
#include <utils/stringutil.h>
#include "utils/flagparser.h"
#include "utils/return_code.h"
#include "utils/stringutil.h"

using namespace plotfx;

@@ -71,6 +61,9 @@ int main(int argc, const char** argv) {
  bool flag_version = false;
  flag_parser.defineSwitch("version", &flag_version);

  bool flag_debug = true;
  flag_parser.defineSwitch("debug", &flag_debug);

  {
    auto rc = flag_parser.parseArgv(argc - 1, argv + 1);
    if (!rc.isSuccess()) {
@@ -114,24 +107,33 @@ int main(int argc, const char** argv) {
    return 1;
  }

  auto doc_raw = FileUtil::read(flag_in).toString(); // FIXME

  plotfx::Document doc;
  if (auto rc = document_load(doc_raw, &doc); !rc.isSuccess()) {
    printError(rc);
    return EXIT_FAILURE;
  }

  std::string fmt = flag_out_fmt;
  if (fmt.empty()) {
    if (StringUtil::endsWith(flag_out, ".svg")) { fmt = "svg"; }
    if (StringUtil::endsWith(flag_out, ".png")) { fmt = "png"; }
  }

  if (auto rc = document_render(doc, fmt, flag_out); rc.isSuccess()) {
    return EXIT_SUCCESS;
  } else {
    printError(rc);
  plotfx_t* ctx = plotfx_init();
  if (!ctx) {
    std::cerr << "ERROR: error while initializing PlotFX" << std::endl;
    return EXIT_FAILURE;
  }

  if (!plotfx_configure_file(ctx, flag_in.c_str())) {
    std::cerr
        << "ERROR: error while parsing configuration: "
        << plotfx_geterror(ctx)
        << std::endl;
    return EXIT_FAILURE;
  }

  if (!plotfx_render_file(ctx, flag_out.c_str(), fmt.c_str())) {
    std::cerr
        << "ERROR: error while rendering"
        << plotfx_geterror(ctx)
        << std::endl;
    return EXIT_FAILURE;
  }

  return EXIT_SUCCESS;
}