Commit 47038d17 authored by Paul Asmuth's avatar Paul Asmuth
Browse files

simplify the C API, add the new C++ fviz::eval API

parent 4a5357ff
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -68,7 +68,7 @@ endif()

# Build: Config
# -----------------------------------------------------------------------------
configure_file(core/config.h.in fviz_config.h)
configure_file(core/config.h.in config.h)
message(STATUS "Config Options: text_backend=${FVIZ_TEXT_BACKEND}")
message(STATUS "Config Options: text_enable_bidi=${FVIZ_TEXT_ENABLE_BIDI}")

@@ -84,7 +84,7 @@ add_library(fviz-lib-a STATIC $<TARGET_OBJECTS:fviz>)
set_target_properties(fviz-lib-a PROPERTIES OUTPUT_NAME fviz)
add_library(fviz-lib-so SHARED $<TARGET_OBJECTS:fviz>)
set_target_properties(fviz-lib-so PROPERTIES OUTPUT_NAME fviz)
set_target_properties(fviz-lib-so PROPERTIES PUBLIC_HEADER "core/fviz.h")
set_target_properties(fviz-lib-so PROPERTIES PUBLIC_HEADER "core/api.h")


# Build: CLI

core/api.cc

0 → 100644
+76 −0
Original line number Diff line number Diff line
/**
 * This file is part of the "fviz" project
 *   Copyright (c) 2018 Paul Asmuth
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "api.h"
#include "core/environment.h"
#include "core/eval.h"

#include <iostream>
#include <string.h>

using namespace std::placeholders;
using namespace fviz;

struct fviz_s {
  OutputFormat format;
  std::string buffer;
  ReturnCode error;
};

fviz_t* fviz_init() {
  auto ctx = std::make_unique<fviz_t>();
  ctx->format = OutputFormat::SVG;
  return ctx.release();
}

void fviz_destroy(fviz_t* ctx) {
  delete ctx;
}

const char* fviz_get_error(const fviz_t* ctx) {
  return ctx->error.message.c_str();
}

void fviz_set_error(fviz_t* ctx, const ReturnCode& err) {
  ctx->error = err;
}

int fviz_eval(fviz_t* ctx, const char* expr) {
  Environment env;
  auto rc = fviz::eval(env, expr, ctx->format, &ctx->buffer);
  fviz_set_error(ctx, rc);
  return rc;
}

void fviz_get_result(fviz_t* ctx, const void** data, size_t* data_len) {
  *data = ctx->buffer.data();
  *data_len = ctx->buffer.size();
}

int fviz_set_output_format(fviz_t* ctx, const char* path, const char* fmt) {
  std::string format = fmt;

  if (format == "svg") {
    ctx->format == OutputFormat::SVG;
    return OK;
  }

  if (format == "png") {
    ctx->format == OutputFormat::PNG;
    return OK;
  }

  fviz_set_error(ctx, errorf(ERROR, "invalid output format: {}", format));
  return ERROR;
}

core/api.h

0 → 100644
+65 −0
Original line number Diff line number Diff line
/**
 * This file is part of the "fviz" project
 *   Copyright (c) 2018 Paul Asmuth
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#pragma once
#include <stdlib.h>

/**
 * The fviz C API
 */
#ifdef __cplusplus
extern "C" {
#endif

typedef struct fviz_s fviz_t;

/**
 * Initialize a new fviz context.
 *
 * @returns: A fviz context that must be free'd using `fviz_destroy`
 */
fviz_t* fviz_init();

/**
 * Free a fviz context
 */
void fviz_destroy(fviz_t* ctx);

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

/**
 * Evaluate an fviz expression
 *
 * @returns: One (1) on success and zero (0) if an error has occured
 */
int fviz_eval(fviz_t* ctx, const char* expr);

/**
 * Retrieve the result. Pointer is valid until the next call to fviz_eval
 */
void fviz_get_result(fviz_t* ctx, const void** data, size_t* data_len);

/**
 * Set the output format
 */
void fviz_set_output_format(fviz_t* ctx, const char* format);


#ifdef __cplusplus
} // extern C
#endif
+71 −22
Original line number Diff line number Diff line
@@ -14,12 +14,13 @@
#include <stdlib.h>
#include <unistd.h>
#include <iostream>
#include "fviz.h"
#include "fviz_config.h"
#include "config.h"
#include "utils/flagparser.h"
#include "return_code.h"
#include "utils/stringutil.h"
#include "core/environment.h"
#include "core/eval.h"
#include "fileutil.h"

using namespace fviz;

@@ -36,8 +37,14 @@ int main(int argc, const char** argv) {
  std::string flag_out;
  flag_parser.defineString("out", false, &flag_out);

  std::string flag_out_fmt;
  flag_parser.defineString("outfmt", false, &flag_out_fmt);
  bool flag_stdin = false;
  flag_parser.defineSwitch("stdin", &flag_stdin);

  bool flag_stdout = false;
  flag_parser.defineSwitch("stdout", &flag_stdout);

  std::string flag_format;
  flag_parser.defineString("format", false, &flag_format);

  bool flag_help = false;
  flag_parser.defineSwitch("help", &flag_help);
@@ -79,7 +86,9 @@ int main(int argc, const char** argv) {
        "Usage: $ fviz [OPTIONS]\n"
        "  --in <path>               Path to the input file\n"
        "  --out <path>              Path to the output file\n"
        "  --outfmt <format>         Output format. If no format is given, it is inferred from the\n"
        "  --stdin                   Read the input file from stdin\n"
        "  --stdout                  Write the output file from sdout\n"
        "  --format <format>         Output format. If no format is given, it is inferred from the\n"
        "                            filename. Valid values: 'png', 'svg'\n"
        "  --font-defaults <bool>    Enable or disable default font loading. Default is enabled.\n"
        "                            Valid values: 'on' and 'off'\n"
@@ -94,40 +103,80 @@ int main(int argc, const char** argv) {
    return 0;
  }

  if (flag_in.empty()) {
  /* check if the input flags are valid */
  if (flag_in.empty() && !flag_stdin) {
    std::cerr << "Need an input file (--in)\n";
    return 1;
  }

  if (flag_out.empty()) {
  if (!flag_in.empty() && flag_stdin) {
    std::cerr
        << "Can't read from an input file (--in) and stdin (--stdin) at the "
        << "same time\n";

    return 1;
  }

  if (flag_out.empty() && !flag_stdout) {
    std::cerr << "Need an output file (--out)\n";
    return 1;
  }

  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 (!flag_out.empty() && flag_stdout) {
    std::cerr
        << "Can't write to an output file (--out) and stdout (--stdout) at the "
        << "same time\n";

    return 1;
  }

  fviz_t* ctx = fviz_init();
  if (!ctx) {
    std::cerr << "ERROR: error while initializing fviz" << std::endl;
  /* figure out which output format the user wants */
  auto output_format = fviz::OutputFormat::SVG;
  if (flag_format.empty()) {
    if (StringUtil::endsWith(flag_out, ".svg"))
      output_format = OutputFormat::SVG;
    if (StringUtil::endsWith(flag_out, ".png"))
      output_format = OutputFormat::PNG;
  } else if (flag_format == "svg") {
    output_format = OutputFormat::SVG;
  } else if (flag_format == "png") {
    output_format = OutputFormat::PNG;
  } else {
    std::cerr
        << "ERROR: invalid output format (--format). valid values are "
        << "'svg' and 'png'"
        << std::endl;

    return EXIT_FAILURE;
  }

  Environment* env = static_cast<Environment*>(fviz_env(ctx));
  env->font_defaults = flag_font_defaults;
  env->font_load = flag_font_load;
  /* run fviz */
  Environment env;
  env.font_defaults = flag_font_defaults;
  env.font_load = flag_font_load;

  std::string input;
  if (auto rc = read_file(flag_in, &input); !rc) {
    fmt::print(
        stderr,
        "ERROR: unable to read input file ({}): {}\n",
        flag_in,
        rc.message);
  }

  if (!fviz_configure_file(ctx, flag_in.c_str())) {
    fviz_printerror(ctx);
  std::string output_buffer;
  if (auto rc = fviz::eval(env, input, output_format, &output_buffer); !rc) {
    error_print(rc, std::cerr);
    return EXIT_FAILURE;
  }

  if (!fviz_render_file(ctx, flag_out.c_str(), fmt.c_str())) {
    fviz_printerror(ctx);
    return EXIT_FAILURE;
  /* write the output file */
  if (flag_stdout) {
    std::cout << output_buffer;
  } else {
    FileUtil::write(
        flag_out,
        Buffer(output_buffer.data(), output_buffer.size()));
  }

  return EXIT_SUCCESS;
+35 −0
Original line number Diff line number Diff line
@@ -18,6 +18,23 @@
#include "sexpr_util.h"
#include "graphics/font_lookup.h"

#include "elements/text.h"
#include "elements/plot.h"
#include "elements/plot/areas.h"
#include "elements/plot/axis.h"
#include "elements/plot/bars.h"
#include "elements/plot/errorbars.h"
#include "elements/plot/grid.h"
#include "elements/plot/labels.h"
#include "elements/plot/lines.h"
#include "elements/plot/points.h"
#include "elements/plot/vectors.h"
#include "elements/chart/linechart.h"
#include "elements/chart/scatterplot.h"
#include "elements/layout/box.h"
#include "elements/legend.h"
#include "elements/legend/item.h"

#include <functional>

using namespace std::placeholders;
@@ -36,6 +53,24 @@ Environment::Environment() :
    color_palette(color_palette_default()) {}

ReturnCode environment_setup_defaults(Environment* env) {
  auto elems = &env->element_map;
  element_bind(elems, "chart/linechart", bind(elements::chart::linechart::build, _1, _2, _3));
  element_bind(elems, "chart/scatterplot", bind(elements::chart::scatterplot::build, _1, _2, _3));
  element_bind(elems, "plot", bind(elements::plot::build, _1, _2, _3));
  element_bind(elems, "plot/areas", bind(elements::plot::areas::build, _1, _2, _3));
  element_bind(elems, "plot/axis", bind(elements::plot::axis::build, _1, _2, _3));
  element_bind(elems, "plot/bars", bind(elements::plot::bars::build, _1, _2, _3));
  element_bind(elems, "plot/errorbars", bind(elements::plot::errorbars::build, _1, _2, _3));
  element_bind(elems, "plot/grid", bind(elements::plot::grid::build, _1, _2, _3));
  element_bind(elems, "plot/labels", bind(elements::plot::labels::build, _1, _2, _3));
  element_bind(elems, "plot/lines", bind(elements::plot::lines::build, _1, _2, _3));
  element_bind(elems, "plot/points", bind(elements::plot::points::build, _1, _2, _3));
  element_bind(elems, "plot/vectors", bind(elements::plot::vectors::build, _1, _2, _3));
  element_bind(elems, "legend", bind(elements::legend::build, _1, _2, _3));
  element_bind(elems, "legend/item", bind(elements::legend::item::build, _1, _2, _3));
  element_bind(elems, "layout/box", bind(elements::layout::box::build, _1, _2, _3));
  element_bind(elems, "text", bind(elements::text::build, _1, _2, _3));

  if (env->font_defaults) {
    if (auto rc = font_load_defaults(&env->font); !rc) {
      return rc;
Loading