diff --git a/.gitignore b/.gitignore index 87289b07f..2ec020514 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,7 @@ spec/nim/bin # Rust compiled code, cargo and rls data spec/rust/target/ + +src/bin +.vscode +spec/c/test_* diff --git a/builder/c_builder.rb b/builder/c_builder.rb new file mode 100644 index 000000000..bcf8d60be --- /dev/null +++ b/builder/c_builder.rb @@ -0,0 +1,27 @@ +require 'fileutils' + +require_relative 'cpp_builder' + +class CBuilder < CppBuilder + attr_accessor :mode + + def initialize(src_dir, cpp_spec_dir, cpp_test_out_dir) + super(src_dir, cpp_spec_dir, cpp_test_out_dir) + end + + def list_disposable_files + list = Dir.glob("#{@cpp_spec_dir}/**/*.c") + Dir.glob("#{@src_dir}/*.c") + Dir.glob("#{@cpp_spec_dir}/**/*.cpp") + Dir.glob("#{@src_dir}/*.cpp") + list.map { |x| + r = File.absolute_path(x) + + # On Windows, filesystem is case insensitive, but our Set + # implementation is not. So we proactively normalize everything we + # can to lower case. + if @mode == :msbuild_windows + r.downcase! + end + + r + } + end +end diff --git a/ci-c b/ci-c new file mode 100755 index 000000000..dfffa4994 --- /dev/null +++ b/ci-c @@ -0,0 +1,23 @@ +#!/bin/sh -ef + +. ./config + +SRC_DIR="$(pwd)/compiled/c" +C_SPEC_DIR="$(pwd)/spec/c" +C_TEST_OUT_DIR="$TEST_OUT_DIR/c" + +./run-c "$SRC_DIR" "$C_SPEC_DIR" "$C_TEST_OUT_DIR" + +# Run C valgrind check, generates Valgrind XML report +echo 'Running Valgrind checks...' +if valgrind --version; then + ./valgrind-c "$SRC_DIR" "$C_TEST_OUT_DIR" || : +else + echo 'Valgrind not found :-(' + + # Generate empty valgrind output - this is normal and it should not stop `ci.json` generation + echo '' >"$C_TEST_OUT_DIR/valgrind.xml" +fi + +./kst-adoption-report $(basename "$SRC_DIR") +aggregate/convert_to_json cpp_stl "$C_TEST_OUT_DIR" "$C_TEST_OUT_DIR/ci.json" diff --git a/kst-adoption-report b/kst-adoption-report index 571869ae0..d00460cb1 100755 --- a/kst-adoption-report +++ b/kst-adoption-report @@ -34,6 +34,8 @@ def glob_spec_files(lang) Dir.glob('spec/construct/**/test_*.py') when 'ruby' Dir.glob('spec/ruby/**/*_spec.rb') + when 'c' + Dir.glob('spec/c/**/test_*.cpp') else raise "Unable to handle language #{@lang.inspect}" end @@ -74,6 +76,9 @@ def spec_file_to_test_name(lang, fn) when 'ruby' raise "Unable to extract test name from #{fn.inspect}" unless fn =~ /^(.*?)_spec\.rb$/ underscore_to_ucamelcase($1) + when 'c' + raise "Unable to extract test name from #{fn.inspect}" unless fn =~ /^test_(.*?)\.cpp$/ + underscore_to_ucamelcase($1) else raise "Unable to handle language #{lang.inspect}" end diff --git a/run-c b/run-c new file mode 100755 index 000000000..048b010a3 --- /dev/null +++ b/run-c @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby + +require_relative 'builder/c_builder' +CBuilder.new(ARGV[0], ARGV[1], ARGV[2]).command_line(ARGV[3..-1]) diff --git a/spec/c/.gitignore b/spec/c/.gitignore new file mode 100644 index 000000000..5d19f2f70 --- /dev/null +++ b/spec/c/.gitignore @@ -0,0 +1 @@ +tests diff --git a/spec/c/CMakeLists.txt b/spec/c/CMakeLists.txt new file mode 100644 index 000000000..121df6b86 --- /dev/null +++ b/spec/c/CMakeLists.txt @@ -0,0 +1,57 @@ +cmake_minimum_required(VERSION 3.1) + +project(KS_TEST_C) + +set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") + +find_package(Boost COMPONENTS unit_test_framework REQUIRED) +find_package(ZLIB REQUIRED) +find_package(Iconv REQUIRED) + +# Enforce UTF-8 source files encoding for MSVC +add_compile_options("$<$:/utf-8>") + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror ") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror -Wno-unused-function -std=c89 -Wdeclaration-after-statement -Wformat=2") +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +set(RUNTIME_SRC_PATH ../../../runtime/c) +set(PREREQ_PATH prereq) + +include(${INC_PATH}) + +set(PREREQ_SOURCES + ${PREREQ_PATH}/custom.c +) + +set(RUNTIME_SOURCES + ${RUNTIME_SRC_PATH}/kaitaistruct.c +) + +add_executable (ks_tests + ${RUNTIME_SOURCES} + ${PREREQ_SOURCES} + ${DISPOSABLE_SOURCES} +) + +include_directories( + "${PROJECT_BINARY_DIR}" + "${KS_PATH}" + "${RUNTIME_SRC_PATH}" + "${PREREQ_PATH}" + "${ZLIB_INCLUDE_DIRS}" +) + +# NB: no quotes around variables here, as it messes up new "optimized +# A debug B" syntax which gets generated on Windows platforms +target_link_libraries(ks_tests + ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} + ${ZLIB_LIBRARIES} + ${Iconv_LIBRARIES} +) + +add_test(ks_tests ks_tests) + +enable_testing() diff --git a/spec/c/cmake/FindIconv.cmake b/spec/c/cmake/FindIconv.cmake new file mode 100644 index 000000000..bf1c9e4c5 --- /dev/null +++ b/spec/c/cmake/FindIconv.cmake @@ -0,0 +1,143 @@ +# Part of modern CMake library (since 2017-11-29), not yet available in most +# CMake distributions: +# +# https://gitlab.kitware.com/cmake/cmake/blob/master/Modules/FindIconv.cmake +# https://github.com/Kitware/CMake/blob/master/Modules/FindIconv.cmake +# +# Minor modifications to allow it to run in standalone environment: +# fix file includes from a current directory to module includes (no +# dir, no .cmake extension). + +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#[=======================================================================[.rst: +FindIconv +--------- + +This module finds the ``iconv()`` POSIX.1 functions on the system. +These functions might be provided in the regular C library or externally +in the form of an additional library. + +The following variables are provided to indicate iconv support: + +.. variable:: Iconv_FOUND + + Variable indicating if the iconv support was found. + +.. variable:: Iconv_INCLUDE_DIRS + + The directories containing the iconv headers. + +.. variable:: Iconv_LIBRARIES + + The iconv libraries to be linked. + +.. variable:: Iconv_IS_BUILT_IN + + A variable indicating whether iconv support is stemming from the + C library or not. Even if the C library provides `iconv()`, the presence of + an external `libiconv` implementation might lead to this being false. + +Additionally, the following :prop_tgt:`IMPORTED` target is being provided: + +.. variable:: Iconv::Iconv + + Imported target for using iconv. + +The following cache variables may also be set: + +.. variable:: Iconv_INCLUDE_DIR + + The directory containing the iconv headers. + +.. variable:: Iconv_LIBRARY + + The iconv library (if not implicitly given in the C library). + +.. note:: + On POSIX platforms, iconv might be part of the C library and the cache + variables ``Iconv_INCLUDE_DIR`` and ``Iconv_LIBRARY`` might be empty. + +#]=======================================================================] + +include(CMakePushCheckState) +if(CMAKE_C_COMPILER_LOADED) + include(CheckCSourceCompiles) +elseif(CMAKE_CXX_COMPILER_LOADED) + include(CheckCXXSourceCompiles) +else() + # If neither C nor CXX are loaded, implicit iconv makes no sense. + set(Iconv_IS_BUILT_IN FALSE) +endif() + +# iconv can only be provided in libc on a POSIX system. +# If any cache variable is already set, we'll skip this test. +if(NOT DEFINED Iconv_IS_BUILT_IN) + if(UNIX AND NOT DEFINED Iconv_INCLUDE_DIR AND NOT DEFINED Iconv_LIBRARY) + cmake_push_check_state(RESET) + # We always suppress the message here: Otherwise on supported systems + # not having iconv in their C library (e.g. those using libiconv) + # would always display a confusing "Looking for iconv - not found" message + set(CMAKE_FIND_QUIETLY TRUE) + # The following code will not work, but it's sufficient to see if it compiles. + # Note: libiconv will define the iconv functions as macros, so CheckSymbolExists + # will not yield correct results. + set(Iconv_IMPLICIT_TEST_CODE + " + #include + #include + int main() { + char *a, *b; + size_t i, j; + iconv_t ic; + ic = iconv_open(\"to\", \"from\"); + iconv(ic, &a, &i, &b, &j); + iconv_close(ic); + } + " + ) + if(CMAKE_C_COMPILER_LOADED) + check_c_source_compiles("${Iconv_IMPLICIT_TEST_CODE}" Iconv_IS_BUILT_IN) + else() + check_cxx_source_compiles("${Iconv_IMPLICIT_TEST_CODE}" Iconv_IS_BUILT_IN) + endif() + cmake_pop_check_state() + else() + set(Iconv_IS_BUILT_IN FALSE) + endif() +endif() + +if(NOT Iconv_IS_BUILT_IN) + find_path(Iconv_INCLUDE_DIR + NAMES "iconv.h" + DOC "iconv include directory") + set(Iconv_LIBRARY_NAMES "iconv" "libiconv") +else() + set(Iconv_INCLUDE_DIR "" CACHE FILEPATH "iconv include directory") + set(Iconv_LIBRARY_NAMES "c") +endif() + +find_library(Iconv_LIBRARY + NAMES ${Iconv_LIBRARY_NAMES} + DOC "iconv library (potentially the C library)") + +mark_as_advanced(Iconv_INCLUDE_DIR) +mark_as_advanced(Iconv_LIBRARY) + +include(FindPackageHandleStandardArgs) +if(NOT Iconv_IS_BUILT_IN) + find_package_handle_standard_args(Iconv REQUIRED_VARS Iconv_LIBRARY Iconv_INCLUDE_DIR) +else() + find_package_handle_standard_args(Iconv REQUIRED_VARS Iconv_LIBRARY) +endif() + +if(Iconv_FOUND) + set(Iconv_INCLUDE_DIRS "${Iconv_INCLUDE_DIR}") + set(Iconv_LIBRARIES "${Iconv_LIBRARY}") + if(NOT TARGET Iconv::Iconv) + add_library(Iconv::Iconv INTERFACE IMPORTED) + endif() + set_property(TARGET Iconv::Iconv PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${Iconv_INCLUDE_DIRS}") + set_property(TARGET Iconv::Iconv PROPERTY INTERFACE_LINK_LIBRARIES "${Iconv_LIBRARIES}") +endif() diff --git a/spec/c/main.cpp b/spec/c/main.cpp new file mode 100644 index 000000000..90d7ccdb1 --- /dev/null +++ b/spec/c/main.cpp @@ -0,0 +1,3 @@ +#define BOOST_TEST_MODULE "C test units for Kaitai Struct" +#define BOOST_TEST_DYN_LINK +#include diff --git a/spec/c/prereq/custom.c b/spec/c/prereq/custom.c new file mode 100644 index 000000000..8f42f61ba --- /dev/null +++ b/spec/c/prereq/custom.c @@ -0,0 +1,68 @@ +#include + +static ks_bytes* decode1(void*userdata, ks_bytes* src) +{ + int length = ks_bytes_get_length(src) + 2; + char* data = calloc(1, length); + ks_bytes* ret; + ks_bytes_get_data(src, data + 1); + + data[0] = '_'; + data[length - 1] = '_'; + + ret = ks_bytes_recreate(src, data, length); + free(data); + return ret; +} + +ks_custom_decoder custom_fx_no_args_create(void) +{ + ks_custom_decoder ret = {0}; + ret.decode = decode1; + return ret; +} + +void custom_fx_no_args_destroy(ks_custom_decoder decoder) +{ +} + +ks_custom_decoder custom_fx_create(int p_key) +{ + ks_custom_decoder ret = {0}; + ret.decode = decode1; + return ret; +} + +void custom_fx_destroy(ks_custom_decoder decoder) +{ +} + +static ks_bytes* decode2(void* userdata, ks_bytes* src) { + int i; + int key = *(int*)userdata; + int len = ks_bytes_get_length(src); + char* data = calloc(1, len); + ks_bytes* ret; + ks_bytes_get_data(src, data); + + for (i = 0; i < len; i++) + data[i] = data[i] + key; + + ret = ks_bytes_recreate(src, data, len); + free(data); + return ret; +} + +ks_custom_decoder my_custom_fx_create(int p_key, int p_flag, ks_bytes* p_some_bytes) +{ + ks_custom_decoder ret = {0}; + ret.userdata = malloc(sizeof(int)); + *((int*)ret.userdata) = p_flag ? p_key : -p_key; + ret.decode = decode2; + return ret; +} + +void my_custom_fx_destroy(ks_custom_decoder decoder) +{ + free(decoder.userdata); +} diff --git a/spec/c/prereq/custom_fx.h b/spec/c/prereq/custom_fx.h new file mode 100644 index 000000000..c30c14d8f --- /dev/null +++ b/spec/c/prereq/custom_fx.h @@ -0,0 +1,9 @@ +#ifndef CUSTOM_FX_H_ +#define CUSTOM_FX_H_ + +#include + +ks_custom_decoder custom_fx_create(int p_key); +void custom_fx_destroy(ks_custom_decoder decoder); + +#endif diff --git a/spec/c/prereq/custom_fx_no_args.h b/spec/c/prereq/custom_fx_no_args.h new file mode 100644 index 000000000..73b7effee --- /dev/null +++ b/spec/c/prereq/custom_fx_no_args.h @@ -0,0 +1,9 @@ +#ifndef CUSTOM_FX_NO_ARGS_H_ +#define CUSTOM_FX_NO_ARGS_H_ + +#include + +ks_custom_decoder custom_fx_no_args_create(void); +void custom_fx_no_args_destroy(ks_custom_decoder decoder); + +#endif diff --git a/spec/c/prereq/my_custom_fx.h b/spec/c/prereq/my_custom_fx.h new file mode 100644 index 000000000..15f7049ac --- /dev/null +++ b/spec/c/prereq/my_custom_fx.h @@ -0,0 +1,9 @@ +#ifndef MY_CUSTOM_FX_H_ +#define MY_CUSTOM_FX_H_ + +#include + +ks_custom_decoder my_custom_fx_create(int p_key, int p_flag, ks_bytes* p_some_bytes); +void my_custom_fx_destroy(ks_custom_decoder decoder); + +#endif diff --git a/spec/c/prereq/operators.h b/spec/c/prereq/operators.h new file mode 100644 index 000000000..3fc95d257 --- /dev/null +++ b/spec/c/prereq/operators.h @@ -0,0 +1,128 @@ +extern "C" { +#include +} +#include +#include + +class bytes_wrapper { +public: + const ks_bytes* data; + bytes_wrapper(const ks_bytes* bytes) : data(bytes) {} +}; + +inline bool operator==(const ks_string s1, const char* s2) +{ + return strcmp(s1.data, s2) == 0; +} + +inline bool operator==(const ks_string s1, const ks_string s2) +{ + return strcmp(s1.data, s2.data) == 0; +} + +inline bool operator!=(const ks_string s1, const ks_string s2) +{ + return !(s1 == s2); +} + +inline std::ostream& operator<<(std::ostream& out, const ks_string s) +{ + return out << s.data; +} + +inline bool operator==(const bytes_wrapper b1, const bytes_wrapper b2) +{ + uint8_t* data1; + uint8_t* data2; + uint64_t length1, length2; + + length1 = ks_bytes_get_length(b1.data); + length2 = ks_bytes_get_length(b2.data); + + if (length1 != length2) + return false; + + data1 = (uint8_t*)malloc(length1); + data2 = (uint8_t*)malloc(length2); + ks_bytes_get_data(b1.data, data1); + ks_bytes_get_data(b2.data, data2); + + for (uint64_t i = 0; i < length1; i++) + { + if (data1[i] != data2[i]) + { + free(data1); + free(data2); + return false; + } + } + + free(data1); + free(data2); + return true; +} + +inline std::ostream& operator<<(std::ostream& out, const bytes_wrapper b) +{ + uint8_t* data; + uint64_t length; + std::stringstream ss; + + length = ks_bytes_get_length(b.data); + data = (uint8_t*)malloc(length); + ks_bytes_get_data(b.data, data); + + bool first = true; + for (uint64_t i = 0; i < length; i++) + { + if (!first) + ss << ", "; + ss << std::hex << "0x" << (int)data[i]; + first = false; + } + free(data); + + return out << "[ " << ss.str() << " ]"; +} + +#define COMPARE_ARRAY(typ, act, ...) \ + { \ + typ temp1[] = {__VA_ARGS__}; \ + std::vector temp2( \ + temp1, \ + temp1 + sizeof(temp1) / sizeof(typ) \ + ); \ + std::vector temp3( \ + act->data, \ + act->data + act->size \ + ); \ + BOOST_CHECK_EQUAL_COLLECTIONS( \ + temp3.begin(), temp3.end(), \ + temp2.begin(), temp2.end() \ + ); \ + } + +#define COMPARE_ARRAY_POINTER(typ, act, ...) \ + { \ + typ* temp1[] = {__VA_ARGS__}; \ + std::vector temp2( \ + temp1, \ + temp1 + sizeof(temp1) / sizeof(typ*) \ + ); \ + std::vector temp3( \ + act->data, \ + act->data + act->size \ + ); \ + std::vector temp4; \ + for (uint32_t i = 0; i < temp2.size(); i++) { \ + temp4.push_back(*temp2[i]); \ + } \ + std::vector temp5; \ + for (uint32_t i = 0; i < temp3.size(); i++) { \ + temp5.push_back(*temp3[i]); \ + } \ + BOOST_CHECK_EQUAL_COLLECTIONS( \ + temp5.begin(), temp5.end(), \ + temp4.begin(), temp4.end() \ + ); \ + } diff --git a/translator/src/main/scala/io/kaitai/struct/testtranslator/Main.scala b/translator/src/main/scala/io/kaitai/struct/testtranslator/Main.scala index c5dfbdc10..6e44b908e 100644 --- a/translator/src/main/scala/io/kaitai/struct/testtranslator/Main.scala +++ b/translator/src/main/scala/io/kaitai/struct/testtranslator/Main.scala @@ -14,6 +14,7 @@ object Main extends App { val importsDir = s"$baseDir/../formats" val ALL_LANGS = List( + "c", "construct", "cpp_stl_98", "cpp_stl_11", diff --git a/translator/src/main/scala/io/kaitai/struct/testtranslator/TestTranslator.scala b/translator/src/main/scala/io/kaitai/struct/testtranslator/TestTranslator.scala index 336bdff87..85fa1fa35 100644 --- a/translator/src/main/scala/io/kaitai/struct/testtranslator/TestTranslator.scala +++ b/translator/src/main/scala/io/kaitai/struct/testtranslator/TestTranslator.scala @@ -108,6 +108,7 @@ class TestTranslator(options: CLIOptions) { } def getSG(lang: String, testSpec: TestSpec, provider: ClassTypeProvider): BaseGenerator = lang match { + case "c" => new CSG(testSpec, provider) case "construct" => new ConstructSG(testSpec, provider) case "cpp_stl_98" => new CppStlSG(testSpec, provider, CppRuntimeConfig().copyAsCpp98()) case "cpp_stl_11" => new CppStlSG(testSpec, provider, CppRuntimeConfig().copyAsCpp11()) diff --git a/translator/src/main/scala/io/kaitai/struct/testtranslator/specgenerators/CSG.scala b/translator/src/main/scala/io/kaitai/struct/testtranslator/specgenerators/CSG.scala new file mode 100644 index 000000000..34504410f --- /dev/null +++ b/translator/src/main/scala/io/kaitai/struct/testtranslator/specgenerators/CSG.scala @@ -0,0 +1,125 @@ +package io.kaitai.struct.testtranslator.specgenerators + +import io.kaitai.struct.datatype.{DataType, KSError} +import io.kaitai.struct.exprlang.Ast +import io.kaitai.struct.languages.CCompiler +import io.kaitai.struct.testtranslator.{Main, TestEquals, TestSpec} +import io.kaitai.struct.datatype.DataType._ +import io.kaitai.struct.translators.CTranslator +import io.kaitai.struct.{ClassTypeProvider, RuntimeConfig} +import io.kaitai.struct.languages.components.CppImportList + +class CSG(spec: TestSpec, provider: ClassTypeProvider) extends BaseGenerator(spec) { + val compiler = new CCompiler(provider, RuntimeConfig()) + val className = spec.id.toLowerCase() + val cppImportList = new CppImportList + val translator = new CTranslator(provider, cppImportList, false) + + override def fileName(name: String): String = s"test_$name.cpp" + + cppImportList.addLocal("operators.h") + cppImportList.addSystem("boost/test/unit_test.hpp") + spec.extraImports.foreach(entry => cppImportList.addLocal(s"$entry.h")) + cppImportList.addSystem("stdio.h") + + override def header() = { + out.puts("static void log(const char* text) {") + out.puts(" printf(text);") + out.puts("}") + out.puts + out.puts(s"BOOST_AUTO_TEST_CASE(test_${spec.id}) {") + out.inc + } + + override def runParse(): Unit = { + runParseCommon1() + out.puts(s"BOOST_CHECK_EQUAL(error, 0);") + out.puts("if (error != 0) return;") + } + + override def runParseExpectError(exception: KSError): Unit = { + runParseCommon1() + out.puts(s"BOOST_CHECK_EQUAL(error == 0, 0);") + } + + def runParseCommon1(): Unit = { + out.puts(s"ksx_$className* data;") + out.puts("ks_stream* stream;") + out.puts("ks_config* config;") + out.puts("ks_error error;") + out.puts("config = ks_config_create(log);") + out.puts("FILE* file = fopen(\"src/" + spec.data + "\", \"r\");") + out.puts("BOOST_CHECK_EQUAL(file != 0, 1);") + out.puts("if (!file) return;") + out.puts("stream = ks_stream_create_from_file(file, config);") + out.puts(s"data = ksx_read_${className}_from_stream(stream, &error);") + out.puts(s"(void)data;") + } + + override def footer() = { + out.puts + out.puts("ks_config_destroy(config);") + out.dec + out.puts("}") + } + + override def simpleEquality(check: TestEquals): Unit = { + val ptr = translator.detectType(check.expected) match { + case t: StrType => "*" + case _ => "" + } + val actStr = translateAct(check.actual) + val expStr = translator.translate(check.expected) + translator.detectType(check.expected) match { + case t: BytesType => + out.puts(s"BOOST_CHECK_EQUAL(bytes_wrapper($actStr), bytes_wrapper($expStr));") + case _ => + out.puts(s"BOOST_CHECK_EQUAL($ptr$actStr, $ptr$expStr);") + } + } + + override def floatEquality(check: TestEquals): Unit = { + val actStr = translateAct(check.actual) + val expStr = translator.translate(check.expected) + out.puts(s"BOOST_CHECK_CLOSE($actStr, $expStr, 1e-4);") + } + + override def nullAssert(actual: Ast.expr): Unit = { + val nullCheckStr = actual match { + case Ast.expr.Attribute(x, Ast.identifier(attrName)) => + fixup("!" + translator.anyField(x, s"_is_valid_$attrName")) + } + out.puts(s"BOOST_CHECK($nullCheckStr);") + } + + override def trueArrayEquality(check: TestEquals, elType: DataType, elts: Seq[Ast.expr]): Unit = { + val elTypeName = CCompiler.kaitaiType2NativeType(elType) + val eltsStr = elts.map(translator.translate).mkString(", ") + val actStr = translateAct(check.actual) + elType match { + case t: StrType => + out.puts(s"COMPARE_ARRAY_POINTER(ks_string, $actStr, $eltsStr);") + case _ => + out.puts(s"COMPARE_ARRAY($elTypeName, $actStr, $eltsStr);") + } + } + + override def indentStr: String = " " + + override def results: String = { + "// " + AUTOGEN_COMMENT + "\n\n" + + "#define KS_USE_ZLIB\n" + + "#define KS_USE_ICONV\n" + + "extern \"C\" {\n" + + "#include \"" + spec.id + ".h\"\n" + + "}\n" + + cppImportList.result + "\n" + + out.result + } + + def fixup(s: String) : String = s.replace("->" + Main.INIT_OBJ_NAME, "") + + def translateAct(x: Ast.expr) = { + fixup(translator.translate(x)) + } +} diff --git a/valgrind-c b/valgrind-c new file mode 100755 index 000000000..983328e12 --- /dev/null +++ b/valgrind-c @@ -0,0 +1,15 @@ +#!/bin/sh -e + +. ./config + +if [ "$#" -ne 2 ]; then + echo "$0 " + exit 1 +fi + +SRC_DIR="$1" +C_TEST_OUT_DIR="$2" + +OBJ_DIR="$SRC_DIR/bin" + +valgrind --leak-check=full --xml=yes --xml-file="$C_TEST_OUT_DIR/valgrind.xml" "$OBJ_DIR/ks_tests"