-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
3e2a111
commit cac4b90
Showing
5 changed files
with
315 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,9 @@ | ||
module CifAPI | ||
|
||
include("wrappers.jl") | ||
include("ctypes.jl") | ||
include("errors.jl") | ||
include("handlers.jl") | ||
include("api.jl") | ||
|
||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
abstract type CifContainer <: AbstractDict{String} end | ||
abstract type NestedCifContainer <: CifContainer end | ||
mutable struct Block <: CifContainer | ||
loop_names::Vector{Vector{String}} #one loop is a list of datanames | ||
data_values::Dict{String,<:Vector} | ||
original_file::AbstractPath | ||
end | ||
mutable struct CifBlock{V} <: NestedCifContainer{V} | ||
save_frames::Dict{String,Block{V}} | ||
loop_names::Vector{Vector{String}} #one loop is a list of datanames | ||
data_values::Dict{String,Vector{V}} | ||
original_file::AbstractPath | ||
end | ||
|
||
get_data_values(b::Block) = b.data_values | ||
get_data_values(b::CifBlock) = b.data_values | ||
|
||
abstract type CifCollection <: AbstractDict{String} end | ||
struct Cif{T<:CifContainer} <: CifCollection | ||
header_comments::String | ||
contents::Dict{String,T} | ||
end | ||
|
||
mutable struct Uchar | ||
string::Ptr{UInt16} | ||
end | ||
|
||
function get_block_code(b) | ||
s = Uchar(0) | ||
val = cif_container_get_code(b, Ref(s)) | ||
checkerror(val) | ||
return make_jl_string(s) | ||
end | ||
|
||
function get_syntactical_type(t::cif_value_tp_ptr) | ||
val_type = cif_value_kind(t.handle) | ||
if val_type == 0 || val_type == 1 | ||
return typeof(t) | ||
elseif val_type == 2 | ||
cif_list | ||
elseif val_type == 3 | ||
cif_table | ||
elseif val_type == 4 | ||
return Nothing | ||
elseif val_type == 5 | ||
return Missing | ||
end | ||
end | ||
|
||
function cif_list(cv::cif_value_tp_ptr) | ||
cif_type = cif_value_kind(cv.handle) | ||
if cif_type != 2 | ||
error("$val is not a cif list value") | ||
end | ||
elctptr = Ref{Cint}(0) | ||
val = cif_value_get_element_count(cv.handle, elctptr) | ||
if val != 0 | ||
error(ERROR_CODES[val]) | ||
end | ||
elct = elctptr[] | ||
so_far = Vector() | ||
for el_num in 1:elct | ||
new_element = cif_value_tp_ptr(0) | ||
val = cif_value_get_element_at(cv.handle, el_num - 1, Ref(new_element)) | ||
if val != 0 | ||
error(ERROR_CODES[val]) | ||
end | ||
t = get_syntactical_type(new_element) | ||
if t == cif_value_tp_ptr | ||
push!(so_far, String(new_element)) | ||
elseif t == cif_list | ||
push!(so_far, cif_list(new_element)) | ||
elseif t == cif_table | ||
push!(so_far, cif_table(new_element)) | ||
else | ||
push!(so_far, t()) | ||
end | ||
end | ||
return so_far | ||
end | ||
|
||
function cif_table(cv::cif_value_tp_ptr) | ||
cif_type = cif_value_kind(cv.handle) | ||
if cif_type != 3 | ||
error("$val is not a cif table value") | ||
end | ||
so_far = Dict{String,Any}() | ||
for el in keys(cv) | ||
new_val = cv[el] | ||
t = get_syntactical_type(new_val) | ||
if t == cif_value_tp_ptr | ||
so_far[el] = String(new_val) | ||
elseif t == cif_list | ||
so_far[el] = cif_list(new_val) | ||
elseif t == cif_table | ||
so_far[el] = cif_table(new_val) | ||
else | ||
so_far[el] = t() | ||
end | ||
end | ||
return so_far | ||
end | ||
|
||
function Base.String(t::cif_value_tp) | ||
#Get the textual representation | ||
s = Uchar(0) | ||
val = cif_value_get_text(t.handle, Ref(s)) | ||
checkerror(val) | ||
return make_jl_string(s) | ||
end | ||
|
||
function destroy!(cif) | ||
val = cif_destroy(cif.data) | ||
if val != 0 | ||
error(ERROR_CODES[val]) | ||
end | ||
return | ||
end | ||
|
||
function make_jl_string(s::Uchar) | ||
n = get_c_length(s.string, -1) # short for testing | ||
icu_string = unsafe_wrap(Array{UInt16,1}, s.string, n, own=false) | ||
return transcode(String, icu_string) | ||
end | ||
|
||
function get_c_length(s::Ptr, max=-1) | ||
# Now loop over the values we have | ||
n = 1 | ||
b = unsafe_load(s, n) | ||
while b != 0 && (max == -1 || (max != -1 && n < max)) | ||
n = n + 1 | ||
b = unsafe_load(s, n) | ||
end | ||
n = n - 1 | ||
return n | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
mutable struct cif_tp_ptr | ||
handle::Ptr{cif_tp} | ||
end | ||
|
||
mutable struct cif_container_tp_ptr | ||
handle::Ptr{cif_container_tp} # *cif_block_tp | ||
end | ||
|
||
mutable struct cif_loop_tp_ptr | ||
handle::Ptr{cif_loop_tp} | ||
end | ||
|
||
mutable struct cif_value_tp_ptr | ||
handle::Ptr{cif_value_tp} | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
mutable struct cif_builder_context | ||
actual_cif::Dict{String,<:CifContainer} | ||
block_stack::Array{<:CifContainer} | ||
filename::AbstractPath | ||
verbose::Bool | ||
end | ||
|
||
handle_cif_start(a, b)::Cint = 0 | ||
|
||
handle_cif_end(a, b)::Cint = 0 | ||
|
||
handle_block_start(a::cif_container_tp_ptr, b)::Cint = begin | ||
blockname = get_block_code(a) | ||
if b.verbose | ||
println("New blockname $(blockname)") | ||
end | ||
newblock = Block() | ||
newblock.original_file = b.filename | ||
push!(b.block_stack, newblock) | ||
return 0 | ||
end | ||
|
||
function handle_block_end(a::cif_container_tp_ptr, b::cif_builder_context)::Cint | ||
# Remove missing values | ||
all_names = keys(get_data_values(b.block_stack[end])) | ||
# Length > 1 dealt with already | ||
all_names = filter(x -> length(get_data_values(b.block_stack[end])[x]) == 1, all_names) | ||
# Remove any whose first and only entry is 'missing' | ||
drop_names = filter(x -> ismissing(get_data_values(b.block_stack[end])[x][1]), all_names) | ||
# println("Removing $drop_names from block") | ||
[delete!(b.block_stack[end], x) for x in drop_names] | ||
# and finish off | ||
blockname = get_block_code(a) | ||
if b.verbose | ||
println("Block is finished: $blockname") | ||
end | ||
b.actual_cif[blockname] = pop!(b.block_stack) | ||
return 0 | ||
end | ||
|
||
function handle_frame_start(a::cif_container_tp_ptr, b)::Cint | ||
blockname = get_block_code(a) | ||
if b.verbose | ||
println("Frame started: $blockname") | ||
end | ||
newblock = Block() | ||
newblock.original_file = b.filename | ||
b.block_stack[end] = CifBlock(b.block_stack[end]) | ||
push!(b.block_stack, newblock) | ||
return 0 | ||
end | ||
|
||
function handle_frame_end(a, b)::Cint | ||
# Remove missing values | ||
all_names = keys(get_data_values(b.block_stack[end])) | ||
# Length > 1 dealt with already | ||
all_names = filter(x -> length(get_data_values(b.block_stack[end])[x]) == 1, all_names) | ||
# Remove any whose first and only entry is 'missing' | ||
drop_names = filter(x -> ismissing(get_data_values(b.block_stack[end])[x][1]), all_names) | ||
[delete!(b.block_stack[end], x) for x in drop_names] | ||
final_frame = pop!(b.block_stack) | ||
blockname = get_block_code(a) | ||
b.block_stack[end].save_frames[blockname] = final_frame | ||
if b.verbose | ||
println("Frame $blockname is finished") | ||
end | ||
return 0 | ||
end | ||
|
||
handle_loop_start(a, b)::Cint = 0 | ||
|
||
function handle_loop_end(a::Ptr{cif_loop_tp}, b)::Cint | ||
if b.verbose | ||
println("Loop header $(keys(a))") | ||
end | ||
# ignore missing values | ||
loop_names = lowercase.(keys(a)) | ||
not_missing = filter(x -> any(y -> !ismissing(y), get_data_values(b.block_stack[end])[x]), loop_names) | ||
create_loop!(b.block_stack[end], not_missing) | ||
# and remove the data | ||
missing_ones = setdiff(Set(loop_names), not_missing) | ||
#println("Removing $missing_ones from loop") | ||
[delete!(b.block_stack[end], x) for x in missing_ones] | ||
return 0 | ||
end | ||
|
||
handle_packet_start(a, b)::Cint = 0 | ||
|
||
handle_packet_end(a, b)::Cint = 0 | ||
|
||
function handle_item(a::Ptr{UInt16}, b::cif_value_tp_ptr, c)::Cint | ||
a_as_uchar = Uchar(a) | ||
val = "" | ||
keyname = make_jl_string(a_as_uchar) | ||
if c.verbose | ||
println("Processing name $keyname") | ||
end | ||
current_block = c.block_stack[end] | ||
syntax_type = get_syntactical_type(b) | ||
if syntax_type == cif_value_tp_ptr | ||
val = String(b) | ||
elseif syntax_type == cif_list | ||
val = cif_list(b) | ||
elseif syntax_type == cif_table | ||
val = cif_table(b) | ||
elseif syntax_type == Nothing | ||
val = nothing | ||
elseif syntax_type == Missing | ||
val = missing | ||
else | ||
error("") | ||
end | ||
if c.verbose | ||
if !ismissing(val) && val !== nothing | ||
println("With value $val") | ||
elseif ismissing(val) | ||
println("With value ?") | ||
else | ||
println("With value .") | ||
end | ||
end | ||
lc_keyname = lowercase(keyname) | ||
if !(lc_keyname in keys(get_data_values(current_block))) | ||
get_data_values(current_block)[lc_keyname] = [val] | ||
else | ||
push!(get_data_values(current_block)[lc_keyname], val) | ||
end | ||
return 0 | ||
end | ||
|
||
default_options(path; verbose=false) = begin | ||
handle_cif_start_c = @cfunction(handle_cif_start, Cint, (cif_tp_ptr, Ref{cif_builder_context})) | ||
handle_cif_end_c = @cfunction(handle_cif_end, Cint, (cif_tp_ptr, Ref{cif_builder_context})) | ||
handle_block_start_c = @cfunction(handle_block_start, Cint, (cif_container_tp_ptr, Ref{cif_builder_context})) | ||
handle_block_end_c = @cfunction(handle_block_end, Cint, (cif_container_tp_ptr, Ref{cif_builder_context})) | ||
handle_frame_start_c = @cfunction(handle_frame_start, Cint, (cif_container_tp_ptr, Ref{cif_builder_context})) | ||
handle_frame_end_c = @cfunction(handle_frame_end, Cint, (cif_container_tp_ptr, Ref{cif_builder_context})) | ||
handle_loop_start_c = @cfunction(handle_loop_start, Cint, (cif_loop_tp_ptr, Ref{cif_builder_context})) | ||
handle_loop_end_c = @cfunction(handle_loop_end, Cint, (Ptr{cif_loop_tp}, Ref{cif_builder_context})) | ||
handle_packet_start_c = @cfunction(handle_packet_start, Cint, (Ptr{cif_packet_tp}, Ref{cif_builder_context})) | ||
handle_packet_end_c = @cfunction(handle_packet_end, Cint, (Ptr{cif_packet_tp}, Ref{cif_builder_context})) | ||
handle_item_c = @cfunction(handle_item, Cint, (Ptr{UInt16}, cif_value_tp_ptr, Ref{cif_builder_context})) | ||
handlers = cif_handler_tp( | ||
handle_cif_start_c, | ||
handle_cif_end_c, | ||
handle_block_start_c, | ||
handle_block_end_c, | ||
handle_frame_start_c, | ||
handle_frame_end_c, | ||
handle_loop_start_c, | ||
handle_loop_end_c, | ||
handle_packet_start_c, | ||
handle_packet_end_c, | ||
handle_item_c, | ||
) | ||
context = cif_builder_context(Dict(), CifContainer[], path, verbose) | ||
p_opts = cif_parse_opts_s(0, C_NULL, 0, 1, 1, 1, C_NULL, C_NULL, Ref(handlers), C_NULL, C_NULL, C_NULL, C_NULL, context) | ||
return p_opts | ||
end | ||
|
||
|