From 826e1fe87182f804a7d2424e2057ff5baaaf9108 Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Mon, 15 Jun 2026 15:32:43 +1200 Subject: [PATCH] Simplify the C API wrapper --- src/GDXFile.jl | 432 ++++++++++++++++---------- src/GDXInterface.jl | 2 +- src/gdx_c_api.jl | 734 -------------------------------------------- src/libgdx.jl | 254 +++++++++++++++ 4 files changed, 529 insertions(+), 893 deletions(-) delete mode 100644 src/gdx_c_api.jl create mode 100644 src/libgdx.jl diff --git a/src/GDXFile.jl b/src/GDXFile.jl index ee6cf34..152a599 100644 --- a/src/GDXFile.jl +++ b/src/GDXFile.jl @@ -384,130 +384,177 @@ function read_gdx( only = nothing, ) gdx = GDXHandle() - gdx_create(gdx) only_filter = only === nothing ? nothing : Set{Symbol}(_symkey.(only)) - try - gdx_open_read(gdx, filepath) - gdxfile = GDXFile(filepath, Dict{Symbol,GDXSymbol}(), Symbol[]) - n_syms, n_uels = gdx_system_info(gdx) - for sym_nr in 1:n_syms - sym_name, sym_dim, sym_type = gdx_symbol_info(gdx, sym_nr) - sym_key = _symkey(sym_name) - if only_filter !== nothing && !(sym_key in only_filter) - continue - end - sym_count, sym_user_info, sym_description = - gdx_symbol_info_x(gdx, sym_nr) - if sym_type == GMS_DT_SET - _insert!( - gdxfile, - sym_key, - _read_set( - gdx, - sym_nr, - sym_name, - sym_dim, - sym_description, - sink, - ), - ) - elseif sym_type == GMS_DT_PAR - _insert!( - gdxfile, - sym_key, - _read_parameter( - gdx, - sym_nr, - sym_name, - sym_dim, - sym_description, - parse_integers, - sink, - ), - ) - elseif sym_type == GMS_DT_VAR - _insert!( - gdxfile, - sym_key, - _read_variable( - gdx, - sym_nr, - sym_name, - sym_dim, - sym_description, - sym_user_info, - parse_integers, - sink, - ), - ) - elseif sym_type == GMS_DT_EQU - _insert!( - gdxfile, - sym_key, - _read_equation( - gdx, - sym_nr, - sym_name, - sym_dim, - sym_description, - sym_user_info, - parse_integers, - sink, - ), - ) - elseif sym_type == GMS_DT_ALIAS - aliased_name = - sym_user_info > 0 ? gdx_symbol_info(gdx, sym_user_info)[1] : - "*" - _insert!( - gdxfile, - sym_key, - GDXAlias(sym_name, sym_description, aliased_name), - ) + pInt = Ref{Cint}(0) + rc = c__gdxopenread(gdx, filepath, pInt) + if pInt[] != 0 || rc != 1 + throw(GDXException("Can't open file '$filepath'", pInt[])) + end + gdxfile = GDXFile(filepath, Dict{Symbol,GDXSymbol}(), Symbol[]) + p_n_syms, p_n_uels = Ref{Cint}(), Ref{Cint}() + if c__gdxsysteminfo(gdx, p_n_syms, p_n_uels) != 1 + throw(GDXException("Can't read system info", 0)) + end + n_syms, n_uels = p_n_syms[], p_n_uels[] + cbuf = fill(UInt8(' '), GMS_SSSIZE) + for sym_nr in 1:n_syms + p_dim, p_type = Ref{Cint}(0), Ref{Cint}(0) + if c__gdxsymbolinfo(gdx, sym_nr, cbuf, p_dim, p_type) != 1 + throw(GDXException("Can't read symbol info", 0)) + end + sym_dim, sym_type = p_dim[], p_type[] + sym_name = GC.@preserve cbuf unsafe_string(pointer(cbuf)) + sym_key = _symkey(sym_name) + if only_filter !== nothing && !(sym_key in only_filter) + continue + end + cbuf[1] = UInt8('\0') + p_count, p_user_info = Ref{Cint}(0), Ref{Cint}(0) + if c__gdxsymbolinfox(gdx, sym_nr, p_count, p_user_info, cbuf) != 1 + throw(GDXException("Can't read extended symbol info", 0)) + end + sym_count, sym_user_info = p_count[], p_user_info[] + sym_description = GC.@preserve cbuf unsafe_string(pointer(cbuf)) + if sym_type == GMS_DT_SET + _insert!( + gdxfile, + sym_key, + _read_set( + gdx, + sym_nr, + sym_name, + sym_dim, + sym_description, + sink, + ), + ) + elseif sym_type == GMS_DT_PAR + _insert!( + gdxfile, + sym_key, + _read_parameter( + gdx, + sym_nr, + sym_name, + sym_dim, + sym_description, + parse_integers, + sink, + ), + ) + elseif sym_type == GMS_DT_VAR + _insert!( + gdxfile, + sym_key, + _read_variable( + gdx, + sym_nr, + sym_name, + sym_dim, + sym_description, + sym_user_info, + parse_integers, + sink, + ), + ) + elseif sym_type == GMS_DT_EQU + _insert!( + gdxfile, + sym_key, + _read_equation( + gdx, + sym_nr, + sym_name, + sym_dim, + sym_description, + sym_user_info, + parse_integers, + sink, + ), + ) + elseif sym_type == GMS_DT_ALIAS + aliased_name = "*" + if sym_user_info > 0 + p_dim, p_type = Ref{Cint}(0), Ref{Cint}(0) + if c__gdxsymbolinfo(gdx, sym_user_info, cbuf, p_dim, p_type) != + 1 + throw(GDXException("Can't read symbol info", 0)) + end + sym_dim, sym_type = p_dim[], p_type[] + aliased_name = GC.@preserve cbuf unsafe_string(pointer(cbuf)) end + alias = GDXAlias(sym_name, sym_description, aliased_name) + _insert!(gdxfile, sym_key, alias) end - gdx_close(gdx) - return gdxfile - finally - gdx_free(gdx) end + c__gdxclose(gdx) + return gdxfile +end + +function _gdx_symbol_get_domain_x(gdx::GDXHandle, sym_nr::Integer, dim::Integer) + cbufs = [fill(UInt8('\0'), GMS_SSSIZE) for _ in 1:dim] + _ = c__gdxsymbolgetdomainx(gdx, sym_nr, cbufs) + return GC.@preserve cbufs unsafe_string.(pointer.(cbufs)) +end + +function _gdx_data_read_str( + gdx::GDXHandle, + keystr::Vector{String}, + vals::Vector{Float64}, +) + cbuf = [fill(UInt8('\0'), GMS_SSSIZE) for _ in 1:length(keystr)] + p_dim_first = Ref{Cint}(0) + if c__gdxdatareadstr(gdx, cbuf, vals, p_dim_first) != 1 + throw(GDXException("Failed to read GDX record", 0)) + end + GC.@preserve cbuf begin + keystr .= unsafe_string.(pointer.(cbuf)) + end + return end function _read_set( gdx::GDXHandle, - sym_nr::Int, + sym_nr, name::String, - dim::Int, + dim, description::String, sink, ) - domains = dim > 0 ? gdx_symbol_get_domain_x(gdx, sym_nr, dim) : String[] - n_recs = gdx_data_read_str_start(gdx, sym_nr) + domains = dim > 0 ? _gdx_symbol_get_domain_x(gdx, sym_nr, dim) : String[] + p_n_recs = Ref{Cint}() + if c__gdxdatareadstrstart(gdx, sym_nr, p_n_recs) != 1 + throw(GDXException("Can't start GDX read", 0)) + end + n_recs = p_n_recs[] keys = Vector{String}(undef, max(dim, 1)) vals = Vector{Float64}(undef, GMS_VAL_MAX) columns = [Vector{String}(undef, n_recs) for _ in 1:dim] text_nrs = Vector{Int}(undef, n_recs) for i in 1:n_recs - gdx_data_read_str(gdx, keys, vals) + _gdx_data_read_str(gdx, keys, vals) for d in 1:dim columns[d][i] = keys[d] end text_nrs[i] = Int(vals[GAMS_VALUE_LEVEL]) end - gdx_data_read_done(gdx) + c__gdxdatareaddone(gdx) col_names = Symbol[ Symbol(domain == "*" ? "dim$d" : domain) for (d, domain) in enumerate(domains) ] - has_text = any(>(0), text_nrs) - if has_text - element_text = Vector{String}(undef, n_recs) + if any(>(0), text_nrs) + cbuf = fill(UInt8(' '), GMS_SSSIZE) + element_text = String["" for _ in 1:n_recs] for i in 1:n_recs if text_nrs[i] > 0 - found, text = gdx_get_elem_text(gdx, text_nrs[i]) - element_text[i] = found ? text : "" - else - element_text[i] = "" + cbuf[1] = UInt8('\0') + p_node = Ref{Cint}(0) + if c__gdxgetelemtext(gdx, text_nrs[i], cbuf, p_node) == 1 + GC.@preserve cbuf begin + element_text[i] = unsafe_string(pointer(cbuf)) + end + end end end nt = NamedTuple{(col_names..., :element_text)}(( @@ -522,27 +569,31 @@ end function _read_parameter( gdx::GDXHandle, - sym_nr::Int, + sym_nr::Integer, name::String, - dim::Int, + dim::Integer, description::String, parse_integers::Bool, sink, ) - domains = dim > 0 ? gdx_symbol_get_domain_x(gdx, sym_nr, dim) : String[] - n_recs = gdx_data_read_str_start(gdx, sym_nr) + domains = dim > 0 ? _gdx_symbol_get_domain_x(gdx, sym_nr, dim) : String[] + p_n_recs = Ref{Cint}() + if c__gdxdatareadstrstart(gdx, sym_nr, p_n_recs) != 1 + throw(GDXException("Can't start GDX read", 0)) + end + n_recs = p_n_recs[] keys = Vector{String}(undef, max(dim, 1)) vals = Vector{Float64}(undef, GMS_VAL_MAX) columns = [Vector{String}(undef, n_recs) for _ in 1:dim] values = Vector{Float64}(undef, n_recs) for i in 1:n_recs - gdx_data_read_str(gdx, keys, vals) + _gdx_data_read_str(gdx, keys, vals) for d in 1:dim columns[d][i] = keys[d] end values[i] = parse_gdx_value(vals[GAMS_VALUE_LEVEL]) end - gdx_data_read_done(gdx) + c__gdxdatareaddone(gdx) col_names = Symbol[ Symbol(domain == "*" ? "dim$d" : domain) for (d, domain) in enumerate(domains) @@ -554,16 +605,20 @@ end function _read_variable( gdx::GDXHandle, - sym_nr::Int, + sym_nr::Integer, name::String, - dim::Int, + dim::Integer, description::String, - user_info::Int, + user_info::Integer, parse_integers::Bool, sink, ) - domains = dim > 0 ? gdx_symbol_get_domain_x(gdx, sym_nr, dim) : String[] - n_recs = gdx_data_read_str_start(gdx, sym_nr) + domains = dim > 0 ? _gdx_symbol_get_domain_x(gdx, sym_nr, dim) : String[] + p_n_recs = Ref{Cint}() + if c__gdxdatareadstrstart(gdx, sym_nr, p_n_recs) != 1 + throw(GDXException("Can't start GDX read", 0)) + end + n_recs = p_n_recs[] keys = Vector{String}(undef, max(dim, 1)) vals = Vector{Float64}(undef, GMS_VAL_MAX) columns = [Vector{String}(undef, n_recs) for _ in 1:dim] @@ -573,7 +628,7 @@ function _read_variable( upper = Vector{Float64}(undef, n_recs) scale = Vector{Float64}(undef, n_recs) for i in 1:n_recs - gdx_data_read_str(gdx, keys, vals) + _gdx_data_read_str(gdx, keys, vals) for d in 1:dim columns[d][i] = keys[d] end @@ -583,7 +638,7 @@ function _read_variable( upper[i] = parse_gdx_value(vals[GAMS_VALUE_UPPER]) scale[i] = parse_gdx_value(vals[GAMS_VALUE_SCALE]) end - gdx_data_read_done(gdx) + c__gdxdatareaddone(gdx) col_names = Symbol[ Symbol(domain == "*" ? "dim$d" : domain) for (d, domain) in enumerate(domains) @@ -608,16 +663,20 @@ end function _read_equation( gdx::GDXHandle, - sym_nr::Int, + sym_nr::Integer, name::String, - dim::Int, + dim::Integer, description::String, - user_info::Int, + user_info::Integer, parse_integers::Bool, sink, ) - domains = dim > 0 ? gdx_symbol_get_domain_x(gdx, sym_nr, dim) : String[] - n_recs = gdx_data_read_str_start(gdx, sym_nr) + domains = dim > 0 ? _gdx_symbol_get_domain_x(gdx, sym_nr, dim) : String[] + p_n_recs = Ref{Cint}() + if c__gdxdatareadstrstart(gdx, sym_nr, p_n_recs) != 1 + throw(GDXException("Can't start GDX read", 0)) + end + n_recs = p_n_recs[] keys = Vector{String}(undef, max(dim, 1)) vals = Vector{Float64}(undef, GMS_VAL_MAX) columns = [Vector{String}(undef, n_recs) for _ in 1:dim] @@ -627,7 +686,7 @@ function _read_equation( upper = Vector{Float64}(undef, n_recs) scale = Vector{Float64}(undef, n_recs) for i in 1:n_recs - gdx_data_read_str(gdx, keys, vals) + _gdx_data_read_str(gdx, keys, vals) for d in 1:dim columns[d][i] = keys[d] end @@ -637,7 +696,7 @@ function _read_equation( upper[i] = parse_gdx_value(vals[GAMS_VALUE_UPPER]) scale[i] = parse_gdx_value(vals[GAMS_VALUE_SCALE]) end - gdx_data_read_done(gdx) + c__gdxdatareaddone(gdx) col_names = Symbol[ Symbol(domain == "*" ? "dim$d" : domain) for (d, domain) in enumerate(domains) @@ -682,27 +741,33 @@ function write_gdx( producer::String = "GDXInterface.jl", ) gdx = GDXHandle() - gdx_create(gdx) - try - gdx_open_write(gdx, filepath, producer) - for k in gdxfile._order - sym = gdxfile._symbols[k] - if sym isa GDXAlias - continue - end - _write_symbol(gdx, sym) + pInt = Ref{Cint}(0) + rc = c__gdxopenwrite(gdx, filepath, producer, pInt) + if pInt[] != 0 || rc != 1 + throw(GDXException("Can't open file '$filepath' for writing", pInt[])) + end + for k in gdxfile._order + sym = gdxfile._symbols[k] + if sym isa GDXAlias + continue end - for k in gdxfile._order - sym = gdxfile._symbols[k] - if !(sym isa GDXAlias) - continue - end - gdx_add_alias(gdx, sym.alias_for, sym.name) + _write_symbol(gdx, sym) + end + for k in gdxfile._order + sym = gdxfile._symbols[k] + if !(sym isa GDXAlias) + continue + end + if c__gdxaddalias(gdx, sym.alias_for, sym.name) != 1 + throw( + GDXException( + "Can't add alias '$(sym.name)' for '$(sym.alias_for)'", + 0, + ), + ) end - gdx_close(gdx) - finally - gdx_free(gdx) end + c__gdxclose(gdx) return filepath end @@ -730,16 +795,15 @@ function write_gdx( producer::String = "GDXInterface.jl", ) gdx = GDXHandle() - gdx_create(gdx) - try - gdx_open_write(gdx, filepath, producer) - for (name, tbl) in symbols - _write_parameter_table(gdx, name, tbl, _table_description(tbl)) - end - gdx_close(gdx) - finally - gdx_free(gdx) + pInt = Ref{Cint}(0) + rc = c__gdxopenwrite(gdx, filepath, producer, pInt) + if pInt[] != 0 || rc != 1 + throw(GDXException("Can't open file '$filepath' for writing", pInt[])) end + for (name, tbl) in symbols + _write_parameter_table(gdx, name, tbl, _table_description(tbl)) + end + c__gdxclose(gdx) return filepath end @@ -747,13 +811,15 @@ function _set_domain_x( gdx::GDXHandle, name::String, domain::Vector{String}, - dim::Int, + dim::Integer, ) - if !(length(domain) == dim && dim > 0) - return + if length(domain) == dim && dim > 0 + p_sym_nr = Ref{Cint}(0) + if c__gdxfindsymbol(gdx, name, p_sym_nr) == 1 + c__gdxsymbolsetdomainx(gdx, p_sym_nr[], domain) + end end - found, sym_nr = gdx_find_symbol(gdx, name) - return found && gdx_symbol_set_domain_x(gdx, sym_nr, domain) + return end function _table_description(tbl) @@ -772,6 +838,20 @@ _write_symbol(gdx::GDXHandle, sym::GDXVariable) = _write_variable(gdx, sym) _write_symbol(gdx::GDXHandle, sym::GDXEquation) = _write_equation(gdx, sym) +function gdx_data_write_str_start( + gdx::GDXHandle, + name::String, + text::String, + dim::Integer, + typ::Integer, + user_info::Int = 0, +) + if c__gdxdatawritestrstart(gdx, name, text, dim, typ, user_info) != 1 + throw(GDXException("Can't start writing symbol '$name'", 0)) + end + return +end + function _write_set(gdx::GDXHandle, sym::GDXSet) tbl = Tables.columns(sym.records) col_names = collect(Tables.columnnames(tbl)) @@ -789,12 +869,23 @@ function _write_set(gdx::GDXHandle, sym::GDXSet) end if has_text text = string(Tables.getcolumn(tbl, :element_text)[i]) - vals[GAMS_VALUE_LEVEL] = - isempty(text) ? 0.0 : Float64(gdx_add_set_text(gdx, text)) + if isempty(text) + vals[GAMS_VALUE_LEVEL] = 0.0 + else + p_text_nr = Ref{Cint}(0) + if c__gdxaddsettext(gdx, text, p_text_nr) != 1 + throw(GDXException("Can't register set element text", 0)) + end + vals[GAMS_VALUE_LEVEL] = Float64(p_text_nr[]) + end end - gdx_data_write_str(gdx, keys, vals) + if c__gdxdatawritestr(gdx, keys, vals) != 1 + throw(GDXException("Can't write record", 0)) + end + end + if c__gdxdatawritedone(gdx) != 1 + throw(GDXException("Can't finish writing symbol", 0)) end - gdx_data_write_done(gdx) return _set_domain_x(gdx, sym.name, sym.domain, dim) end @@ -828,9 +919,13 @@ function _write_parameter_table( keys[j] = string(Tables.getcolumn(cols, col)[i]) end vals[GAMS_VALUE_LEVEL] = _to_gdx_value(value_col[i]) - gdx_data_write_str(gdx, keys, vals) + if c__gdxdatawritestr(gdx, keys, vals) != 1 + throw(GDXException("Can't write record", 0)) + end + end + if c__gdxdatawritedone(gdx) != 1 + throw(GDXException("Can't finish writing symbol", 0)) end - gdx_data_write_done(gdx) return _set_domain_x(gdx, name, domain, dim) end @@ -865,9 +960,13 @@ function _write_variable(gdx::GDXHandle, sym::GDXVariable) vals[GAMS_VALUE_LOWER] = _to_gdx_value(lower_col[i]) vals[GAMS_VALUE_UPPER] = _to_gdx_value(upper_col[i]) vals[GAMS_VALUE_SCALE] = _to_gdx_value(scale_col[i]) - gdx_data_write_str(gdx, keys, vals) + if c__gdxdatawritestr(gdx, keys, vals) != 1 + throw(GDXException("Can't write record", 0)) + end + end + if c__gdxdatawritedone(gdx) != 1 + throw(GDXException("Can't finish writing symbol", 0)) end - gdx_data_write_done(gdx) return _set_domain_x(gdx, sym.name, sym.domain, dim) end @@ -900,9 +999,13 @@ function _write_equation(gdx::GDXHandle, sym::GDXEquation) vals[GAMS_VALUE_LOWER] = _to_gdx_value(lower_col[i]) vals[GAMS_VALUE_UPPER] = _to_gdx_value(upper_col[i]) vals[GAMS_VALUE_SCALE] = _to_gdx_value(scale_col[i]) - gdx_data_write_str(gdx, keys, vals) + if c__gdxdatawritestr(gdx, keys, vals) != 1 + throw(GDXException("Can't write record", 0)) + end + end + if c__gdxdatawritedone(gdx) != 1 + throw(GDXException("Can't finish writing symbol", 0)) end - gdx_data_write_done(gdx) return _set_domain_x(gdx, sym.name, sym.domain, dim) end @@ -931,3 +1034,16 @@ function _to_gdx_value(val::Float64) end _to_gdx_value(val::Real) = _to_gdx_value(Float64(val)) + +function parse_gdx_value(val::Float64) + if val == GAMS_SV_UNDEF || val == GAMS_SV_NA + return NaN + elseif val == GAMS_SV_PINF + return Inf + elseif val == GAMS_SV_MINF + return -Inf + elseif val == GAMS_SV_EPS + return -0.0 + end + return val +end diff --git a/src/GDXInterface.jl b/src/GDXInterface.jl index 54dfd6a..193e95e 100644 --- a/src/GDXInterface.jl +++ b/src/GDXInterface.jl @@ -11,7 +11,7 @@ import Tables using gdx_jll: libgdx -include("gdx_c_api.jl") +include("libgdx.jl") include("GDXFile.jl") # GDXInterface exports all symbols not starting with `_`. If you don't want all diff --git a/src/gdx_c_api.jl b/src/gdx_c_api.jl deleted file mode 100644 index 32fc3d9..0000000 --- a/src/gdx_c_api.jl +++ /dev/null @@ -1,734 +0,0 @@ -# Copyright (c) 2026 Martin Kirk Bonde, James Daniel Foster and contributors -# Copyright (c) 2020-2023 GAMS Software GmbH -# -# Use of this source code is governed by an MIT-style license that can be found -# in the LICENSE.md file or at https://opensource.org/licenses/MIT. - -# GDX library bindings (for libgdx) -# Low-level C API wrappers for reading and writing GDX files - -# libgdx C library prefix for ccall: -const GDX_C_PREFIX = "c__" -macro cpfx(x) - s = strip(string(x), ':') - return Expr(:quote, Symbol(GDX_C_PREFIX, s)) -end - -# ============================================================================= -# Constants -# ============================================================================= - -const GMS_MAX_INDEX_DIM = 20 -const GMS_SSSIZE = 256 -const GMS_VAL_MAX = 5 - -# GAMS value position in GDX data -const GAMS_VALUE_LEVEL = 1 -const GAMS_VALUE_MARGINAL = 2 -const GAMS_VALUE_LOWER = 3 -const GAMS_VALUE_UPPER = 4 -const GAMS_VALUE_SCALE = 5 - -# GAMS data types -const GMS_DT_SET = 0 -const GMS_DT_PAR = 1 -const GMS_DT_VAR = 2 -const GMS_DT_EQU = 3 -const GMS_DT_ALIAS = 4 -const GMS_DT_MAX = 5 - -# GAMS special values -const GAMS_SV_UNDEF = 1.0e300 # undefined -const GAMS_SV_NA = 2.0e300 # not available / applicable -const GAMS_SV_PINF = 3.0e300 # plus infinity -const GAMS_SV_MINF = 4.0e300 # minus infinity -const GAMS_SV_EPS = 5.0e300 # epsilon -const GAMS_SV_ACR = 10.0e300 # potential / real acronym -const GAMS_SV_NAINT = 2100000000 # not available / applicable for integers - -function parse_gdx_value(val::Float64) - if val == GAMS_SV_UNDEF || val == GAMS_SV_NA - return NaN - end - if val == GAMS_SV_PINF - return Inf - end - if val == GAMS_SV_MINF - return -Inf - end - if val == GAMS_SV_EPS - return -0.0 - end - return val -end - -# ============================================================================= -# GDX Handle -# ============================================================================= - -mutable struct GDXHandle - cptr::Ref{Ptr{Cvoid}} - cival::Ref{Cint} - cival2::Ref{Cint} - cival3::Ref{Cint} - civec::Vector{Cint} - crvec::Vector{Cdouble} - buf::Vector{Vector{UInt8}} - cbuf::Vector{Ptr{UInt8}} - - function GDXHandle() - cptr = Ref{Ptr{Cvoid}}(C_NULL) - buf = Vector{Vector{UInt8}}(undef, GMS_MAX_INDEX_DIM) - for i in 1:GMS_MAX_INDEX_DIM - buf[i] = Vector{UInt8}(undef, GMS_SSSIZE) - buf[i] .= UInt8(' ') - end - cbuf = pointer.(buf) - crvec = Vector{Cdouble}(undef, GMS_VAL_MAX) - civec = Vector{Cint}(undef, GMS_MAX_INDEX_DIM) - return new( - cptr, - Ref{Cint}(-1), - Ref{Cint}(-1), - Ref{Cint}(-1), - civec, - crvec, - buf, - cbuf, - ) - end -end - -struct GDXException <: Exception - msg::String - n_err::Int -end - -function Base.showerror(io::IO, e::GDXException) - return print(io, "GDX failed: $(e.msg) ($(e.n_err))") -end - -# ============================================================================= -# Core handle management -# ============================================================================= - -function gdx_create(gdx_ptr::Ref{Ptr{Cvoid}}) - ccall((:xcreate, libgdx), Cvoid, (Ptr{Ptr{Cvoid}},), gdx_ptr) - if gdx_ptr[] == C_NULL - throw(GDXException("Can't create GAMS GDX object", 0)) - end - return -end - -gdx_create(gdx::GDXHandle) = gdx_create(gdx.cptr) - -function gdx_free(gdx_ptr::Ref{Ptr{Cvoid}}) - ccall((:xfree, libgdx), Cvoid, (Ptr{Ptr{Cvoid}},), gdx_ptr) - return -end - -gdx_free(gdx::GDXHandle) = gdx_free(gdx.cptr) - -# ============================================================================= -# File operations -# ============================================================================= - -function gdx_open_read(gdx_ptr::Ptr{Cvoid}, file::String, n_err::Ref{Cint}) - return ccall( - (@cpfx(:gdxopenread), libgdx), - Cint, - (Ptr{Cvoid}, Cstring, Ref{Cint}), - gdx_ptr, - file, - n_err, - ) -end - -function gdx_open_read(gdx::GDXHandle, file::String) - rc = gdx_open_read(gdx.cptr[], file, gdx.cival) - if gdx.cival[] != 0 || rc != 1 - throw(GDXException("Can't open file '$file'", gdx.cival[])) - end - return rc -end - -function gdx_open_write( - gdx_ptr::Ptr{Cvoid}, - file::String, - producer::String, - n_err::Ref{Cint}, -) - return ccall( - (@cpfx(:gdxopenwrite), libgdx), - Cint, - (Ptr{Cvoid}, Cstring, Cstring, Ref{Cint}), - gdx_ptr, - file, - producer, - n_err, - ) -end - -function gdx_open_write( - gdx::GDXHandle, - file::String, - producer::String = "GAMS.jl", -) - rc = gdx_open_write(gdx.cptr[], file, producer, gdx.cival) - if gdx.cival[] != 0 || rc != 1 - throw(GDXException("Can't open file '$file' for writing", gdx.cival[])) - end - return -end - -function gdx_close(gdx_ptr::Ptr{Cvoid}) - return ccall((@cpfx(:gdxclose), libgdx), Cint, (Ptr{Cvoid},), gdx_ptr) -end - -function gdx_close(gdx::GDXHandle) - gdx_close(gdx.cptr[]) - return -end - -# ============================================================================= -# System and symbol information -# ============================================================================= - -function gdx_system_info( - gdx_ptr::Ptr{Cvoid}, - sym_count::Ref{Cint}, - uel_count::Ref{Cint}, -) - return ccall( - (@cpfx(:gdxsysteminfo), libgdx), - Cint, - (Ptr{Cvoid}, Ref{Cint}, Ref{Cint}), - gdx_ptr, - sym_count, - uel_count, - ) -end - -function gdx_system_info(gdx::GDXHandle) - rc = gdx_system_info(gdx.cptr[], gdx.cival, gdx.cival2) - if rc != 1 - throw(GDXException("Can't read system info", 0)) - end - return Int(gdx.cival[]), Int(gdx.cival2[]) -end - -function gdx_symbol_info( - gdx_ptr::Ptr{Cvoid}, - sym_id::Int, - name::Ptr{UInt8}, - dim::Ref{Cint}, - type::Ref{Cint}, -) - return ccall( - (@cpfx(:gdxsymbolinfo), libgdx), - Cint, - (Ptr{Cvoid}, Cint, Ptr{UInt8}, Ref{Cint}, Ref{Cint}), - gdx_ptr, - sym_id, - name, - dim, - type, - ) -end - -function gdx_symbol_info(gdx::GDXHandle, sym_id::Int) - gdx.buf[1][1] = UInt8('\0') - rc = gdx_symbol_info(gdx.cptr[], sym_id, gdx.cbuf[1], gdx.cival, gdx.cival2) - if rc != 1 - throw(GDXException("Can't read symbol info", 0)) - end - return unsafe_string(gdx.cbuf[1]), Int(gdx.cival[]), Int(gdx.cival2[]) -end - -function gdx_symbol_info_x( - gdx_ptr::Ptr{Cvoid}, - sym_id::Int, - count::Ref{Cint}, - user_info::Ref{Cint}, - text::Ptr{UInt8}, -) - return ccall( - (@cpfx(:gdxsymbolinfox), libgdx), - Cint, - (Ptr{Cvoid}, Cint, Ref{Cint}, Ref{Cint}, Ptr{UInt8}), - gdx_ptr, - sym_id, - count, - user_info, - text, - ) -end - -function gdx_symbol_info_x(gdx::GDXHandle, sym_id::Int) - gdx.buf[1][1] = UInt8('\0') - rc = gdx_symbol_info_x( - gdx.cptr[], - sym_id, - gdx.cival, - gdx.cival2, - gdx.cbuf[1], - ) - if rc != 1 - throw(GDXException("Can't read extended symbol info", 0)) - end - return Int(gdx.cival[]), Int(gdx.cival2[]), unsafe_string(gdx.cbuf[1]) -end - -function gdx_find_symbol(gdx_ptr::Ptr{Cvoid}, name::String, sym_nr::Ref{Cint}) - return ccall( - (@cpfx(:gdxfindsymbol), libgdx), - Cint, - (Ptr{Cvoid}, Cstring, Ref{Cint}), - gdx_ptr, - name, - sym_nr, - ) -end - -function gdx_find_symbol(gdx::GDXHandle, name::String) - rc = gdx_find_symbol(gdx.cptr[], name, gdx.cival) - return rc == 1, Int(gdx.cival[]) -end - -function gdx_symbol_get_domain_x( - gdx_ptr::Ptr{Cvoid}, - sym_nr::Int, - domains::Vector{Ptr{UInt8}}, -) - return ccall( - (@cpfx(:gdxsymbolgetdomainx), libgdx), - Cint, - (Ptr{Cvoid}, Cint, Ptr{Ptr{UInt8}}), - gdx_ptr, - sym_nr, - domains, - ) -end - -function gdx_symbol_get_domain_x(gdx::GDXHandle, sym_nr::Int, dim::Int) - for i in 1:dim - gdx.buf[i][1] = UInt8('\0') - end - rc = gdx_symbol_get_domain_x(gdx.cptr[], sym_nr, gdx.cbuf) - domains = Vector{String}(undef, dim) - for i in 1:dim - domains[i] = unsafe_string(gdx.cbuf[i]) - end - return domains -end - -function gdx_symbol_set_domain_x( - gdx_ptr::Ptr{Cvoid}, - sym_nr::Int, - domain_ids::Vector{String}, -) - return ccall( - (@cpfx(:gdxsymbolsetdomainx), libgdx), - Cint, - (Ptr{Cvoid}, Cint, Ptr{Cstring}), - gdx_ptr, - sym_nr, - domain_ids, - ) -end - -function gdx_symbol_set_domain_x( - gdx::GDXHandle, - sym_nr::Int, - domain_ids::Vector{String}, -) - rc = gdx_symbol_set_domain_x(gdx.cptr[], sym_nr, domain_ids) - return rc -end - -# ============================================================================= -# Alias -# ============================================================================= - -function gdx_add_alias(gdx_ptr::Ptr{Cvoid}, id1::String, id2::String) - return ccall( - (@cpfx(:gdxaddalias), libgdx), - Cint, - (Ptr{Cvoid}, Cstring, Cstring), - gdx_ptr, - id1, - id2, - ) -end - -function gdx_add_alias(gdx::GDXHandle, id1::String, id2::String) - rc = gdx_add_alias(gdx.cptr[], id1, id2) - if rc != 1 - throw(GDXException("Can't add alias '$id2' for '$id1'", 0)) - end - return -end - -# ============================================================================= -# Set element text -# ============================================================================= - -function gdx_get_elem_text( - gdx_ptr::Ptr{Cvoid}, - text_nr::Int, - text::Ptr{UInt8}, - node::Ref{Cint}, -) - return ccall( - (@cpfx(:gdxgetelemtext), libgdx), - Cint, - (Ptr{Cvoid}, Cint, Ptr{UInt8}, Ref{Cint}), - gdx_ptr, - text_nr, - text, - node, - ) -end - -function gdx_get_elem_text(gdx::GDXHandle, text_nr::Int) - gdx.buf[1][1] = UInt8('\0') - rc = gdx_get_elem_text(gdx.cptr[], text_nr, gdx.cbuf[1], gdx.cival) - return rc == 1, unsafe_string(gdx.cbuf[1]) -end - -function gdx_add_set_text(gdx_ptr::Ptr{Cvoid}, text::String, text_nr::Ref{Cint}) - return ccall( - (@cpfx(:gdxaddsettext), libgdx), - Cint, - (Ptr{Cvoid}, Cstring, Ref{Cint}), - gdx_ptr, - text, - text_nr, - ) -end - -function gdx_add_set_text(gdx::GDXHandle, text::String) - rc = gdx_add_set_text(gdx.cptr[], text, gdx.cival) - if rc != 1 - throw(GDXException("Can't register set element text", 0)) - end - return Int(gdx.cival[]) -end - -# ============================================================================= -# UEL (Unique Element List) operations -# ============================================================================= - -function gdx_um_uel_get( - gdx_ptr::Ptr{Cvoid}, - uel_nr::Int, - uel::Ptr{UInt8}, - uel_map::Ref{Cint}, -) - return ccall( - (@cpfx(:gdxumuelget), libgdx), - Cint, - (Ptr{Cvoid}, Cint, Ptr{UInt8}, Ref{Cint}), - gdx_ptr, - uel_nr, - uel, - uel_map, - ) -end - -function gdx_um_uel_get(gdx::GDXHandle, uel_nr::Int) - gdx.buf[1][1] = UInt8('\0') - rc = gdx_um_uel_get(gdx.cptr[], uel_nr, gdx.cbuf[1], gdx.cival) - if rc != 1 - throw(GDXException("Can't get UEL #$uel_nr", 0)) - end - return unsafe_string(gdx.cbuf[1]) -end - -function gdx_uel_register_str_start(gdx_ptr::Ptr{Cvoid}) - return ccall( - (@cpfx(:gdxuelregisterstrstart), libgdx), - Cint, - (Ptr{Cvoid},), - gdx_ptr, - ) -end - -function gdx_uel_register_str_start(gdx::GDXHandle) - rc = gdx_uel_register_str_start(gdx.cptr[]) - if rc != 1 - throw(GDXException("Can't start UEL string registration", 0)) - end - return -end - -function gdx_uel_register_str( - gdx_ptr::Ptr{Cvoid}, - uel::String, - uel_nr::Ref{Cint}, -) - return ccall( - (@cpfx(:gdxuelregisterstr), libgdx), - Cint, - (Ptr{Cvoid}, Cstring, Ref{Cint}), - gdx_ptr, - uel, - uel_nr, - ) -end - -function gdx_uel_register_str(gdx::GDXHandle, uel::String) - rc = gdx_uel_register_str(gdx.cptr[], uel, gdx.cival) - return Int(gdx.cival[]) -end - -function gdx_uel_register_done(gdx_ptr::Ptr{Cvoid}) - return ccall( - (@cpfx(:gdxuelregisterdone), libgdx), - Cint, - (Ptr{Cvoid},), - gdx_ptr, - ) -end - -function gdx_uel_register_done(gdx::GDXHandle) - rc = gdx_uel_register_done(gdx.cptr[]) - if rc != 1 - throw(GDXException("Can't finish UEL registration", 0)) - end - return -end - -# ============================================================================= -# Reading data (raw integer interface) -# ============================================================================= - -function gdx_data_read_raw_start( - gdx_ptr::Ptr{Cvoid}, - start::Int, - n_rec::Ref{Cint}, -) - return ccall( - (@cpfx(:gdxdatareadrawstart), libgdx), - Cint, - (Ptr{Cvoid}, Cint, Ref{Cint}), - gdx_ptr, - start, - n_rec, - ) -end - -function gdx_data_read_raw_start(gdx::GDXHandle, start::Int) - rc = gdx_data_read_raw_start(gdx.cptr[], start, gdx.cival) - if rc != 1 - throw(GDXException("Can't start GDX read", 0)) - end - return Int(gdx.cival[]) -end - -function gdx_data_read_raw( - gdx_ptr::Ptr{Cvoid}, - idx::Vector{Cint}, - vals::Vector{Cdouble}, - dim::Ref{Cint}, -) - return ccall( - (@cpfx(:gdxdatareadraw), libgdx), - Cint, - (Ptr{Cvoid}, Ptr{Cint}, Ptr{Cdouble}, Ref{Cint}), - gdx_ptr, - idx, - vals, - dim, - ) -end - -function gdx_data_read_raw( - gdx::GDXHandle, - idx::Vector{Int}, - vals::Vector{Float64}, -) - @assert(length(idx) <= length(gdx.civec)) - @assert(length(vals) <= length(gdx.crvec)) - - rc = gdx_data_read_raw(gdx.cptr[], gdx.civec, gdx.crvec, gdx.cival) - if rc != 1 - throw(GDXException("Reading raw data failed", 0)) - end - - for i in 1:length(idx) - idx[i] = gdx.civec[i] - end - for i in 1:length(vals) - vals[i] = gdx.crvec[i] - end - return -end - -# ============================================================================= -# Reading data (string interface) -# ============================================================================= - -function gdx_data_read_str_start( - gdx_ptr::Ptr{Cvoid}, - start::Int, - n_err::Ref{Cint}, -) - return ccall( - (@cpfx(:gdxdatareadstrstart), libgdx), - Cint, - (Ptr{Cvoid}, Cint, Ref{Cint}), - gdx_ptr, - start, - n_err, - ) -end - -function gdx_data_read_str_start(gdx::GDXHandle, start::Int) - rc = gdx_data_read_str_start(gdx.cptr[], start, gdx.cival) - if rc != 1 - throw(GDXException("Can't start GDX read", 0)) - end - return Int(gdx.cival[]) -end - -function gdx_data_read_str( - gdx_ptr::Ptr{Cvoid}, - keystr::Vector{Ptr{UInt8}}, - vals::Vector{Cdouble}, - dim_first::Ref{Cint}, -) - return ccall( - (@cpfx(:gdxdatareadstr), libgdx), - Cint, - (Ptr{Cvoid}, Ptr{Ptr{UInt8}}, Ptr{Cdouble}, Ref{Cint}), - gdx_ptr, - keystr, - vals, - dim_first, - ) -end - -function gdx_data_read_str( - gdx::GDXHandle, - keystr::Vector{String}, - vals::Vector{Float64}, -) - @assert(length(keystr) <= length(gdx.cbuf)) - @assert(length(vals) <= length(gdx.crvec)) - - for b in gdx.buf - b[1] = UInt8('\0') - end - - rc = gdx_data_read_str(gdx.cptr[], gdx.cbuf, gdx.crvec, gdx.cival) - if rc != 1 - throw(GDXException("Failed to read GDX record", 0)) - end - - for i in 1:length(keystr) - keystr[i] = unsafe_string(gdx.cbuf[i]) - end - for i in 1:length(vals) - vals[i] = gdx.crvec[i] - end - return -end - -function gdx_data_read_done(gdx_ptr::Ptr{Cvoid}) - return ccall( - (@cpfx(:gdxdatareaddone), libgdx), - Cint, - (Ptr{Cvoid},), - gdx_ptr, - ) -end - -function gdx_data_read_done(gdx::GDXHandle) - gdx_data_read_done(gdx.cptr[]) - return -end - -# ============================================================================= -# Writing data -# ============================================================================= - -function gdx_data_write_str_start( - gdx_ptr::Ptr{Cvoid}, - name::String, - text::String, - dim::Int, - typ::Int, - user_info::Int, -) - return ccall( - (@cpfx(:gdxdatawritestrstart), libgdx), - Cint, - (Ptr{Cvoid}, Cstring, Cstring, Cint, Cint, Cint), - gdx_ptr, - name, - text, - dim, - typ, - user_info, - ) -end - -function gdx_data_write_str_start( - gdx::GDXHandle, - name::String, - text::String, - dim::Int, - typ::Int, - user_info::Int = 0, -) - rc = gdx_data_write_str_start(gdx.cptr[], name, text, dim, typ, user_info) - if rc != 1 - throw(GDXException("Can't start writing symbol '$name'", 0)) - end - return -end - -function gdx_data_write_str( - gdx_ptr::Ptr{Cvoid}, - keys::Vector{String}, - vals::Vector{Float64}, -) - return ccall( - (@cpfx(:gdxdatawritestr), libgdx), - Cint, - (Ptr{Cvoid}, Ptr{Cstring}, Ptr{Cdouble}), - gdx_ptr, - keys, - vals, - ) -end - -function gdx_data_write_str( - gdx::GDXHandle, - keys::Vector{String}, - vals::Vector{Float64}, -) - rc = gdx_data_write_str(gdx.cptr[], keys, vals) - if rc != 1 - throw(GDXException("Can't write record", 0)) - end - return -end - -function gdx_data_write_done(gdx_ptr::Ptr{Cvoid}) - return ccall( - (@cpfx(:gdxdatawritedone), libgdx), - Cint, - (Ptr{Cvoid},), - gdx_ptr, - ) -end - -function gdx_data_write_done(gdx::GDXHandle) - rc = gdx_data_write_done(gdx.cptr[]) - if rc != 1 - throw(GDXException("Can't finish writing symbol", 0)) - end - return -end diff --git a/src/libgdx.jl b/src/libgdx.jl new file mode 100644 index 0000000..f8c1079 --- /dev/null +++ b/src/libgdx.jl @@ -0,0 +1,254 @@ +# Copyright (c) 2026 Martin Kirk Bonde, James Daniel Foster and contributors +# Copyright (c) 2020-2023 GAMS Software GmbH +# +# Use of this source code is governed by an MIT-style license that can be found +# in the LICENSE.md file or at https://opensource.org/licenses/MIT. + +# ============================================================================= +# Constants +# ============================================================================= + +const GMS_MAX_INDEX_DIM = 20 +const GMS_SSSIZE = 256 +const GMS_VAL_MAX = 5 + +# GAMS value position in GDX data +const GAMS_VALUE_LEVEL = 1 +const GAMS_VALUE_MARGINAL = 2 +const GAMS_VALUE_LOWER = 3 +const GAMS_VALUE_UPPER = 4 +const GAMS_VALUE_SCALE = 5 + +# GAMS data types +const GMS_DT_SET = 0 +const GMS_DT_PAR = 1 +const GMS_DT_VAR = 2 +const GMS_DT_EQU = 3 +const GMS_DT_ALIAS = 4 +const GMS_DT_MAX = 5 + +# GAMS special values +const GAMS_SV_UNDEF = 1.0e300 # undefined +const GAMS_SV_NA = 2.0e300 # not available / applicable +const GAMS_SV_PINF = 3.0e300 # plus infinity +const GAMS_SV_MINF = 4.0e300 # minus infinity +const GAMS_SV_EPS = 5.0e300 # epsilon +const GAMS_SV_ACR = 10.0e300 # potential / real acronym +const GAMS_SV_NAINT = 2100000000 # not available / applicable for integers + +# ============================================================================= +# GDX Handle +# ============================================================================= + +mutable struct GDXHandle + cptr::Ptr{Cvoid} + + function GDXHandle() + cptr = Ref{Ptr{Cvoid}}(C_NULL) + @ccall libgdx.xcreate(cptr::Ptr{Ptr{Cvoid}})::Cvoid + if cptr[] == C_NULL + throw(GDXException("Can't create GAMS GDX object", 0)) + end + gdx = new(cptr[]) + finalizer(gdx) do gdx_i + @ccall libgdx.xfree(Ref(gdx_i.cptr)::Ptr{Ptr{Cvoid}})::Cvoid + return + end + return gdx + end +end + +Base.cconvert(::Type{Ptr{Cvoid}}, gdx::GDXHandle) = gdx + +Base.unsafe_convert(::Type{Ptr{Cvoid}}, gdx::GDXHandle) = gdx.cptr + +struct GDXException <: Exception + msg::String + n_err::Int +end + +function Base.showerror(io::IO, e::GDXException) + return print(io, "GDX failed: $(e.msg) ($(e.n_err))") +end + +function c__gdxopenread(gdx_ptr, file, n_err) + return @ccall libgdx.c__gdxopenread( + gdx_ptr::Ptr{Cvoid}, + file::Cstring, + n_err::Ptr{Cint}, + )::Cint +end + +function c__gdxopenwrite(gdx_ptr, file, producer, n_err) + return @ccall libgdx.c__gdxopenwrite( + gdx_ptr::Ptr{Cvoid}, + file::Cstring, + producer::Cstring, + n_err::Ptr{Cint}, + )::Cint +end + +c__gdxclose(gdx) = @ccall libgdx.c__gdxclose(gdx::Ptr{Cvoid})::Cint + +function c__gdxsysteminfo(gdx_ptr, sym_count, uel_count) + return @ccall libgdx.c__gdxsysteminfo( + gdx_ptr::Ptr{Cvoid}, + sym_count::Ptr{Cint}, + uel_count::Ptr{Cint}, + )::Cint +end + +function c__gdxsymbolinfo(gdx_ptr, sym_id, name, dim, type) + return @ccall libgdx.c__gdxsymbolinfo( + gdx_ptr::Ptr{Cvoid}, + sym_id::Cint, + name::Ptr{UInt8}, + dim::Ptr{Cint}, + type::Ptr{Cint}, + )::Cint +end + +function c__gdxsymbolinfox(gdx_ptr, sym_id, count, user_info, text) + return @ccall libgdx.c__gdxsymbolinfox( + gdx_ptr::Ptr{Cvoid}, + sym_id::Cint, + count::Ptr{Cint}, + user_info::Ptr{Cint}, + text::Ptr{UInt8}, + )::Cint +end + +function c__gdxfindsymbol(gdx_ptr, name, sym_nr) + return @ccall libgdx.c__gdxfindsymbol( + gdx_ptr::Ptr{Cvoid}, + name::Cstring, + sym_nr::Ptr{Cint}, + )::Cint +end + +function c__gdxsymbolgetdomainx(gdx_ptr, sym_nr, domains) + return @ccall libgdx.c__gdxsymbolgetdomainx( + gdx_ptr::Ptr{Cvoid}, + sym_nr::Cint, + domains::Ptr{Ptr{UInt8}}, + )::Cint +end + +function c__gdxsymbolsetdomainx(gdx_ptr, sym_nr, domain_ids) + return @ccall libgdx.c__gdxsymbolsetdomainx( + gdx_ptr::Ptr{Cvoid}, + sym_nr::Cint, + domain_ids::Ptr{Cstring}, + )::Cint +end + +function c__gdxaddalias(gdx_ptr, id1, id2) + return @ccall libgdx.c__gdxaddalias( + gdx_ptr::Ptr{Cvoid}, + id1::Cstring, + id2::Cstring, + )::Cint +end + +function c__gdxgetelemtext(gdx_ptr, text_nr, text, node) + return @ccall libgdx.c__gdxgetelemtext( + gdx_ptr::Ptr{Cvoid}, + text_nr::Cint, + text::Ptr{UInt8}, + node::Ptr{Cint}, + )::Cint +end + +function c__gdxaddsettext(gdx_ptr, text, text_nr) + return @ccall libgdx.c__gdxaddsettext( + gdx_ptr::Ptr{Cvoid}, + text::Cstring, + text_nr::Ptr{Cint}, + )::Cint +end + +function c__gdxumuelget(gdx_ptr, uel_nr, uel, uel_map) + return @ccall libgdx.c__gdxumuelget( + gdx_ptr::Ptr{Cvoid}, + uel_nr::Cint, + uel::Ptr{UInt8}, + uel_map::Ptr{Cint}, + )::Cint +end + +function c__gdxuelregisterstrstart(gdx_pt) + return @ccall libgdx.c__gdxuelregisterstrstart(gdx_ptr::Ptr{Cvoid})::Cint +end + +function c__gdxuelregisterstr(gdx_ptr, uel, uel_nr) + return @ccall libgdx.c__gdxuelregisterstr( + gdx_ptr::Ptr{Cvoid}, + uel::Cstring, + uel_nr::Ptr{Cint}, + )::Cint +end + +function c__gdxuelregisterdone(gdx_ptr) + return @ccall libgdx.c__gdxuelregisterdone(gdx_ptr::Ptr{Cvoid})::Cint +end + +function c__gdxdatareadrawstart(gdx_ptr, start, n_rec) + return @ccall libgdx.c__gdxdatareadrawstart( + gdx_ptr::Ptr{Cvoid}, + start::Cint, + n_rec::Ptr{Cint}, + )::Cint +end + +function c__gdxdatareadraw(gdx_ptr, idx, vals, dim) + return @ccall libgdx.c__gdxdatareadraw( + gdx_ptr::Ptr{Cvoid}, + idx::Ptr{Cint}, + vals::Ptr{Cdouble}, + dim::Ptr{Cint}, + )::Cint +end + +function c__gdxdatareadstrstart(gdx_ptr, start, n_err) + return @ccall libgdx.c__gdxdatareadstrstart( + gdx_ptr::Ptr{Cvoid}, + start::Cint, + n_err::Ptr{Cint}, + )::Cint +end + +function c__gdxdatareadstr(gdx_ptr, keystr, vals, dim_first) + return @ccall libgdx.c__gdxdatareadstr( + gdx_ptr::Ptr{Cvoid}, + keystr::Ptr{Ptr{UInt8}}, + vals::Ptr{Cdouble}, + dim_first::Ptr{Cint}, + )::Cint +end + +function c__gdxdatareaddone(gdx_ptr) + return @ccall libgdx.c__gdxdatareaddone(gdx_ptr::Ptr{Cvoid})::Cint +end + +function c__gdxdatawritestrstart(gdx_ptr, name, text, dim, typ, user_info) + return @ccall libgdx.c__gdxdatawritestrstart( + gdx_ptr::Ptr{Cvoid}, + name::Cstring, + text::Cstring, + dim::Cint, + typ::Cint, + user_info::Cint, + )::Cint +end + +function c__gdxdatawritestr(gdx_ptr, keys, vals) + return @ccall libgdx.c__gdxdatawritestr( + gdx_ptr::Ptr{Cvoid}, + keys::Ptr{Cstring}, + vals::Ptr{Cdouble}, + )::Cint +end + +function c__gdxdatawritedone(gdx) + return @ccall libgdx.c__gdxdatawritedone(gdx::Ptr{Cvoid})::Cint +end