Skip to content

Commit

Permalink
Add all files
Browse files Browse the repository at this point in the history
  • Loading branch information
singularitti committed Sep 5, 2022
1 parent 3e2a111 commit cac4b90
Show file tree
Hide file tree
Showing 5 changed files with 315 additions and 2 deletions.
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
[![Stable](https://img.shields.io/badge/docs-stable-blue.svg)](https://MineralsCloud.github.io/CifAPI.jl/stable/)
[![Dev](https://img.shields.io/badge/docs-dev-blue.svg)](https://MineralsCloud.github.io/CifAPI.jl/dev/)
[![Build Status](https://github.com/MineralsCloud/CifAPI.jl/actions/workflows/CI.yml/badge.svg?branch=main)](https://github.com/MineralsCloud/CifAPI.jl/actions/workflows/CI.yml?query=branch%3Amain)
[![Build Status](https://github.com/MineralsCloud/CifAPI.jl/badges/main/pipeline.svg)](https://github.com/MineralsCloud/CifAPI.jl/pipelines)
[![Coverage](https://github.com/MineralsCloud/CifAPI.jl/badges/main/coverage.svg)](https://github.com/MineralsCloud/CifAPI.jl/commits/main)
[![Build Status](https://ci.appveyor.com/api/projects/status/github/MineralsCloud/CifAPI.jl?svg=true)](https://ci.appveyor.com/project/MineralsCloud/CifAPI-jl)
[![Build Status](https://api.cirrus-ci.com/github/MineralsCloud/CifAPI.jl.svg)](https://cirrus-ci.com/github/MineralsCloud/CifAPI.jl)
[![Coverage](https://codecov.io/gh/MineralsCloud/CifAPI.jl/branch/main/graph/badge.svg)](https://codecov.io/gh/MineralsCloud/CifAPI.jl)
Expand Down
3 changes: 3 additions & 0 deletions src/CifAPI.jl
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
136 changes: 136 additions & 0 deletions src/api.jl
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
15 changes: 15 additions & 0 deletions src/ctypes.jl
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
161 changes: 161 additions & 0 deletions src/handlers.jl
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


0 comments on commit cac4b90

Please sign in to comment.