From 9e7adcde65f5cdb9972249dbdf11a2f3d90efacf Mon Sep 17 00:00:00 2001 From: Hongyang Zhou Date: Tue, 11 Feb 2020 14:23:50 -0500 Subject: [PATCH 01/38] Update legacy functions. --- src/IDLCall.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/IDLCall.jl b/src/IDLCall.jl index 1e19302..227200d 100644 --- a/src/IDLCall.jl +++ b/src/IDLCall.jl @@ -4,7 +4,7 @@ module IDLCall using Compat # Find IDL library directory if on Linux -if is_unix() +if Sys.isunix() idl_dir = dirname(chomp(readstring(`which idl`))) idl_lib_dir = chomp(readstring(`bash -c "ls -d $(idl_dir)/bin.*"`)) const idlcall = idl_lib_dir*"/libidl" @@ -16,11 +16,11 @@ end export init, get_var, put_var, execute, @get_var, @put_var, idl_repl -jl_idl_type = get(ENV, "JL_IDL_TYPE", is_windows() ? "CALLABLE" : "RPC") +jl_idl_type = get(ENV, "JL_IDL_TYPE", Sys.iswindows() ? "CALLABLE" : "RPC") jl_idl_type == "RPC" ? include("IDLRPC.jl") : jl_idl_type == "CALLABLE" ? include("IDLCallable.jl") : -is_windows() ? error("JL_IDL_TYPE must be CALLABLE on windows") : +Sys.iswindows() ? error("JL_IDL_TYPE must be CALLABLE on windows") : error("JL_IDL_TYPE must be RPC or CALLABLE") include("IDLREPL.jl") From 4a5f45642a56dbce996e9e1a008cfb4f83e4c4f7 Mon Sep 17 00:00:00 2001 From: Hongyang Zhou Date: Tue, 11 Feb 2020 15:03:11 -0500 Subject: [PATCH 02/38] Fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 346d9cd..6150657 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ tested on Windows so please file an issue if you use Windows and want to help ma IDL can be called using either the `RPC` or `Callable` interface. On windows only the `Callable` interface is available. You can set an environmental variable `JL_IDL_TYPE` to `RPC` or `CALLABLE` to force the use of that interface. -Alternatively you can set `ENV["JL_IDL_TYPE]` within julia before starting IDLCall. +Alternatively you can set `ENV["JL_IDL_TYPE"]` within julia before starting IDLCall. Note that by default IDLCall uses the `RPC` interface on Mac and Linux and `Callable` on Windows. The biggest difference between these is that: From a7a30573117736ef2a63465d6bee0d946920bfb2 Mon Sep 17 00:00:00 2001 From: hyzhou Date: Tue, 11 Feb 2020 15:36:35 -0500 Subject: [PATCH 03/38] First modification, not working yet. --- src/IDLCall.jl | 21 ++-- src/IDLCallable.jl | 138 ++++++++++----------- src/IDLREPL.jl | 122 +++++++++---------- src/IDLRPC.jl | 287 ++++++++++++++++++++++---------------------- src/common-funcs.jl | 8 +- src/idl_types.jl | 36 +++--- 6 files changed, 308 insertions(+), 304 deletions(-) diff --git a/src/IDLCall.jl b/src/IDLCall.jl index 227200d..b057c34 100644 --- a/src/IDLCall.jl +++ b/src/IDLCall.jl @@ -1,17 +1,24 @@ module IDLCall -using Compat +#using Compat # Find IDL library directory if on Linux if Sys.isunix() - idl_dir = dirname(chomp(readstring(`which idl`))) - idl_lib_dir = chomp(readstring(`bash -c "ls -d $(idl_dir)/bin.*"`)) - const idlcall = idl_lib_dir*"/libidl" - const idlrpc = idl_lib_dir*"/libidl_rpc" + #IDL_DIR = dirname(chomp(readstring(`which idl`))) + #idl_lib_dir = chomp(readstring(`bash -c "ls -d $(IDL_DIR)/bin.*"`)) + #IDL_DIR = dirname(chomp(read(`which idl`,String))) + IDL_DIR = "/Applications/exelis/idl85/" + #IDL_PATH='/Users/hyzhou/Idl:${IDL_DIR}/lib:${IDL_DIR}/lib/utilities' + #IDL_STARTUP=idlrc + idl_lib_dir = chomp(read(`bash -c "ls -d $(IDL_DIR)/bin.*"`,String)) + #const idlcall = idl_lib_dir*"/libidl" + #const idlrpc = idl_lib_dir*"/libidl_rpc" + const idlcall = joinpath(idl_lib_dir,"lib") + const idlrpc = joinpath(idl_lib_dir,"libidl_rpc") else - const idlcall = "libidl" - const idlrpc = "libidl_rpc" + const idlcall = "libidl" + const idlrpc = "libidl_rpc" end export init, get_var, put_var, execute, @get_var, @put_var, idl_repl diff --git a/src/IDLCallable.jl b/src/IDLCallable.jl index 682c3b4..9307b23 100644 --- a/src/IDLCallable.jl +++ b/src/IDLCallable.jl @@ -4,19 +4,19 @@ include("common-funcs.jl") include("common-macros.jl") if is_apple() - cd(idl_lib_dir) do - Libdl.dlopen("libidl") - end + cd(idl_lib_dir) do + Libdl.dlopen("libidl") + end end function init() - ecode = ccall((:IDL_Init, idlcall), Cint, (Cint, Ptr{Cint}, Ptr{Ptr{UInt8}}), - 0, C_NULL, C_NULL) - if ecode == 0 - error("IDL.init: IDL init failed") - end - global output_cb - ccall((:IDL_ToutPush, idlcall), Void, (Ptr{Void},), output_cb) + ecode = ccall((:IDL_Init, idlcall), Cint, (Cint, Ptr{Cint}, Ptr{Ptr{UInt8}}), + 0, C_NULL, C_NULL) + if ecode == 0 + error("IDL.init: IDL init failed") + end + global output_cb + ccall((:IDL_ToutPush, idlcall), Void, (Ptr{Void},), output_cb) end # function execute{T<:AbstractString}(strarr::Array{T,1}) @@ -31,22 +31,22 @@ end # end function execute_converted(str::AbstractString) - # does no conversion of interpolated vars, continuation chars, or newlines - ecode = ccall((:IDL_ExecuteStr, idlcall), Cint, (Ptr{UInt8},), str) - if ecode != 0 - # since error get printed by IDL, we just reset error state - ecode = ccall((:IDL_ExecuteStr, idlcall), Cint, (Ptr{UInt8},), "message, /RESET") - end - return true + # does no conversion of interpolated vars, continuation chars, or newlines + ecode = ccall((:IDL_ExecuteStr, idlcall), Cint, (Ptr{UInt8},), str) + if ecode != 0 + # since error get printed by IDL, we just reset error state + ecode = ccall((:IDL_ExecuteStr, idlcall), Cint, (Ptr{UInt8},), "message, /RESET") + end + return true end function get_output(flags::Cint, buf::Ptr{UInt8}, n::Cint) - line = unsafe_string(buf, n) - stderr = (flags & IDL_TOUT_F_STDERR) != 0 - newline = (flags & IDL_TOUT_F_NLPOST) != 0 - if newline line = line*"\n" end - print(line) - return + line = unsafe_string(buf, n) + stderr = (flags & IDL_TOUT_F_STDERR) != 0 + newline = (flags & IDL_TOUT_F_NLPOST) != 0 + if newline line = line*"\n" end + print(line) + return end output_cb = cfunction(get_output, Void, (Cint, Ptr{UInt8},Cint)) @@ -61,70 +61,70 @@ output_cb = cfunction(get_output, Void, (Cint, Ptr{UInt8},Cint)) const var_refs = Dict{Ptr{UInt8}, Any}() function done_with_var(p::Ptr{UInt8}) - if !haskey(var_refs, p) - error("IDL.done_with_var: ptr not found: "*string(p)) - end - delete!(var_refs, p) - return + if !haskey(var_refs, p) + error("IDL.done_with_var: ptr not found: "*string(p)) + end + delete!(var_refs, p) + return end free_cb = cfunction(done_with_var, Void, (Ptr{UInt8},)) function put_var{T,N}(arr::Array{T,N}, name::AbstractString) - if !isbits(eltype(arr)) || (idl_type(arr) < 0) - error("IDL.put_var: only works with some vars containing bits types") - end - dim = zeros(Int, IDL_MAX_ARRAY_DIM) - dim[1:N] = [size(arr)...] - vptr = ccall((:IDL_ImportNamedArray, idlcall), Ptr{IDL_Variable}, - (Ptr{UInt8}, Cint, IDL_ARRAY_DIM, Cint, Ptr{UInt8}, IDL_ARRAY_FREE_CB , Ptr{Void}), - name, N, dim, idl_type(arr), pointer(arr), free_cb, C_NULL) - if vptr == C_NULL - error("IDL.put_var: failed") - end - var_refs[pointer(arr)] = (name, vptr, arr) - return + if !isbits(eltype(arr)) || (idl_type(arr) < 0) + error("IDL.put_var: only works with some vars containing bits types") + end + dim = zeros(Int, IDL_MAX_ARRAY_DIM) + dim[1:N] = [size(arr)...] + vptr = ccall((:IDL_ImportNamedArray, idlcall), Ptr{IDL_Variable}, + (Ptr{UInt8}, Cint, IDL_ARRAY_DIM, Cint, Ptr{UInt8}, IDL_ARRAY_FREE_CB , Ptr{Void}), + name, N, dim, idl_type(arr), pointer(arr), free_cb, C_NULL) + if vptr == C_NULL + error("IDL.put_var: failed") + end + var_refs[pointer(arr)] = (name, vptr, arr) + return end function put_var(x, name::AbstractString) - # Sort of a HACK: import as one-element array and then truncate to scalar - # IDL_ImportArray(int n_dim, IDL_MEMINT dim[], int type, - # UCHAR *data, IDL_ARRAY_FREE_CB free_cb, void *s) - if !isbits(x) || (idl_type(x) < 0) - error("IDL.put_var: only works with some vars containing bits types") - end - dim = zeros(Int, IDL_MAX_ARRAY_DIM) - dim[1] = 1 - ccall((:IDL_ImportNamedArray, idlcall), Ptr{Void}, - (Ptr{UInt8}, Cint, Ptr{IDL_MEMINT}, Cint, Ptr{UInt8}, Ptr{Void}, Ptr{Void}), - name, 1, dim, idl_type(x), pointer([x]), C_NULL, C_NULL) - execute("$name = $name[0]") - return + # Sort of a HACK: import as one-element array and then truncate to scalar + # IDL_ImportArray(int n_dim, IDL_MEMINT dim[], int type, + # UCHAR *data, IDL_ARRAY_FREE_CB free_cb, void *s) + if !isbits(x) || (idl_type(x) < 0) + error("IDL.put_var: only works with some vars containing bits types") + end + dim = zeros(Int, IDL_MAX_ARRAY_DIM) + dim[1] = 1 + ccall((:IDL_ImportNamedArray, idlcall), Ptr{Void}, + (Ptr{UInt8}, Cint, Ptr{IDL_MEMINT}, Cint, Ptr{UInt8}, Ptr{Void}, Ptr{Void}), + name, 1, dim, idl_type(x), pointer([x]), C_NULL, C_NULL) + execute("$name = $name[0]") + return end function put_var(str::AbstractString, name::AbstractString) - # Sort of a HACK: do direcly since ImportNamedArray doesn't work - execute("$name = '$str'") - return + # Sort of a HACK: do direcly since ImportNamedArray doesn't work + execute("$name = '$str'") + return end function get_name(vptr::Ptr{IDL_Variable}) - str = ccall((:IDL_VarName, idlcall), Ptr{Cchar}, (Ptr{IDL_Variable},), vptr) - return unsafe_string(str) + str = ccall((:IDL_VarName, idlcall), Ptr{Cchar}, (Ptr{IDL_Variable},), vptr) + return unsafe_string(str) end function get_vptr(name::AbstractString) - # returns C_NULL if name not in scope - name = uppercase(name) - vptr = ccall((:IDL_GetVarAddr, idlcall), Ptr{IDL_Variable}, (Ptr{UInt8},), name) - vptr + # returns C_NULL if name not in scope + name = uppercase(name) + vptr = ccall((:IDL_GetVarAddr, idlcall), Ptr{IDL_Variable}, (Ptr{UInt8},), name) + vptr end function get_var(name::AbstractString) - name = uppercase(name) - vptr = ccall((:IDL_GetVarAddr, idlcall), Ptr{IDL_Variable}, (Ptr{UInt8},), name) - if vptr == C_NULL - error("IDL.get_var: variable $name does not exist") - end - get_var(vptr) + name = uppercase(name) + vptr = ccall((:IDL_GetVarAddr, idlcall), Ptr{IDL_Variable}, (Ptr{UInt8},), name) + if vptr == C_NULL + error("IDL.get_var: variable $name does not exist") + end + get_var(vptr) end diff --git a/src/IDLREPL.jl b/src/IDLREPL.jl index a23960e..3c7ce1d 100644 --- a/src/IDLREPL.jl +++ b/src/IDLREPL.jl @@ -1,76 +1,76 @@ import Base: LineEdit, REPL function idl_repl() - - # Setup idl prompt - prompt = LineEdit.Prompt("IDL> "; - prompt_prefix=Base.text_colors[:blue], - prompt_suffix=Base.text_colors[:white]) - - repl = Base.active_repl - prompt.on_done = REPL.respond(repl,prompt) do line - ok2, line, msg = convert_continuations(line) - if !ok2 - println(msg) - println() - return - end - ok2, line, msg = replace_interpolated_vars(line) - if !ok2 - println(msg) - println() - return - end - ec = execute_converted(line) - nothing - end + # Setup idl prompt + prompt = LineEdit.Prompt("IDL> "; + prompt_prefix=Base.text_colors[:blue], + prompt_suffix=Base.text_colors[:white]) - main_mode = repl.interface.modes[1] + repl = Base.active_repl - # replace existing IDL REPL if present - i_mode = find_prompt_in_modes(repl.interface.modes, "IDL> ") - if i_mode < 1 - push!(repl.interface.modes,prompt) - else - repl.interface.modes[i_mode] = prompt - end + prompt.on_done = REPL.respond(repl,prompt) do line + ok2, line, msg = convert_continuations(line) + if !ok2 + println(msg) + println() + return + end + ok2, line, msg = replace_interpolated_vars(line) + if !ok2 + println(msg) + println() + return + end + ec = execute_converted(line) + nothing + end + main_mode = repl.interface.modes[1] - hp = main_mode.hist - hp.mode_mapping[:idl] = prompt - prompt.hist = hp - - const idl_keymap = Dict{Any,Any}( - '>' => function (s,args...) - if isempty(s) - if !haskey(s.mode_state,prompt) - s.mode_state[prompt] = LineEdit.init_state(repl.t,prompt) - end - LineEdit.transition(s,prompt) - else - LineEdit.edit_insert(s,'>') - end - end) + # replace existing IDL REPL if present + i_mode = find_prompt_in_modes(repl.interface.modes, "IDL> ") + if i_mode < 1 + push!(repl.interface.modes,prompt) + else + repl.interface.modes[i_mode] = prompt + end - search_prompt, skeymap = LineEdit.setup_search_keymap(hp) - mk = REPL.mode_keymap(main_mode) - b = Dict{Any,Any}[skeymap, mk, LineEdit.history_keymap, LineEdit.default_keymap, - LineEdit.escape_defaults] - prompt.keymap_dict = LineEdit.keymap(b) + hp = main_mode.hist + hp.mode_mapping[:idl] = prompt + prompt.hist = hp - main_mode.keymap_dict = LineEdit.keymap_merge(main_mode.keymap_dict, idl_keymap); - nothing + idl_keymap = Dict{Any,Any}( + '>' => function (s,args...) + if isempty(s) + if !haskey(s.mode_state,prompt) + s.mode_state[prompt] = LineEdit.init_state(repl.t,prompt) + end + LineEdit.transition(s,prompt) + else + LineEdit.edit_insert(s,'>') + end + end) + + search_prompt, skeymap = LineEdit.setup_search_keymap(hp) + mk = REPL.mode_keymap(main_mode) + + b = Dict{Any,Any}[skeymap, mk, LineEdit.history_keymap, LineEdit.default_keymap, + LineEdit.escape_defaults] + prompt.keymap_dict = LineEdit.keymap(b) + + main_mode.keymap_dict = LineEdit.keymap_merge(main_mode.keymap_dict, idl_keymap) + nothing end function find_prompt_in_modes(modes, name) - j = -1 - for (i,mode) in enumerate(modes) - if :prompt in fieldnames(mode) && mode.prompt == name - j = i - break - end - end - return j + j = -1 + for (i,mode) in enumerate(modes) + if :prompt in fieldnames(mode) && mode.prompt == name + j = i + break + end + end + return j end diff --git a/src/IDLRPC.jl b/src/IDLRPC.jl index d412a5e..a203636 100644 --- a/src/IDLRPC.jl +++ b/src/IDLRPC.jl @@ -4,95 +4,95 @@ include("common-funcs.jl") include("common-macros.jl") # RPC client -type RPCclient - ptr::Ptr{Void} - process::Union{Void, Base.Process} +struct RPCclient + ptr::Ptr{Nothing} + process::Union{Nothing, Base.Process} end RPCclient() = RPCclient(C_NULL, nothing) -RPCclient(ptr::Ptr{Void}) = RPCclient(ptr, nothing) +RPCclient(ptr::Ptr{Nothing}) = RPCclient(ptr, nothing) pclient = RPCclient() function rpc_init() - ccall((:IDL_RPCInit, idlrpc), Ptr{Void}, (Clong, Ptr{UInt8}), 0, C_NULL) + ccall((:IDL_RPCInit, idlrpc), Ptr{Nothing}, (Clong, Ptr{UInt8}), 0, C_NULL) end function rpc_cleanup() - ecode = ccall((:IDL_RPCCleanup, idlrpc), Cint, (Ptr{Void}, Cint), pclient.ptr, 0) - if ecode != 1 - error("IDL.exit: failed") - end - if pclient.process != nothing - kill(pclient.process) - end - return + ecode = ccall((:IDL_RPCCleanup, idlrpc), Cint, (Ptr{Nothing}, Cint), pclient.ptr, 0) + if ecode != 1 + error("IDL.exit: failed") + end + if pclient.process != nothing + kill(pclient.process) + end + return end function init() - olderr = STDERR - (rd, wr) = redirect_stderr() #Redirect error messages - ptr = rpc_init() - if ptr != C_NULL #Check if idlrpc is already running - global pclient = RPCclient(ptr) - else #Start up idlrpc - print("Initializing IDL ") - proc = spawn(`idlrpc`) - ptr = C_NULL - cnt = 0 - while ptr == C_NULL && cnt < 60 #Allow for startup time - ptr = rpc_init() - cnt = cnt + 1 - sleep(1) - print(".") - end - println("") - ptr == C_NULL && error("IDL.init: IDLRPC init failed") - global pclient = RPCclient(ptr, proc) - end - capture(true) - redirect_stderr(olderr) - #Register cleanup function to be called at exit - atexit(rpc_cleanup) + olderr = STDERR + (rd, wr) = redirect_stderr() #Redirect error messages + ptr = rpc_init() + if ptr != C_NULL #Check if idlrpc is already running + global pclient = RPCclient(ptr) + else #Start up idlrpc + print("Initializing IDL ") + proc = spawn(`idlrpc`) + ptr = C_NULL + cnt = 0 + while ptr == C_NULL && cnt < 60 #Allow for startup time + ptr = rpc_init() + cnt = cnt + 1 + sleep(1) + print(".") + end + println("") + ptr == C_NULL && error("IDL.init: IDLRPC init failed") + global pclient = RPCclient(ptr, proc) + end + capture(true) + redirect_stderr(olderr) + #Register cleanup function to be called at exit + atexit(rpc_cleanup) end function execute_converted(str::AbstractString) - # does no conversion of interpolated vars, continuation chars, or newlines - ecode = ccall((:IDL_RPCExecuteStr, idlrpc), Cint, (Ptr{Void},Ptr{UInt8}), pclient.ptr, str) - if ecode != 1 - # since error get printed by IDL, we just reset error state - ecode = ccall((:IDL_RPCExecuteStr, idlrpc), Cint, (Ptr{Void},Ptr{UInt8}), pclient.ptr, - "message, /RESET") - flush() - return false - end - flush() - return true + # does no conversion of interpolated vars, continuation chars, or newlines + ecode = ccall((:IDL_RPCExecuteStr, idlrpc), Cint, (Ptr{Nothing},Ptr{UInt8}), pclient.ptr, str) + if ecode != 1 + # since error get printed by IDL, we just reset error state + ecode = ccall((:IDL_RPCExecuteStr, idlrpc), Cint, (Ptr{Nothing},Ptr{UInt8}), pclient.ptr, + "message, /RESET") + flush() + return false + end + flush() + return true end function capture(flag::Bool) - nlines = flag ? 5000 : 0 - ecode = ccall((:IDL_RPCOutputCapture, idlrpc), Cint, (Ptr{Void}, Cint), pclient.ptr, nlines) - if ecode != 1 - error("IDL.capture: IDL_RPCOutputCapture failed") - end - return nothing + nlines = flag ? 5000 : 0 + ecode = ccall((:IDL_RPCOutputCapture, idlrpc), Cint, (Ptr{Nothing}, Cint), pclient.ptr, nlines) + if ecode != 1 + error("IDL.capture: IDL_RPCOutputCapture failed") + end + return nothing end function get_output!(line_s::IDL_RPC_LINE_S) - ecode = ccall((:IDL_RPCOutputGetStr, idlrpc), Cint, (Ptr{Void},Ref{IDL_RPC_LINE_S},Cint), - pclient.ptr, line_s, 0) - ecode == 1 ? true : false + ecode = ccall((:IDL_RPCOutputGetStr, idlrpc), Cint, (Ptr{Nothing},Ref{IDL_RPC_LINE_S},Cint), + pclient.ptr, line_s, 0) + ecode == 1 ? true : false end flag_set(x, flag) = (x & flag) == flag function flush() - line_s = IDL_RPC_LINE_S() - # gc() - while get_output!(line_s) - println(unsafe_string(line_s.buf)) - flag_set(line_s.flags, IDL_TOUT_F_NLPOST) && print("\n") - end + line_s = IDL_RPC_LINE_S() + # gc() + while get_output!(line_s) + println(unsafe_string(line_s.buf)) + flag_set(line_s.flags, IDL_TOUT_F_NLPOST) && print("\n") + end end # no free_cb needed in idlrpc (I think) @@ -102,68 +102,68 @@ free_cb = C_NULL # This is different than callable idl where the pointer to the data is copied. # I think the difference is because callable idl runs in the same process but # idlrpc does not. Thus, no free_cb is needed in idlrpc version. -function put_var{T,N}(arr::Array{T,N}, name::AbstractString) - if !isbits(eltype(arr)) || (idl_type(arr) < 0) - error("IDL.put_var: only works with some vars containing bits types") - end - dim = zeros(Int, IDL_MAX_ARRAY_DIM) - dim[1:N] = [size(arr)...] - vptr = ccall((:IDL_RPCImportArray, idlrpc), Ptr{IDL_Variable}, - (Cint, IDL_ARRAY_DIM, Cint, Ptr{T}, IDL_ARRAY_FREE_CB), - N, dim, idl_type(arr), arr, free_cb) - ecode = ccall((:IDL_RPCSetVariable, idlrpc), Cint, - (Ptr{Void}, Ptr{UInt8}, Ptr{IDL_Variable}), - pclient.ptr, name, vptr) - if ecode != 1 - error("IDL.put_var: failed") - end - return +function put_var(arr::Array{T,N}, name::AbstractString) where {T,N} + if !isbits(eltype(arr)) || (idl_type(arr) < 0) + error("IDL.put_var: only works with some vars containing bits types") + end + dim = zeros(Int, IDL_MAX_ARRAY_DIM) + dim[1:N] = [size(arr)...] + vptr = ccall((:IDL_RPCImportArray, idlrpc), Ptr{IDL_Variable}, + (Cint, IDL_ARRAY_DIM, Cint, Ptr{T}, IDL_ARRAY_FREE_CB), + N, dim, idl_type(arr), arr, free_cb) + ecode = ccall((:IDL_RPCSetVariable, idlrpc), Cint, + (Ptr{Nothing}, Ptr{UInt8}, Ptr{IDL_Variable}), + pclient.ptr, name, vptr) + if ecode != 1 + error("IDL.put_var: failed") + end + return end # there must be a slicker way to do this? function uint_size(x) - if sizeof(x) == 1 - UInt8 - elseif sizeof(x) == 2 - UInt16 - elseif sizeof(x) == 4 - UInt32 - elseif sizeof(x) == 8 - UInt64 - elseif sizeof(x) == 16 - UInt128 - end + if sizeof(x) == 1 + UInt8 + elseif sizeof(x) == 2 + UInt16 + elseif sizeof(x) == 4 + UInt32 + elseif sizeof(x) == 8 + UInt64 + elseif sizeof(x) == 16 + UInt128 + end end function put_var(x, name::AbstractString) - if !isbits(x) || (idl_type(x) < 0) - error("IDL.put_var: only works with some vars containing bits types") - end - vptr = get_vptr(name) - ccall((:IDL_RPCStoreScalar, idlrpc), Void, - (Ptr{IDL_Variable}, Cint, Ref{UInt128}), - vptr, idl_type(x), Ref{UInt128}(convert(UInt128,reinterpret(uint_size(x),x)))) - ecode = ccall((:IDL_RPCSetVariable, idlrpc), Cint, - (Ptr{Void}, Ptr{UInt8}, Ptr{IDL_Variable}), - pclient.ptr, name, vptr) - return -end - -function put_var{T}(x::Complex{T}, name::AbstractString) - T == Float32 || T == Float64 || error("IDL.put_var: only floating point complex types allowed") - if T == Float64 - y = (convert(UInt128, reinterpret(UInt64, imag(x))) << 64) + reinterpret(UInt64, real(x)) - else - y = (convert(UInt128, reinterpret(UInt32, imag(x))) << 32) + reinterpret(UInt32, real(x)) - end - vptr = get_vptr(name) - ccall((:IDL_RPCStoreScalar, idlrpc), Void, - (Ptr{IDL_Variable}, Cint, Ref{UInt128}), - vptr, idl_type(x), Ref{UInt128}(y)) - ecode = ccall((:IDL_RPCSetVariable, idlrpc), Cint, - (Ptr{Void}, Ptr{UInt8}, Ptr{IDL_Variable}), - pclient.ptr, name, vptr) - return + if !isbits(x) || (idl_type(x) < 0) + error("IDL.put_var: only works with some vars containing bits types") + end + vptr = get_vptr(name) + ccall((:IDL_RPCStoreScalar, idlrpc), Nothing, + (Ptr{IDL_Variable}, Cint, Ref{UInt128}), + vptr, idl_type(x), Ref{UInt128}(convert(UInt128,reinterpret(uint_size(x),x)))) + ecode = ccall((:IDL_RPCSetVariable, idlrpc), Cint, + (Ptr{Nothing}, Ptr{UInt8}, Ptr{IDL_Variable}), + pclient.ptr, name, vptr) + return +end + +function put_var(x::Complex{T}, name::AbstractString) where {T} + T == Float32 || T == Float64 || error("IDL.put_var: only floating point complex types allowed") + if T == Float64 + y = (convert(UInt128, reinterpret(UInt64, imag(x))) << 64) + reinterpret(UInt64, real(x)) + else + y = (convert(UInt128, reinterpret(UInt32, imag(x))) << 32) + reinterpret(UInt32, real(x)) + end + vptr = get_vptr(name) + ccall((:IDL_RPCStoreScalar, idlrpc), Nothing, + (Ptr{IDL_Variable}, Cint, Ref{UInt128}), + vptr, idl_type(x), Ref{UInt128}(y)) + ecode = ccall((:IDL_RPCSetVariable, idlrpc), Cint, + (Ptr{Nothing}, Ptr{UInt8}, Ptr{IDL_Variable}), + pclient.ptr, name, vptr) + return end # function put_var(str::AbstractString, name::AbstractString) @@ -173,39 +173,38 @@ end # end function put_var(str::AbstractString, name::AbstractString) - idl_string = IDL_String() - ccall((:IDL_RPCStrStore, idlrpc), Void, (Ptr{IDL_String}, Ptr{Cchar}), - idl_string, str) - ecode = ccall((:IDL_RPCSetVariable, idlrpc), Cint, - (Ptr{Void}, Ptr{UInt8}, Ptr{IDL_Variable}), - pclient.ptr, name, vptr) - if ecode != 1 - error("IDL.put_var: failed") - end + idl_string = IDL_String() + ccall((:IDL_RPCStrStore, idlrpc), Nothing, (Ptr{IDL_String}, Ptr{Cchar}), + idl_string, str) + ecode = ccall((:IDL_RPCSetVariable, idlrpc), Cint, + (Ptr{Nothing}, Ptr{UInt8}, Ptr{IDL_Variable}), + pclient.ptr, name, vptr) + if ecode != 1 + error("IDL.put_var: failed") + end end function get_name(vptr::Ptr{IDL_Variable}) - # not implemented for RPC - str = ccall((:IDL_RPCVarName, idlrpc), Ptr{Cchar}, (Ptr{IDL_Variable},), vptr) - return unsafe_string(str) + # not implemented for RPC + str = ccall((:IDL_RPCVarName, idlrpc), Ptr{Cchar}, (Ptr{IDL_Variable},), vptr) + return unsafe_string(str) end function get_vptr(name::AbstractString) - # returns C_NULL if name not in scope - ccall((:IDL_RPCGetMainVariable, idlrpc), Ptr{IDL_Variable}, (Ptr{Void},Ptr{UInt8}), - pclient.ptr, name) + # returns C_NULL if name not in scope + ccall((:IDL_RPCGetMainVariable, idlrpc), Ptr{IDL_Variable}, (Ptr{Nothing},Ptr{UInt8}), + pclient.ptr, name) end function get_var(name::AbstractString) - vptr = ccall((:IDL_RPCGetMainVariable, idlrpc), Ptr{IDL_Variable}, (Ptr{Void},Ptr{UInt8}), - pclient.ptr, name) - # NOTE: IDL_RPCGetVariable never seems to return NULL in spite of docs - if vptr == C_NULL - error("IDL.get_var: variable $name does not exist") - end - var = get_var(vptr, name) - # not sure if this is needed? - vptr = ccall((:IDL_RPCDeltmp, idlrpc), Void, (Ptr{IDL_Variable},), vptr) - var + vptr = ccall((:IDL_RPCGetMainVariable, idlrpc), Ptr{IDL_Variable}, (Ptr{Nothing},Ptr{UInt8}), + pclient.ptr, name) + # NOTE: IDL_RPCGetVariable never seems to return NULL in spite of docs + if vptr == C_NULL + error("IDL.get_var: variable $name does not exist") + end + var = get_var(vptr, name) + # not sure if this is needed? + vptr = ccall((:IDL_RPCDeltmp, idlrpc), Nothing, (Ptr{IDL_Variable},), vptr) + var end - diff --git a/src/common-funcs.jl b/src/common-funcs.jl index 9dd602e..aa8404b 100644 --- a/src/common-funcs.jl +++ b/src/common-funcs.jl @@ -3,9 +3,9 @@ help() = execute("help") help(s::AbstractString) = execute("help, "*s) idlhelp(s::AbstractString) = execute("?"*s) -idlhelp{T<:AbstractString}(strarr::Array{T,1}) = println("IDL.idlhelp: Array input not supported") +idlhelp(strarr::Array{T,1}) where {T<:AbstractString} = println("IDL.idlhelp: Array input not supported") shell_command(s::AbstractString) = println("% Shell commands not allowed in IDLRPC") -shell_command{T<:AbstractString}(strarr::Array{T,1}) = println("% Shell commands not allowed in IDLRPC") +shell_command(strarr::Array{T,1}) where {T<:AbstractString} = println("% Shell commands not allowed in IDLRPC") reset() = execute(".reset_session") full_reset() = execute(".full_reset_session") dotrun(filename::AbstractString) = execute(".run $filename") @@ -17,7 +17,7 @@ function execute(str::AbstractString) return nothing end -function execute_converted{T<:AbstractString}(strarr::Array{T,1}) +function execute_converted(strarr::Array{T,1}) where {T<:AbstractString} # does no conversion of interpolated vars, continuation chars, or newlines for str in strarr execute_converted(str) || return false @@ -42,7 +42,7 @@ function put_var_from_name(name::AbstractString, abort::Bool=true) return (ok, msg) end -function put_var{T<:AbstractString,N}(arr::Array{T,N}, name::AbstractString) +function put_var(arr::Array{T,N}, name::AbstractString) where {T<:AbstractString,N} # Sort of a HACK: do direcly since ImportNamedArray doesn't work execute("$name = strarr"*replace(string(size(arr)), ",)", ")")) for i=1:length(arr) diff --git a/src/idl_types.jl b/src/idl_types.jl index 450971e..88805c2 100644 --- a/src/idl_types.jl +++ b/src/idl_types.jl @@ -24,14 +24,14 @@ const IDL_TYP_LONG64 = 14 const IDL_TYP_ULONG64 = 15 # translating IDL/C types to julia -typealias IDL_MEMINT Int -typealias IDL_UMEMINT UInt -typealias UCHAR Cuchar +const IDL_MEMINT = Int +const IDL_UMEMINT = UInt +const UCHAR = Cuchar # NOTE: IDL_ARRAY_DIM is fixed length array IDL_MEMINT[IDL_MAX_ARRAY_DIM] (i.e, Int[8]) -typealias IDL_ARRAY_DIM Ptr{IDL_MEMINT} -typealias IDL_ARRAY_FREE_CB Ptr{Void} -typealias IDL_FILEINT Int # possibly different on Windows -typealias IDL_STRING_SLEN_T Cint +const IDL_ARRAY_DIM = Ptr{IDL_MEMINT} +const IDL_ARRAY_FREE_CB = Ptr{Nothing} +const IDL_FILEINT = Int # possibly different on Windows +const IDL_STRING_SLEN_T = Cint const IDL_STRING_MAX_SLEN = 2147483647 # should you check this? # /***** IDL_VARIABLE flag values ********/ @@ -60,12 +60,10 @@ function idl_type(jl_t) idl_t = IDL_TYP_FLOAT elseif t == Float64 idl_t = IDL_TYP_DOUBLE - elseif t == Complex64 + elseif t == ComplexF64 idl_t = IDL_TYP_COMPLEX elseif t <: AbstractString idl_t = IDL_TYP_STRING - elseif t == Complex128 - idl_t = IDL_TYP_DCOMPLEX elseif t == UInt16 idl_t = IDL_TYP_UINT elseif t == UInt32 @@ -93,11 +91,11 @@ function jl_type(idl_t) elseif idl_t == IDL_TYP_DOUBLE jl_t = Float64 elseif idl_t == IDL_TYP_COMPLEX - jl_t = Complex64 + jl_t = ComplexF64 elseif idl_t == IDL_TYP_STRING jl_t = Compat.String - elseif idl_t == IDL_TYP_DCOMPLEX - jl_t = Complex128 + #elseif idl_t == IDL_TYP_DCOMPLEX + # jl_t = Complex128 elseif idl_t == IDL_TYP_UINT jl_t = UInt16 elseif idl_t == IDL_TYP_ULONG @@ -116,8 +114,8 @@ end #*************************************************************************************************# # some IDL types from extern.jl # sizeof(buf) is max size of IDL_ALLTYPES Union (64x2=128 bits or 16 bytes on all platforms) -typealias IDL_ALLTYPES UInt128 -immutable IDL_Variable +const IDL_ALLTYPES = UInt128 +struct IDL_Variable vtype::UCHAR flags::UCHAR flags2::UCHAR @@ -125,7 +123,7 @@ immutable IDL_Variable end # works as a fixed length array -immutable IDL_DIMS +struct IDL_DIMS d1::IDL_MEMINT d2::IDL_MEMINT d3::IDL_MEMINT @@ -139,7 +137,7 @@ end dims(d::IDL_DIMS) = (d.d1,d.d2,d.d3,d.d4,d.d5,d.d6,d.d7,d.d8) dims(d::IDL_DIMS, ndims::Integer) = (d.d1,d.d2,d.d3,d.d4,d.d5,d.d6,d.d7,d.d8)[1:ndims] -immutable IDL_Array +struct IDL_Array elt_len::IDL_MEMINT # Length of element in char units arr_len::IDL_MEMINT # Length of entire array (char) n_elts::IDL_MEMINT # total # of elements @@ -153,7 +151,7 @@ immutable IDL_Array data_guard::IDL_MEMINT # Guard longword end -immutable IDL_String +struct IDL_String slen::IDL_STRING_SLEN_T # Length of string, 0 for null stype::Cshort # type of string, static or dynamic s::Ptr{Cchar} # Addr of string @@ -162,7 +160,7 @@ end # From idl_rpc.h const IDL_RPC_MAX_STRLEN = 512 # max string length -immutable IDL_RPC_LINE_S +struct IDL_RPC_LINE_S flags::Cint buf::Ptr{Cchar} IDL_RPC_LINE_S() = new(0, Base.unsafe_convert(Ptr{Cchar}, Array(Cchar, IDL_RPC_MAX_STRLEN))) From 662f26038d9d2efa275269e5b37e650b1e8bcf56 Mon Sep 17 00:00:00 2001 From: hyzhou Date: Tue, 11 Feb 2020 16:18:20 -0500 Subject: [PATCH 04/38] Got stuck with "clnttcp_create: RPC: Remote system error - Connection refused". --- src/IDLCall.jl | 24 +++++++++++++----------- src/IDLRPC.jl | 2 +- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/IDLCall.jl b/src/IDLCall.jl index b057c34..f91cf01 100644 --- a/src/IDLCall.jl +++ b/src/IDLCall.jl @@ -5,20 +5,22 @@ module IDLCall # Find IDL library directory if on Linux if Sys.isunix() - #IDL_DIR = dirname(chomp(readstring(`which idl`))) - #idl_lib_dir = chomp(readstring(`bash -c "ls -d $(IDL_DIR)/bin.*"`)) + # readlink??? + #IDL_LIB_DIR = chomp(readstring(`bash -c "ls -d $(IDL_DIR)/bin.*"`)) #IDL_DIR = dirname(chomp(read(`which idl`,String))) - IDL_DIR = "/Applications/exelis/idl85/" + IDL_DIR = "/Applications/exelis/idl85" #IDL_PATH='/Users/hyzhou/Idl:${IDL_DIR}/lib:${IDL_DIR}/lib/utilities' #IDL_STARTUP=idlrc - idl_lib_dir = chomp(read(`bash -c "ls -d $(IDL_DIR)/bin.*"`,String)) - #const idlcall = idl_lib_dir*"/libidl" - #const idlrpc = idl_lib_dir*"/libidl_rpc" - const idlcall = joinpath(idl_lib_dir,"lib") - const idlrpc = joinpath(idl_lib_dir,"libidl_rpc") -else - const idlcall = "libidl" - const idlrpc = "libidl_rpc" + #IDL_LIB_DIR = chomp(read(`bash -c "ls -d $(IDL_DIR)/bin.*"`,String)) + IDL_LIB_DIR = "/Applications/exelis/idl85/bin/bin.darwin.x86_64" + #const idlcall = IDL_LIB_DIR*"/libidl" + #const idlrpc = IDL_LIB_DIR*"/libidl_rpc" + #const idlcall = joinpath(IDL_LIB_DIR,"lib") + #const idlrpc = joinpath(IDL_LIB_DIR,"libidl_rpc") + const idlrpc = joinpath(IDL_LIB_DIR,"libidl_rpc.dylib") +else # Windows + #const idlcall = "libidl" + #const idlrpc = "libidl_rpc" end export init, get_var, put_var, execute, @get_var, @put_var, idl_repl diff --git a/src/IDLRPC.jl b/src/IDLRPC.jl index a203636..c2f9575 100644 --- a/src/IDLRPC.jl +++ b/src/IDLRPC.jl @@ -29,7 +29,7 @@ function rpc_cleanup() end function init() - olderr = STDERR + olderr = stderr (rd, wr) = redirect_stderr() #Redirect error messages ptr = rpc_init() if ptr != C_NULL #Check if idlrpc is already running From b39255b98a06f713a54d13e6b4ced462393383d8 Mon Sep 17 00:00:00 2001 From: hyzhou Date: Thu, 13 Feb 2020 17:02:05 -0500 Subject: [PATCH 05/38] Update legacy functions. --- src/IDLCallable.jl | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/IDLCallable.jl b/src/IDLCallable.jl index 9307b23..4d429ce 100644 --- a/src/IDLCallable.jl +++ b/src/IDLCallable.jl @@ -3,20 +3,20 @@ include("idl_types.jl") include("common-funcs.jl") include("common-macros.jl") -if is_apple() - cd(idl_lib_dir) do +using Libdl + +if Sys.isapple() + cd(IDL_LIB_DIR) do Libdl.dlopen("libidl") end end function init() ecode = ccall((:IDL_Init, idlcall), Cint, (Cint, Ptr{Cint}, Ptr{Ptr{UInt8}}), - 0, C_NULL, C_NULL) - if ecode == 0 - error("IDL.init: IDL init failed") - end + 0, C_NULL, C_NULL) + ecode == 0 && error("IDL.init: IDL init failed") global output_cb - ccall((:IDL_ToutPush, idlcall), Void, (Ptr{Void},), output_cb) + ccall((:IDL_ToutPush, idlcall), Nothing, (Ptr{Nothing},), output_cb) end # function execute{T<:AbstractString}(strarr::Array{T,1}) @@ -49,7 +49,7 @@ function get_output(flags::Cint, buf::Ptr{UInt8}, n::Cint) return end -output_cb = cfunction(get_output, Void, (Cint, Ptr{UInt8},Cint)) +output_cb = @cfunction(get_output, Nothing, (Cint, Ptr{UInt8},Cint)) # function exit() # # probably better to do a .full_reset instead @@ -68,16 +68,16 @@ function done_with_var(p::Ptr{UInt8}) return end -free_cb = cfunction(done_with_var, Void, (Ptr{UInt8},)) +free_cb = @cfunction(done_with_var, Nothing, (Ptr{UInt8},)) -function put_var{T,N}(arr::Array{T,N}, name::AbstractString) +function put_var(arr::Array{T,N}, name::AbstractString) where {T,N} if !isbits(eltype(arr)) || (idl_type(arr) < 0) error("IDL.put_var: only works with some vars containing bits types") end dim = zeros(Int, IDL_MAX_ARRAY_DIM) dim[1:N] = [size(arr)...] vptr = ccall((:IDL_ImportNamedArray, idlcall), Ptr{IDL_Variable}, - (Ptr{UInt8}, Cint, IDL_ARRAY_DIM, Cint, Ptr{UInt8}, IDL_ARRAY_FREE_CB , Ptr{Void}), + (Ptr{UInt8}, Cint, IDL_ARRAY_DIM, Cint, Ptr{UInt8}, IDL_ARRAY_FREE_CB , Ptr{Nothing}), name, N, dim, idl_type(arr), pointer(arr), free_cb, C_NULL) if vptr == C_NULL error("IDL.put_var: failed") @@ -89,15 +89,15 @@ end function put_var(x, name::AbstractString) # Sort of a HACK: import as one-element array and then truncate to scalar # IDL_ImportArray(int n_dim, IDL_MEMINT dim[], int type, - # UCHAR *data, IDL_ARRAY_FREE_CB free_cb, void *s) + # UCHAR *data, IDL_ARRAY_FREE_CB free_cb, Nothing *s) if !isbits(x) || (idl_type(x) < 0) error("IDL.put_var: only works with some vars containing bits types") end dim = zeros(Int, IDL_MAX_ARRAY_DIM) dim[1] = 1 - ccall((:IDL_ImportNamedArray, idlcall), Ptr{Void}, - (Ptr{UInt8}, Cint, Ptr{IDL_MEMINT}, Cint, Ptr{UInt8}, Ptr{Void}, Ptr{Void}), - name, 1, dim, idl_type(x), pointer([x]), C_NULL, C_NULL) + ccall((:IDL_ImportNamedArray, idlcall), Ptr{Nothing}, + (Ptr{UInt8}, Cint, Ptr{IDL_MEMINT}, Cint, Ptr{UInt8}, Ptr{Nothing}, Ptr{Nothing}), + name, 1, dim, idl_type(x), pointer([x]), C_NULL, C_NULL) execute("$name = $name[0]") return end From 0b49f8696a512b7b4ed38e44ed928b3ed5dbc74d Mon Sep 17 00:00:00 2001 From: hyzhou Date: Fri, 14 Feb 2020 17:54:01 -0500 Subject: [PATCH 06/38] Interface in Julia 1.3 --- src/IDL.jl | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/IDL.jl diff --git a/src/IDL.jl b/src/IDL.jl new file mode 100644 index 0000000..172845d --- /dev/null +++ b/src/IDL.jl @@ -0,0 +1,23 @@ +module IDL + +export get_var, put_var, execute +export help + +# Find IDL library directory if on Linux +if Sys.isunix() + IDL_LIB_DIR = "/Applications/exelis/idl85/bin/bin.darwin.x86_64" + const libidl_rpc = joinpath(IDL_LIB_DIR,"libidl_rpc.dylib") + const idlrpc = "/Applications/exelis/idl85/bin/idlrpc" +else # Windows + const idlcall = "libidl" + const idlrpc = "libidl_rpc" +end + +jl_idl_type = get(ENV, "JL_IDL_TYPE", Sys.iswindows() ? "CALLABLE" : "RPC") + +jl_idl_type == "RPC" ? include("IDLRPC.jl") : +jl_idl_type == "CALLABLE" ? include("IDLCallable.jl") : +Sys.iswindows() ? error("JL_IDL_TYPE must be CALLABLE on windows") : +error("JL_IDL_TYPE must be RPC or CALLABLE") + +end From 4892e975f5dd2815f744688e16fb979e79ab3c37 Mon Sep 17 00:00:00 2001 From: hyzhou Date: Fri, 14 Feb 2020 17:54:44 -0500 Subject: [PATCH 07/38] Format adjustment. --- src/idl_types.jl | 184 +++++++++++++++++++++++------------------------ 1 file changed, 92 insertions(+), 92 deletions(-) diff --git a/src/idl_types.jl b/src/idl_types.jl index 88805c2..d470cee 100644 --- a/src/idl_types.jl +++ b/src/idl_types.jl @@ -44,71 +44,71 @@ const IDL_V_STRUCT = 32 const IDL_V_NULL = 64 function idl_type(jl_t) - # IDL type index from julia type - t = typeof(jl_t) - if t <: AbstractArray - t = eltype(jl_t) - end - idl_t = -1 - if t == UInt8 - idl_t = IDL_TYP_BYTE - elseif t == Int16 - idl_t = IDL_TYP_INT - elseif t == Int32 - idl_t = IDL_TYP_LONG - elseif t == Float32 - idl_t = IDL_TYP_FLOAT - elseif t == Float64 - idl_t = IDL_TYP_DOUBLE - elseif t == ComplexF64 - idl_t = IDL_TYP_COMPLEX - elseif t <: AbstractString - idl_t = IDL_TYP_STRING - elseif t == UInt16 - idl_t = IDL_TYP_UINT - elseif t == UInt32 - idl_t = IDL_TYP_ULONG - elseif t == Int64 - idl_t = IDL_TYP_LONG64 - elseif t == UInt64 - idl_t = IDL_TYP_ULONG64 - end - if idl_t < 0 error("IDL.idl_type: type not found: " * string(t)) end - return idl_t + # IDL type index from julia type + t = typeof(jl_t) + if t <: AbstractArray + t = eltype(jl_t) + end + idl_t = -1 + if t == UInt8 + idl_t = IDL_TYP_BYTE + elseif t == Int16 + idl_t = IDL_TYP_INT + elseif t == Int32 + idl_t = IDL_TYP_LONG + elseif t == Float32 + idl_t = IDL_TYP_FLOAT + elseif t == Float64 + idl_t = IDL_TYP_DOUBLE + elseif t == ComplexF64 + idl_t = IDL_TYP_COMPLEX + elseif t <: AbstractString + idl_t = IDL_TYP_STRING + elseif t == UInt16 + idl_t = IDL_TYP_UINT + elseif t == UInt32 + idl_t = IDL_TYP_ULONG + elseif t == Int64 + idl_t = IDL_TYP_LONG64 + elseif t == UInt64 + idl_t = IDL_TYP_ULONG64 + end + if idl_t < 0 error("IDL.idl_type: type not found: " * string(t)) end + return idl_t end function jl_type(idl_t) - # julia type from IDL type index - jl_t = Any - if idl_t == IDL_TYP_BYTE - jl_t = UInt8 - elseif idl_t == IDL_TYP_INT - jl_t = Int16 - elseif idl_t == IDL_TYP_LONG - jl_t = Int32 - elseif idl_t == IDL_TYP_FLOAT - jl_t = Float32 - elseif idl_t == IDL_TYP_DOUBLE - jl_t = Float64 - elseif idl_t == IDL_TYP_COMPLEX - jl_t = ComplexF64 - elseif idl_t == IDL_TYP_STRING - jl_t = Compat.String - #elseif idl_t == IDL_TYP_DCOMPLEX - # jl_t = Complex128 - elseif idl_t == IDL_TYP_UINT - jl_t = UInt16 - elseif idl_t == IDL_TYP_ULONG - jl_t = UInt32 - elseif idl_t == IDL_TYP_LONG64 - jl_t = Int64 - elseif idl_t == IDL_TYP_ULONG64 - jl_t = UInt64 - end - if jl_t == Any - error("IDL.jl_type: type not found: " * string(idl_t)) - end - return jl_t + # julia type from IDL type index + jl_t = Any + if idl_t == IDL_TYP_BYTE + jl_t = UInt8 + elseif idl_t == IDL_TYP_INT + jl_t = Int16 + elseif idl_t == IDL_TYP_LONG + jl_t = Int32 + elseif idl_t == IDL_TYP_FLOAT + jl_t = Float32 + elseif idl_t == IDL_TYP_DOUBLE + jl_t = Float64 + elseif idl_t == IDL_TYP_COMPLEX + jl_t = ComplexF64 + elseif idl_t == IDL_TYP_STRING + jl_t = Compat.String + #elseif idl_t == IDL_TYP_DCOMPLEX + # jl_t = Complex128 + elseif idl_t == IDL_TYP_UINT + jl_t = UInt16 + elseif idl_t == IDL_TYP_ULONG + jl_t = UInt32 + elseif idl_t == IDL_TYP_LONG64 + jl_t = Int64 + elseif idl_t == IDL_TYP_ULONG64 + jl_t = UInt64 + end + if jl_t == Any + error("IDL.jl_type: type not found: " * string(idl_t)) + end + return jl_t end #*************************************************************************************************# @@ -116,54 +116,54 @@ end # sizeof(buf) is max size of IDL_ALLTYPES Union (64x2=128 bits or 16 bytes on all platforms) const IDL_ALLTYPES = UInt128 struct IDL_Variable - vtype::UCHAR - flags::UCHAR - flags2::UCHAR - buf::IDL_ALLTYPES + vtype::UCHAR + flags::UCHAR + flags2::UCHAR + buf::IDL_ALLTYPES end # works as a fixed length array struct IDL_DIMS - d1::IDL_MEMINT - d2::IDL_MEMINT - d3::IDL_MEMINT - d4::IDL_MEMINT - d5::IDL_MEMINT - d6::IDL_MEMINT - d7::IDL_MEMINT - d8::IDL_MEMINT + d1::IDL_MEMINT + d2::IDL_MEMINT + d3::IDL_MEMINT + d4::IDL_MEMINT + d5::IDL_MEMINT + d6::IDL_MEMINT + d7::IDL_MEMINT + d8::IDL_MEMINT end dims(d::IDL_DIMS) = (d.d1,d.d2,d.d3,d.d4,d.d5,d.d6,d.d7,d.d8) dims(d::IDL_DIMS, ndims::Integer) = (d.d1,d.d2,d.d3,d.d4,d.d5,d.d6,d.d7,d.d8)[1:ndims] struct IDL_Array - elt_len::IDL_MEMINT # Length of element in char units - arr_len::IDL_MEMINT # Length of entire array (char) - n_elts::IDL_MEMINT # total # of elements - data::Ptr{UCHAR} # ^ to beginning of array data - n_dim::UCHAR # # of dimensions used by array - flags::UCHAR # Array block flags - file_unit::Cshort # # of assoc file if file var - dim::IDL_DIMS # dimensions - free_cb::IDL_ARRAY_FREE_CB # Free callback - offset::IDL_FILEINT # Offset to base of data for file var - data_guard::IDL_MEMINT # Guard longword + elt_len::IDL_MEMINT # Length of element in char units + arr_len::IDL_MEMINT # Length of entire array (char) + n_elts::IDL_MEMINT # total # of elements + data::Ptr{UCHAR} # ^ to beginning of array data + n_dim::UCHAR # # of dimensions used by array + flags::UCHAR # Array block flags + file_unit::Cshort # # of assoc file if file var + dim::IDL_DIMS # dimensions + free_cb::IDL_ARRAY_FREE_CB # Free callback + offset::IDL_FILEINT # Offset to base of data for file var + data_guard::IDL_MEMINT # Guard longword end struct IDL_String - slen::IDL_STRING_SLEN_T # Length of string, 0 for null - stype::Cshort # type of string, static or dynamic - s::Ptr{Cchar} # Addr of string - IDL_String() = new(0, 0, Base.unsafe_convert(Ptr{Cchar}, Array(Cchar, IDL_RPC_MAX_STRLEN))) + slen::IDL_STRING_SLEN_T # Length of string, 0 for null + stype::Cshort # type of string, static or dynamic + s::Ptr{Cchar} # Addr of string + IDL_String() = new(0, 0, Base.unsafe_convert(Ptr{Cchar}, Array{Cchar}(undef, IDL_RPC_MAX_STRLEN))) end # From idl_rpc.h const IDL_RPC_MAX_STRLEN = 512 # max string length struct IDL_RPC_LINE_S - flags::Cint - buf::Ptr{Cchar} - IDL_RPC_LINE_S() = new(0, Base.unsafe_convert(Ptr{Cchar}, Array(Cchar, IDL_RPC_MAX_STRLEN))) + flags::Cint + buf::Ptr{Cchar} + IDL_RPC_LINE_S() = new(0, Base.unsafe_convert(Ptr{Cchar}, Array{Cchar}(undef, IDL_RPC_MAX_STRLEN))) end const IDL_TOUT_F_STDERR = 1 # Output to stderr instead of stdout From d401d3c0e3c8e19e727e205da2fcc76e12b89ae4 Mon Sep 17 00:00:00 2001 From: hyzhou Date: Fri, 14 Feb 2020 17:55:26 -0500 Subject: [PATCH 08/38] Commented out line continuation part for testing. --- src/common-funcs.jl | 327 ++++++++++++++++++++++---------------------- 1 file changed, 164 insertions(+), 163 deletions(-) diff --git a/src/common-funcs.jl b/src/common-funcs.jl index aa8404b..941eb45 100644 --- a/src/common-funcs.jl +++ b/src/common-funcs.jl @@ -1,4 +1,3 @@ - # convienence routines help() = execute("help") help(s::AbstractString) = execute("help, "*s) @@ -11,198 +10,200 @@ full_reset() = execute(".full_reset_session") dotrun(filename::AbstractString) = execute(".run $filename") function execute(str::AbstractString) - ok, strarr, msg = convert_command(str) - ok || error(msg) - execute_converted(strarr) - return nothing + ok, strarr, msg = convert_command(str) + ok || error(msg) + println("start") + execute_converted(strarr) + println("done") + return nothing end function execute_converted(strarr::Array{T,1}) where {T<:AbstractString} - # does no conversion of interpolated vars, continuation chars, or newlines - for str in strarr - execute_converted(str) || return false - end - return true + # does no conversion of interpolated vars, continuation chars, or newlines + for str in strarr + execute_converted(str) || return false + end + return true end function put_var_from_name(name::AbstractString, abort::Bool=true) - # abort=false causes routine to not issue error - ok = true - msg = "" - if !isdefined(Main, Symbol(name)) - ok = false - msg = "IDL.put_var_from_name: undefined variable $name in Module Main" - if abort - error(msg) - else - return (ok, msg) - end - end - put_var(getfield(Main, Symbol(name)), name) - return (ok, msg) + # abort=false causes routine to not issue error + ok = true + msg = "" + if !isdefined(Main, Symbol(name)) + ok = false + msg = "IDL.put_var_from_name: undefined variable $name in Module Main" + if abort + error(msg) + else + return (ok, msg) + end + end + put_var(getfield(Main, Symbol(name)), name) + return (ok, msg) end function put_var(arr::Array{T,N}, name::AbstractString) where {T<:AbstractString,N} - # Sort of a HACK: do direcly since ImportNamedArray doesn't work - execute("$name = strarr"*replace(string(size(arr)), ",)", ")")) - for i=1:length(arr) - j = i-1 - str = arr[i] - execute("$name[$j] = '$str'") - end - return + # Sort of a HACK: do direcly since ImportNamedArray doesn't work + execute("$name = strarr"*replace(string(size(arr)), ",)", ")")) + for i=1:length(arr) + j = i-1 + str = arr[i] + execute("$name[$j] = '$str'") + end + return end const mask64 = 0x0000000000000000ffffffffffffffff const mask32 = 0x000000000000000000000000ffffffff function get_var(vptr::Ptr{IDL_Variable}, name::AbstractString="") - var = unsafe_load(vptr) - # some types not dealt with - if (var.flags & IDL_V_FILE) != 0 - error("IDL.extract_from_vptr: $name: assoc type not setup") - end - ## if (var.flags & IDL_V_DYNAMIC) != 0 - ## println("dynamic") - ## end - if (var.flags & IDL_V_NULL) != 0 - error("IDL.extract_from_vptr: $name: variable is null") - end + var = unsafe_load(vptr) + # some types not dealt with + if (var.flags & IDL_V_FILE) != 0 + error("IDL.extract_from_vptr: $name: assoc type not setup") + end + ## if (var.flags & IDL_V_DYNAMIC) != 0 + ## println("dynamic") + ## end + if (var.flags & IDL_V_NULL) != 0 + error("IDL.extract_from_vptr: $name: variable is null") + end - # array types - if (var.flags & IDL_V_ARR) != 0 - if var.vtype == IDL_TYP_STRING - parr = reinterpret(Ptr{IDL_Array}, convert(Int, var.buf)) - idl_arr = unsafe_load(parr) - pdata = reinterpret(Ptr{IDL_String}, idl_arr.data) - strarr = Array(Compat.ASCIIString, dims(idl_arr.dim, idl_arr.n_dim)) - for i=1:idl_arr.n_elts - data = unsafe_load(pdata, i) - strarr[i] = data.slen > 0 ? unsafe_string(data.s, Int(data.slen)) : "" - end - return strarr - elseif var.vtype == IDL_TYP_STRUCT - error("IDL.extract_from_vptr: $name: STRUCT not setup") - elseif var.vtype == IDL_TYP_PTR - error("IDL.extract_from_vptr: $name: PTRARR types not setup") - elseif var.vtype == IDL_TYP_OBJREF - error("IDL.extract_from_vptr: $name: OBJARR types not setup") - else - parr = reinterpret(Ptr{IDL_Array}, convert(Int, var.buf)) - idl_arr = unsafe_load(parr) - jl_t = jl_type(var.vtype) - pdata = reinterpret(Ptr{jl_t}, idl_arr.data) - # not sure why this doesn't work - # arr = unsafe_wrap(Array, pdata, dims(idl_arr.dim, idl_arr.n_dim)) - arr = Array(jl_t, dims(idl_arr.dim, idl_arr.n_dim)) - for i=1:idl_arr.n_elts - arr[i] = unsafe_load(pdata, i) - end - return arr - end - end + # array types + if (var.flags & IDL_V_ARR) != 0 + if var.vtype == IDL_TYP_STRING + parr = reinterpret(Ptr{IDL_Array}, convert(Int, var.buf)) + idl_arr = unsafe_load(parr) + pdata = reinterpret(Ptr{IDL_String}, idl_arr.data) + strarr = Array(Compat.ASCIIString, dims(idl_arr.dim, idl_arr.n_dim)) + for i=1:idl_arr.n_elts + data = unsafe_load(pdata, i) + strarr[i] = data.slen > 0 ? unsafe_string(data.s, Int(data.slen)) : "" + end + return strarr + elseif var.vtype == IDL_TYP_STRUCT + error("IDL.extract_from_vptr: $name: STRUCT not setup") + elseif var.vtype == IDL_TYP_PTR + error("IDL.extract_from_vptr: $name: PTRARR types not setup") + elseif var.vtype == IDL_TYP_OBJREF + error("IDL.extract_from_vptr: $name: OBJARR types not setup") + else + parr = reinterpret(Ptr{IDL_Array}, convert(Int, var.buf)) + idl_arr = unsafe_load(parr) + jl_t = jl_type(var.vtype) + pdata = reinterpret(Ptr{jl_t}, idl_arr.data) + # not sure why this doesn't work + # arr = unsafe_wrap(Array, pdata, dims(idl_arr.dim, idl_arr.n_dim)) + arr = Array(jl_t, dims(idl_arr.dim, idl_arr.n_dim)) + for i=1:idl_arr.n_elts + arr[i] = unsafe_load(pdata, i) + end + return arr + end + end - # Scalar value - if var.vtype == IDL_TYP_UNDEF - error("IDL.extract_from_vptr: $name: undefined variable") - elseif var.vtype == IDL_TYP_BYTE - return reinterpret(Int8, convert(UInt8, var.buf)) - elseif var.vtype == IDL_TYP_INT - return reinterpret(Int16, convert(UInt16, var.buf)) - elseif var.vtype == IDL_TYP_LONG - return reinterpret(Int32, convert(UInt32, var.buf)) - elseif var.vtype == IDL_TYP_FLOAT - return reinterpret(Float32, convert(UInt32, var.buf)) - elseif var.vtype == IDL_TYP_DOUBLE - return reinterpret(Float64, convert(UInt64, var.buf)) - elseif var.vtype == IDL_TYP_COMPLEX - return complex(reinterpret(Float32, convert(UInt32, var.buf & mask32)), - reinterpret(Float32, convert(UInt32, var.buf >> 32))) - elseif var.vtype == IDL_TYP_STRING - slen = reinterpret(Int32, convert(UInt32,var.buf & mask32)) - stype = reinterpret(Int32, convert(UInt32,(var.buf & mask64) >> 32)) - println(stype) - s = reinterpret(Ptr{Cchar}, convert(UInt64,var.buf >> 64)) - return slen > 0 ? unsafe_string(s, slen) : "" - elseif var.vtype == IDL_TYP_STRUCT - error("IDL.extract_from_vptr: $name: STRUCT not setup") - elseif var.vtype == IDL_TYP_DCOMPLEX - return complex(reinterpret(Float64, convert(UInt64, var.buf & mask64)), - reinterpret(Float64, convert(UInt64, var.buf >> 64))) - elseif var.vtype == IDL_TYP_PTR - error("IDL.extract_from_vptr: $name: PTR not setup") - elseif var.vtype == IDL_TYP_OBJREF - error("IDL.extract_from_vptr: $name: OBJREF not setup") - elseif var.vtype == IDL_TYP_UINT - return reinterpret(UInt16, convert(UInt16, var.buf)) - elseif var.vtype == IDL_TYP_ULONG - return reinterpret(UInt32, convert(UInt32, var.buf)) - elseif var.vtype == IDL_TYP_LONG64 - return reinterpret(Int64, convert(UInt64, var.buf)) - elseif var.vtype == IDL_TYP_ULONG64 - return reinterpret(UInt64, convert(UInt64, var.buf)) - end - # should be impossible to get here - error("IDL.extract_from_vptr: $name: type is not setup") + # Scalar value + if var.vtype == IDL_TYP_UNDEF + error("IDL.extract_from_vptr: $name: undefined variable") + elseif var.vtype == IDL_TYP_BYTE + return reinterpret(Int8, convert(UInt8, var.buf)) + elseif var.vtype == IDL_TYP_INT + return reinterpret(Int16, convert(UInt16, var.buf)) + elseif var.vtype == IDL_TYP_LONG + return reinterpret(Int32, convert(UInt32, var.buf)) + elseif var.vtype == IDL_TYP_FLOAT + return reinterpret(Float32, convert(UInt32, var.buf)) + elseif var.vtype == IDL_TYP_DOUBLE + return reinterpret(Float64, convert(UInt64, var.buf)) + elseif var.vtype == IDL_TYP_COMPLEX + return complex(reinterpret(Float32, convert(UInt32, var.buf & mask32)), + reinterpret(Float32, convert(UInt32, var.buf >> 32))) + elseif var.vtype == IDL_TYP_STRING + slen = reinterpret(Int32, convert(UInt32,var.buf & mask32)) + stype = reinterpret(Int32, convert(UInt32,(var.buf & mask64) >> 32)) + println(stype) + s = reinterpret(Ptr{Cchar}, convert(UInt64,var.buf >> 64)) + return slen > 0 ? unsafe_string(s, slen) : "" + elseif var.vtype == IDL_TYP_STRUCT + error("IDL.extract_from_vptr: $name: STRUCT not setup") + elseif var.vtype == IDL_TYP_DCOMPLEX + return complex(reinterpret(Float64, convert(UInt64, var.buf & mask64)), + reinterpret(Float64, convert(UInt64, var.buf >> 64))) + elseif var.vtype == IDL_TYP_PTR + error("IDL.extract_from_vptr: $name: PTR not setup") + elseif var.vtype == IDL_TYP_OBJREF + error("IDL.extract_from_vptr: $name: OBJREF not setup") + elseif var.vtype == IDL_TYP_UINT + return reinterpret(UInt16, convert(UInt16, var.buf)) + elseif var.vtype == IDL_TYP_ULONG + return reinterpret(UInt32, convert(UInt32, var.buf)) + elseif var.vtype == IDL_TYP_LONG64 + return reinterpret(Int64, convert(UInt64, var.buf)) + elseif var.vtype == IDL_TYP_ULONG64 + return reinterpret(UInt64, convert(UInt64, var.buf)) + end + # should be impossible to get here + error("IDL.extract_from_vptr: $name: type is not setup") end function inside_string(pt::Int, line::AbstractString) - for re in [r"('[^']+')", r"(\"[^\"]+\")"] - for m in eachmatch(re, line) - if pt >= m.offset && - pt < m.offset+endof(m.captures[1]) - return true - end - end - end - return false + for re in (r"('[^']+')", r"(\"[^\"]+\")") + for m in eachmatch(re, line) + if m.offset+endof(m.captures[1]) > pt ≥ m.offset + return true + end + end + end + return false end function convert_continuations(line) - # remove trailing comments and continuation lines - # will remove continuation on final line which is invalid idl syntax - pt = start(line) - while (pt = first(search(line, r";|\$", pt))) > 0 - if !inside_string(pt, line) - line = replace(line, r"(;|\$).*(\n|$)", "", 1) - end - if pt < endof(line) - pt = next(line, pt)[2] - end - end - return true, line, "" + # remove trailing comments and continuation lines + # will remove continuation on final line which is invalid idl syntax + #pt = start(line) + pt = strip(line) + while (pt = findfirst(r";|\$", pt)) > 0 + if !inside_string(pt, line) + line = replace(line, r"(;|\$).*(\n|$)", "", 1) + end + if pt < endof(line) + pt = next(line, pt)[2] + end + end + return true, line, "" end function convert_newlines(line) - # separates line at newline ("\n") characters into string array - # assumes that continuation characters are already removed - # not type stable but should not matter for repl use - line = chomp(line) - if in('\n', line) - line = split(line, '\n', keep=false) - end - return line + # separates line at newline ("\n") characters into string array + # assumes that continuation characters are already removed + # not type stable but should not matter for repl use + line = chomp(line) + if in('\n', line) + line = split(line, '\n', keep=false) + end + return line end function replace_interpolated_vars(line) - # use %var to automatically pull var into idl and use it - while (m = match(r"\%(\w+)", line)) != nothing - if !inside_string(m.offset, line) - ok, msg = put_var_from_name(ascii(m.captures[1]), false) - if !ok - return false, line, msg - end - line = line[1:m.offset-1]*line[m.offset+1:end] - end - end - return true, line, "" + # use %var to automatically pull var into idl and use it + while (m = match(r"\%(\w+)", line)) != nothing + if !inside_string(m.offset, line) + ok, msg = put_var_from_name(ascii(m.captures[1]), false) + if !ok + return false, line, msg + end + line = line[1:m.offset-1]*line[m.offset+1:end] + end + end + return true, line, "" end function convert_command(line) - ok, line, msg = replace_interpolated_vars(line) - ok || return ok, line, msg - ok, line, msg = convert_continuations(line) - ok || return ok, line, msg - line = convert_newlines(line) - return true, line, msg + ok, line, msg = replace_interpolated_vars(line) + ok || return ok, line, msg + #ok, line, msg = convert_continuations(line) # hyzhou: remove while testing + ok || return ok, line, msg + line = convert_newlines(line) + return true, line, msg end From da199c90d35fd1466544b496c40870495e293c5e Mon Sep 17 00:00:00 2001 From: hyzhou Date: Fri, 14 Feb 2020 17:56:12 -0500 Subject: [PATCH 09/38] Use __init__() function for initializing the package. --- src/IDLRPC.jl | 98 ++++++++++++++++++++++----------------------------- 1 file changed, 42 insertions(+), 56 deletions(-) diff --git a/src/IDLRPC.jl b/src/IDLRPC.jl index c2f9575..67fe93c 100644 --- a/src/IDLRPC.jl +++ b/src/IDLRPC.jl @@ -1,4 +1,3 @@ - include("idl_types.jl") include("common-funcs.jl") include("common-macros.jl") @@ -14,32 +13,30 @@ RPCclient(ptr::Ptr{Nothing}) = RPCclient(ptr, nothing) pclient = RPCclient() function rpc_init() - ccall((:IDL_RPCInit, idlrpc), Ptr{Nothing}, (Clong, Ptr{UInt8}), 0, C_NULL) + ccall((:IDL_RPCInit, libidl_rpc), Ptr{Nothing}, (Clong, Ptr{UInt8}), 0, C_NULL) end function rpc_cleanup() - ecode = ccall((:IDL_RPCCleanup, idlrpc), Cint, (Ptr{Nothing}, Cint), pclient.ptr, 0) - if ecode != 1 - error("IDL.exit: failed") - end + ecode = ccall((:IDL_RPCCleanup, libidl_rpc), Cint, (Ptr{Nothing}, Cint), pclient.ptr, 0) + ecode != 1 && error("IDL.exit: failed") if pclient.process != nothing kill(pclient.process) end return end -function init() +function __init__() olderr = stderr - (rd, wr) = redirect_stderr() #Redirect error messages + (rd, wr) = redirect_stderr() # Redirect error messages ptr = rpc_init() - if ptr != C_NULL #Check if idlrpc is already running + if ptr != C_NULL # Check if idlrpc is already running global pclient = RPCclient(ptr) - else #Start up idlrpc - print("Initializing IDL ") - proc = spawn(`idlrpc`) + else # Start up idlrpc + println("Initializing IDL") + run(`$idlrpc`, wait=false) ptr = C_NULL cnt = 0 - while ptr == C_NULL && cnt < 60 #Allow for startup time + while ptr == C_NULL && cnt < 60 # Allow for startup time ptr = rpc_init() cnt = cnt + 1 sleep(1) @@ -49,19 +46,19 @@ function init() ptr == C_NULL && error("IDL.init: IDLRPC init failed") global pclient = RPCclient(ptr, proc) end - capture(true) + capture(true) # Capture output from IDL redirect_stderr(olderr) - #Register cleanup function to be called at exit + # Register cleanup function to be called at exit atexit(rpc_cleanup) end function execute_converted(str::AbstractString) # does no conversion of interpolated vars, continuation chars, or newlines - ecode = ccall((:IDL_RPCExecuteStr, idlrpc), Cint, (Ptr{Nothing},Ptr{UInt8}), pclient.ptr, str) + ecode = ccall((:IDL_RPCExecuteStr, libidl_rpc), Cint, (Ptr{Nothing},Ptr{UInt8}), pclient.ptr, str) if ecode != 1 # since error get printed by IDL, we just reset error state - ecode = ccall((:IDL_RPCExecuteStr, idlrpc), Cint, (Ptr{Nothing},Ptr{UInt8}), pclient.ptr, - "message, /RESET") + ecode = ccall((:IDL_RPCExecuteStr, libidl_rpc), Cint, (Ptr{Nothing},Ptr{UInt8}), pclient.ptr, + "message, /RESET") flush() return false end @@ -71,16 +68,14 @@ end function capture(flag::Bool) nlines = flag ? 5000 : 0 - ecode = ccall((:IDL_RPCOutputCapture, idlrpc), Cint, (Ptr{Nothing}, Cint), pclient.ptr, nlines) - if ecode != 1 - error("IDL.capture: IDL_RPCOutputCapture failed") - end + ecode = ccall((:IDL_RPCOutputCapture, libidl_rpc), Cint, (Ptr{Nothing}, Cint), pclient.ptr, nlines) + (ecode != 1) && error("IDL.capture: IDL_RPCOutputCapture failed") return nothing end function get_output!(line_s::IDL_RPC_LINE_S) - ecode = ccall((:IDL_RPCOutputGetStr, idlrpc), Cint, (Ptr{Nothing},Ref{IDL_RPC_LINE_S},Cint), - pclient.ptr, line_s, 0) + ecode = ccall((:IDL_RPCOutputGetStr, libidl_rpc), Cint, (Ptr{Nothing},Ref{IDL_RPC_LINE_S},Cint), + pclient.ptr, line_s, 0) ecode == 1 ? true : false end @@ -95,7 +90,7 @@ function flush() end end -# no free_cb needed in idlrpc (I think) +# no free_cb needed in libidl_rpc (I think) free_cb = C_NULL # NOTE: Put_var makes a copy of the data in the array when it is put into idlrpc process. @@ -108,15 +103,12 @@ function put_var(arr::Array{T,N}, name::AbstractString) where {T,N} end dim = zeros(Int, IDL_MAX_ARRAY_DIM) dim[1:N] = [size(arr)...] - vptr = ccall((:IDL_RPCImportArray, idlrpc), Ptr{IDL_Variable}, - (Cint, IDL_ARRAY_DIM, Cint, Ptr{T}, IDL_ARRAY_FREE_CB), + vptr = ccall((:IDL_RPCImportArray, libidl_rpc), Ptr{IDL_Variable}, + (Cint, IDL_ARRAY_DIM, Cint, Ptr{T}, IDL_ARRAY_FREE_CB), N, dim, idl_type(arr), arr, free_cb) - ecode = ccall((:IDL_RPCSetVariable, idlrpc), Cint, - (Ptr{Nothing}, Ptr{UInt8}, Ptr{IDL_Variable}), - pclient.ptr, name, vptr) - if ecode != 1 - error("IDL.put_var: failed") - end + ecode = ccall((:IDL_RPCSetVariable, libidl_rpc), Cint, + (Ptr{Nothing}, Ptr{UInt8}, Ptr{IDL_Variable}), pclient.ptr, name, vptr) + ecode != 1 && error("IDL.put_var: failed") return end @@ -140,12 +132,11 @@ function put_var(x, name::AbstractString) error("IDL.put_var: only works with some vars containing bits types") end vptr = get_vptr(name) - ccall((:IDL_RPCStoreScalar, idlrpc), Nothing, - (Ptr{IDL_Variable}, Cint, Ref{UInt128}), + ccall((:IDL_RPCStoreScalar, libidl_rpc), Nothing, + (Ptr{IDL_Variable}, Cint, Ref{UInt128}), vptr, idl_type(x), Ref{UInt128}(convert(UInt128,reinterpret(uint_size(x),x)))) - ecode = ccall((:IDL_RPCSetVariable, idlrpc), Cint, - (Ptr{Nothing}, Ptr{UInt8}, Ptr{IDL_Variable}), - pclient.ptr, name, vptr) + ecode = ccall((:IDL_RPCSetVariable, libidl_rpc), Cint, + (Ptr{Nothing}, Ptr{UInt8}, Ptr{IDL_Variable}), pclient.ptr, name, vptr) return end @@ -157,12 +148,10 @@ function put_var(x::Complex{T}, name::AbstractString) where {T} y = (convert(UInt128, reinterpret(UInt32, imag(x))) << 32) + reinterpret(UInt32, real(x)) end vptr = get_vptr(name) - ccall((:IDL_RPCStoreScalar, idlrpc), Nothing, - (Ptr{IDL_Variable}, Cint, Ref{UInt128}), - vptr, idl_type(x), Ref{UInt128}(y)) - ecode = ccall((:IDL_RPCSetVariable, idlrpc), Cint, - (Ptr{Nothing}, Ptr{UInt8}, Ptr{IDL_Variable}), - pclient.ptr, name, vptr) + ccall((:IDL_RPCStoreScalar, libidl_rpc), Nothing, + (Ptr{IDL_Variable}, Cint, Ref{UInt128}), vptr, idl_type(x), Ref{UInt128}(y)) + ecode = ccall((:IDL_RPCSetVariable, libidl_rpc), Cint, + (Ptr{Nothing}, Ptr{UInt8}, Ptr{IDL_Variable}), pclient.ptr, name, vptr) return end @@ -174,30 +163,27 @@ end function put_var(str::AbstractString, name::AbstractString) idl_string = IDL_String() - ccall((:IDL_RPCStrStore, idlrpc), Nothing, (Ptr{IDL_String}, Ptr{Cchar}), - idl_string, str) - ecode = ccall((:IDL_RPCSetVariable, idlrpc), Cint, - (Ptr{Nothing}, Ptr{UInt8}, Ptr{IDL_Variable}), - pclient.ptr, name, vptr) - if ecode != 1 - error("IDL.put_var: failed") - end + ccall((:IDL_RPCStrStore, libidl_rpc), Nothing, (Ptr{IDL_String}, Ptr{Cchar}), + idl_string, str) + ecode = ccall((:IDL_RPCSetVariable, libidl_rpc), Cint, + (Ptr{Nothing}, Ptr{UInt8}, Ptr{IDL_Variable}), pclient.ptr, name, vptr) + ecode != 1 && error("IDL.put_var: failed") end function get_name(vptr::Ptr{IDL_Variable}) # not implemented for RPC - str = ccall((:IDL_RPCVarName, idlrpc), Ptr{Cchar}, (Ptr{IDL_Variable},), vptr) + str = ccall((:IDL_RPCVarName, libidl_rpc), Ptr{Cchar}, (Ptr{IDL_Variable},), vptr) return unsafe_string(str) end function get_vptr(name::AbstractString) # returns C_NULL if name not in scope - ccall((:IDL_RPCGetMainVariable, idlrpc), Ptr{IDL_Variable}, (Ptr{Nothing},Ptr{UInt8}), + ccall((:IDL_RPCGetMainVariable, libidl_rpc), Ptr{IDL_Variable}, (Ptr{Nothing},Ptr{UInt8}), pclient.ptr, name) end function get_var(name::AbstractString) - vptr = ccall((:IDL_RPCGetMainVariable, idlrpc), Ptr{IDL_Variable}, (Ptr{Nothing},Ptr{UInt8}), + vptr = ccall((:IDL_RPCGetMainVariable, libidl_rpc), Ptr{IDL_Variable}, (Ptr{Nothing},Ptr{UInt8}), pclient.ptr, name) # NOTE: IDL_RPCGetVariable never seems to return NULL in spite of docs if vptr == C_NULL @@ -205,6 +191,6 @@ function get_var(name::AbstractString) end var = get_var(vptr, name) # not sure if this is needed? - vptr = ccall((:IDL_RPCDeltmp, idlrpc), Nothing, (Ptr{IDL_Variable},), vptr) + vptr = ccall((:IDL_RPCDeltmp, libidl_rpc), Nothing, (Ptr{IDL_Variable},), vptr) var end From af7f327e359c216b54081606aacc60ac99582293 Mon Sep 17 00:00:00 2001 From: hyzhou Date: Fri, 14 Feb 2020 17:58:11 -0500 Subject: [PATCH 10/38] Added Project.toml file. --- Project.toml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 Project.toml diff --git a/Project.toml b/Project.toml new file mode 100644 index 0000000..e91686e --- /dev/null +++ b/Project.toml @@ -0,0 +1,4 @@ +name = "IDL" +uuid = "d8fbff9c-ffdd-4f12-b08d-aa41cc43ce74" +authors = ["Bob Portmann ", "Hongyang Zhou "] +version = "0.1.0" From 33a5d9b4e6f37b390c7d0e7740c08e1fde2e147a Mon Sep 17 00:00:00 2001 From: hyzhou Date: Fri, 14 Feb 2020 18:13:50 -0500 Subject: [PATCH 11/38] Added Manifest.toml file. --- Manifest.toml | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 Manifest.toml diff --git a/Manifest.toml b/Manifest.toml new file mode 100644 index 0000000..ac58105 --- /dev/null +++ b/Manifest.toml @@ -0,0 +1,33 @@ +# This file is machine-generated - editing it directly is not advised + +[[Base64]] +uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" + +[[Distributed]] +deps = ["Random", "Serialization", "Sockets"] +uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b" + +[[InteractiveUtils]] +deps = ["Markdown"] +uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" + +[[Logging]] +uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" + +[[Markdown]] +deps = ["Base64"] +uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" + +[[Random]] +deps = ["Serialization"] +uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" + +[[Serialization]] +uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" + +[[Sockets]] +uuid = "6462fe0b-24de-5631-8697-dd941f90decc" + +[[Test]] +deps = ["Distributed", "InteractiveUtils", "Logging", "Random"] +uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" From fd7926ee570f7f7fbc34110c85bf941c29874b6f Mon Sep 17 00:00:00 2001 From: hyzhou Date: Fri, 14 Feb 2020 18:15:30 -0500 Subject: [PATCH 12/38] First working test. --- test/runtests.jl | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index 7f2e4c1..c5aa7dd 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,5 +1,13 @@ -using IDLCall -using Base.Test +using IDL, Test -# write your own tests here -@test 1 == 1 +execute("a = 1") +help() +execute("a += 1") +a = get_var("a") +@test a == 2 +# If you don't say reset(), rpc will remember everything, even in the next call! +IDL.reset() + + +# Why is this not working? +#execute("1+1") From a2b158a552aeac013ed36edf47861f4c77ec1266 Mon Sep 17 00:00:00 2001 From: hyzhou Date: Fri, 14 Feb 2020 18:16:13 -0500 Subject: [PATCH 13/38] Add Test as extra dependency. --- Project.toml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index e91686e..3c774fb 100644 --- a/Project.toml +++ b/Project.toml @@ -1,4 +1,10 @@ name = "IDL" uuid = "d8fbff9c-ffdd-4f12-b08d-aa41cc43ce74" -authors = ["Bob Portmann ", "Hongyang Zhou "] +authors = ["Bob Portmann", "Hongyang Zhou "] version = "0.1.0" + +[extras] +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[targets] +test = ["Test"] From c8b3b94e0e6b2293b0bf9cc428ec32f890d75faa Mon Sep 17 00:00:00 2001 From: hyzhou Date: Fri, 14 Feb 2020 18:18:06 -0500 Subject: [PATCH 14/38] Updated. --- README.md | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 6150657..7e0d033 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,24 @@ # IDL interface for the Julia language -[![Build Status](https://travis-ci.org/BobPortmann/IDLCall.jl.svg?branch=master)](https://travis-ci.org/BobPortmann/IDLCall.jl) +[![Build Status](https://travis-ci.org/BobPortmann/`IDL.jl`.jl.svg?branch=master)](https://travis-ci.org/BobPortmann/`IDL.jl`.jl) -IDLCall is an interface to call IDL from the Julia language. Note that you must have a valid IDL -license to use IDL from julia. +The `IDL.jl` package is an interface for calling IDL from the Julia language. You must have a valid IDL license to use IDL from Julia. ## Installation Within Julia, use the package manager: ```julia -Pkg.clone("https://github.com/BobPortmann/IDLCall.jl.git") +Pkg.clone("https://github.com/BobPortmann/IDL.jl.git") ``` -IDLCall should find and load the IDL library automatically on Mac and Linux. It has not been +`IDL.jl` should find and load the IDL library automatically on Mac and Linux. It has not been tested on Windows so please file an issue if you use Windows and want to help make it work. IDL can be called using either the `RPC` or `Callable` interface. On windows only the `Callable` interface is available. You can set an environmental variable `JL_IDL_TYPE` to `RPC` or `CALLABLE` -to force the use of that interface. -Alternatively you can set `ENV["JL_IDL_TYPE"]` within julia before starting IDLCall. -Note that by default IDLCall uses the `RPC` interface -on Mac and Linux and `Callable` on Windows. The biggest difference between these is that: +to force the use of that interface. +Alternatively you can set `ENV["JL_IDL_TYPE"]` within julia before starting `IDL.jl`. +Note that by default `IDL.jl` uses the `RPC` interface on Mac and Linux and `Callable` on Windows. The biggest difference between these is that: - `Callable` IDL runs in one program space and thus arrays can be shared between julia and IDL. In `RPC` all arrays are copied between processes. Note that I have run into issues with IDL @@ -28,9 +26,9 @@ on Mac and Linux and `Callable` on Windows. The biggest difference between these - IDL `RPC` is not supported on windows -- `Callable` is always managed by IDLCall while `RPC` can be managed by IDLCall or the user. - By managed we mean that it is opened it when you load IDLCall and closed it when you close julia. - To manage `RPC` yourself run `idlrpc` in a shell before starting IDLCall. This allows the `idlrpc` +- `Callable` is always managed by `IDL.jl` while `RPC` can be managed by `IDL.jl` or the user. + By managed we mean that it is opened it when you load `IDL.jl` and closed it when you close julia. + To manage `RPC` yourself run `idlrpc` in a shell before starting `IDL.jl`. This allows the `idlrpc` session to persist and julia can be restarted without killing the `idlrpc` process. ## Quickstart @@ -38,19 +36,19 @@ on Mac and Linux and `Callable` on Windows. The biggest difference between these I recommend you start your code with ```julia -import IDLCall -idl = IDLCall +using IDL ``` -Then you can add a julia variable to the IDL process with +Then you can add a Julia variable to the IDL process with ``` -idl.put_var(x, "x") +x = 1 +put_var(x, "x") ``` -and you can retrieve variable into julia using +and you can retrieve variable into Julia using ``` -x = idl.get_var("x") +x = get_var("x") ``` You can run an arbitrary chunk of code in IDL using @@ -63,7 +61,7 @@ are not supported yet). ## REPL -You can drop into an IDL REPL by typing `>` at the julia prompt. Then you can type any valid +You can drop into an IDL REPL by typing `>` at the Julia prompt. Then you can type any valid IDL commands, including using continuation characters `$` for multi-line commands. One experimental feature I have added is the use of `%var` will auto-magically import the julia variable `var` into the IDL process. This works at the IDL prompt or in strings passed into the From 0eb33f7fead540c842895d667413e59233d24868 Mon Sep 17 00:00:00 2001 From: hyzhou Date: Sat, 15 Feb 2020 09:51:10 -0500 Subject: [PATCH 15/38] Simplify the line continuation part but won't work if [;\$] inside quotes; tried unsafe_wrap with copy. --- src/common-funcs.jl | 42 +++++++++++++++++------------------------- 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/src/common-funcs.jl b/src/common-funcs.jl index 941eb45..329cfea 100644 --- a/src/common-funcs.jl +++ b/src/common-funcs.jl @@ -12,9 +12,7 @@ dotrun(filename::AbstractString) = execute(".run $filename") function execute(str::AbstractString) ok, strarr, msg = convert_command(str) ok || error(msg) - println("start") execute_converted(strarr) - println("done") return nothing end @@ -76,8 +74,8 @@ function get_var(vptr::Ptr{IDL_Variable}, name::AbstractString="") parr = reinterpret(Ptr{IDL_Array}, convert(Int, var.buf)) idl_arr = unsafe_load(parr) pdata = reinterpret(Ptr{IDL_String}, idl_arr.data) - strarr = Array(Compat.ASCIIString, dims(idl_arr.dim, idl_arr.n_dim)) - for i=1:idl_arr.n_elts + strarr = Array{AbstractString}(dims(idl_arr.dim, idl_arr.n_dim)) + for i = 1:idl_arr.n_elts data = unsafe_load(pdata, i) strarr[i] = data.slen > 0 ? unsafe_string(data.s, Int(data.slen)) : "" end @@ -93,13 +91,15 @@ function get_var(vptr::Ptr{IDL_Variable}, name::AbstractString="") idl_arr = unsafe_load(parr) jl_t = jl_type(var.vtype) pdata = reinterpret(Ptr{jl_t}, idl_arr.data) - # not sure why this doesn't work - # arr = unsafe_wrap(Array, pdata, dims(idl_arr.dim, idl_arr.n_dim)) - arr = Array(jl_t, dims(idl_arr.dim, idl_arr.n_dim)) - for i=1:idl_arr.n_elts + arr = unsafe_wrap(Array, pdata, dims(idl_arr.dim, idl_arr.n_dim)) + #= + arr = Array{jl_t}(undef, dims(idl_arr.dim, idl_arr.n_dim)) + for i = 1:idl_arr.n_elts arr[i] = unsafe_load(pdata, i) end - return arr + =# + # If you don't copy, the pointer will be freed! + return copy(arr) end end @@ -150,7 +150,7 @@ end function inside_string(pt::Int, line::AbstractString) for re in (r"('[^']+')", r"(\"[^\"]+\")") for m in eachmatch(re, line) - if m.offset+endof(m.captures[1]) > pt ≥ m.offset + if m.offset+length(m.captures[1]) > pt ≥ m.offset return true end end @@ -160,27 +160,19 @@ end function convert_continuations(line) # remove trailing comments and continuation lines - # will remove continuation on final line which is invalid idl syntax - #pt = start(line) - pt = strip(line) - while (pt = findfirst(r";|\$", pt)) > 0 - if !inside_string(pt, line) - line = replace(line, r"(;|\$).*(\n|$)", "", 1) - end - if pt < endof(line) - pt = next(line, pt)[2] - end - end + # currently has issue with [;|\$] inside quotes! + line = replace(strip(line), r"(;|\$).*(\n|$)"=>"") + return true, line, "" end function convert_newlines(line) - # separates line at newline ("\n") characters into string array + # separates line at newline ('\n') characters into string array # assumes that continuation characters are already removed # not type stable but should not matter for repl use line = chomp(line) - if in('\n', line) - line = split(line, '\n', keep=false) + if '\n' in line + line = split(line, '\n', keepempty=false) end return line end @@ -202,7 +194,7 @@ end function convert_command(line) ok, line, msg = replace_interpolated_vars(line) ok || return ok, line, msg - #ok, line, msg = convert_continuations(line) # hyzhou: remove while testing + ok, line, msg = convert_continuations(line) # hyzhou: remove while testing ok || return ok, line, msg line = convert_newlines(line) return true, line, msg From 8781e4899cc4feaa44864ad8a4514d7caaa4827c Mon Sep 17 00:00:00 2001 From: hyzhou Date: Sat, 15 Feb 2020 09:51:31 -0500 Subject: [PATCH 16/38] syntax improvements. --- src/IDLRPC.jl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/IDLRPC.jl b/src/IDLRPC.jl index 67fe93c..fbde1be 100644 --- a/src/IDLRPC.jl +++ b/src/IDLRPC.jl @@ -69,7 +69,7 @@ end function capture(flag::Bool) nlines = flag ? 5000 : 0 ecode = ccall((:IDL_RPCOutputCapture, libidl_rpc), Cint, (Ptr{Nothing}, Cint), pclient.ptr, nlines) - (ecode != 1) && error("IDL.capture: IDL_RPCOutputCapture failed") + ecode != 1 && error("IDL.capture: IDL_RPCOutputCapture failed") return nothing end @@ -178,13 +178,13 @@ end function get_vptr(name::AbstractString) # returns C_NULL if name not in scope - ccall((:IDL_RPCGetMainVariable, libidl_rpc), Ptr{IDL_Variable}, (Ptr{Nothing},Ptr{UInt8}), - pclient.ptr, name) + ccall((:IDL_RPCGetMainVariable, libidl_rpc), Ptr{IDL_Variable}, + (Ptr{Nothing},Ptr{UInt8}), pclient.ptr, name) end function get_var(name::AbstractString) - vptr = ccall((:IDL_RPCGetMainVariable, libidl_rpc), Ptr{IDL_Variable}, (Ptr{Nothing},Ptr{UInt8}), - pclient.ptr, name) + vptr = ccall((:IDL_RPCGetMainVariable, libidl_rpc), Ptr{IDL_Variable}, + (Ptr{Nothing},Ptr{UInt8}), pclient.ptr, name) # NOTE: IDL_RPCGetVariable never seems to return NULL in spite of docs if vptr == C_NULL error("IDL.get_var: variable $name does not exist") From 4b1823a988f50953d9d8160e45f24166b9780c15 Mon Sep 17 00:00:00 2001 From: hyzhou Date: Sat, 15 Feb 2020 10:06:37 -0500 Subject: [PATCH 17/38] Add more tests. --- test/runtests.jl | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/test/runtests.jl b/test/runtests.jl index c5aa7dd..665cd23 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,10 +1,34 @@ using IDL, Test +# scalar passing execute("a = 1") help() execute("a += 1") a = get_var("a") @test a == 2 + +# string passing +line = """ +b = '1+1 ' +""" +execute(line) +b = get_var("b") +@test b == "1+1 " + +# array passing +a = [1,2,3] +put_var(a, "a") +execute("a += 1") +a = get_var("a") +@test a == [2,3,4] + + +# call function +line = """ +PRINT, 'HELLO WORLD!' +""" +execute(line) + # If you don't say reset(), rpc will remember everything, even in the next call! IDL.reset() From ce304bf124ef28edb2df8dfa6a942bd47907b914 Mon Sep 17 00:00:00 2001 From: hyzhou Date: Sat, 15 Feb 2020 10:08:31 -0500 Subject: [PATCH 18/38] Updated. --- README.md | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 7e0d033..e37af6d 100644 --- a/README.md +++ b/README.md @@ -33,31 +33,24 @@ Note that by default `IDL.jl` uses the `RPC` interface on Mac and Linux and `Cal ## Quickstart -I recommend you start your code with - ```julia using IDL ``` -Then you can add a Julia variable to the IDL process with - +You can add a Julia variable to the IDL process with ``` x = 1 put_var(x, "x") ``` - and you can retrieve variable into Julia using - ``` x = get_var("x") ``` - You can run an arbitrary chunk of code in IDL using - ``` idl.execute("any valid idl code") ``` Note that only primitive data types are supported at this time (e.g., structure variables -are not supported yet). +are not supported yet). Also, `[;|\$]` inside quotes won't be correctly recognized. ## REPL @@ -69,8 +62,6 @@ variable `var` into the IDL process. This works at the IDL prompt or in strings ## ToDo -- Add tests - - Make more flexible to install on all platforms - Add more variable types to be transferred between julia and IDL. From 7bda91c3600bf624cea999623eed3968384a19e4 Mon Sep 17 00:00:00 2001 From: hyzhou Date: Sat, 15 Feb 2020 10:08:49 -0500 Subject: [PATCH 19/38] isbits->isbitstype --- src/IDLRPC.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/IDLRPC.jl b/src/IDLRPC.jl index fbde1be..deb793e 100644 --- a/src/IDLRPC.jl +++ b/src/IDLRPC.jl @@ -98,14 +98,14 @@ free_cb = C_NULL # I think the difference is because callable idl runs in the same process but # idlrpc does not. Thus, no free_cb is needed in idlrpc version. function put_var(arr::Array{T,N}, name::AbstractString) where {T,N} - if !isbits(eltype(arr)) || (idl_type(arr) < 0) + if !isbitstype(eltype(arr)) || (idl_type(arr) < 0) error("IDL.put_var: only works with some vars containing bits types") end dim = zeros(Int, IDL_MAX_ARRAY_DIM) dim[1:N] = [size(arr)...] vptr = ccall((:IDL_RPCImportArray, libidl_rpc), Ptr{IDL_Variable}, (Cint, IDL_ARRAY_DIM, Cint, Ptr{T}, IDL_ARRAY_FREE_CB), - N, dim, idl_type(arr), arr, free_cb) + N, dim, idl_type(arr), arr, free_cb) ecode = ccall((:IDL_RPCSetVariable, libidl_rpc), Cint, (Ptr{Nothing}, Ptr{UInt8}, Ptr{IDL_Variable}), pclient.ptr, name, vptr) ecode != 1 && error("IDL.put_var: failed") From 2841eea0ff16691bcb8789d13a1739738b874e27 Mon Sep 17 00:00:00 2001 From: hyzhou Date: Sat, 15 Feb 2020 18:42:58 -0500 Subject: [PATCH 20/38] First working version in Julia 1.3 --- src/IDLREPL.jl | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/IDLREPL.jl b/src/IDLREPL.jl index 3c7ce1d..9156921 100644 --- a/src/IDLREPL.jl +++ b/src/IDLREPL.jl @@ -1,15 +1,16 @@ -import Base: LineEdit, REPL +import REPL:respond, LineEdit, mode_keymap +import Base:active_repl, text_colors function idl_repl() # Setup idl prompt prompt = LineEdit.Prompt("IDL> "; - prompt_prefix=Base.text_colors[:blue], - prompt_suffix=Base.text_colors[:white]) + prompt_prefix=text_colors[:blue], + prompt_suffix=text_colors[:white]) - repl = Base.active_repl + repl = active_repl - prompt.on_done = REPL.respond(repl,prompt) do line + prompt.on_done = respond(repl,prompt) do line ok2, line, msg = convert_continuations(line) if !ok2 println(msg) @@ -54,20 +55,21 @@ function idl_repl() end) search_prompt, skeymap = LineEdit.setup_search_keymap(hp) - mk = REPL.mode_keymap(main_mode) + mk = mode_keymap(main_mode) - b = Dict{Any,Any}[skeymap, mk, LineEdit.history_keymap, LineEdit.default_keymap, - LineEdit.escape_defaults] + b = Dict{Any,Any}[skeymap, mk, LineEdit.history_keymap, + LineEdit.default_keymap, LineEdit.escape_defaults] prompt.keymap_dict = LineEdit.keymap(b) - main_mode.keymap_dict = LineEdit.keymap_merge(main_mode.keymap_dict, idl_keymap) + main_mode.keymap_dict = LineEdit.keymap_merge(main_mode.keymap_dict, + idl_keymap) nothing end function find_prompt_in_modes(modes, name) j = -1 for (i,mode) in enumerate(modes) - if :prompt in fieldnames(mode) && mode.prompt == name + if :prompt in fieldnames(typeof(mode)) && mode.prompt == name j = i break end From cc41578de661866a01c2feeea499929a1b6111d7 Mon Sep 17 00:00:00 2001 From: hyzhou Date: Sun, 16 Feb 2020 01:36:00 -0500 Subject: [PATCH 21/38] Indentation adjustment. --- src/common-macros.jl | 76 +++++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 39 deletions(-) diff --git a/src/common-macros.jl b/src/common-macros.jl index 673f20e..f196dbd 100644 --- a/src/common-macros.jl +++ b/src/common-macros.jl @@ -1,60 +1,58 @@ - # These routines were modified from similar routines in MATLAB.jl # E.G., @mput, @mget, _mput_multi, _mget_multi, make_getvar_statement function put_var_multi(vs::Symbol...) - nv = length(vs) - if nv == 1 - v = vs[1] - :(put_var($(v), string($(Meta.quot(v))))) - else - stmts = Array(Expr, nv) - for i = 1:nv - v = vs[i] - stmts[i] = :(put_var($(v), string($(Meta.quot(v))))) - end - Expr(:block, stmts...) - end + nv = length(vs) + if nv == 1 + v = vs[1] + :(put_var($(v), string($(Meta.quot(v))))) + else + stmts = Array(Expr, nv) + for i = 1:nv + v = vs[i] + stmts[i] = :(put_var($(v), string($(Meta.quot(v))))) + end + Expr(:block, stmts...) + end end macro put_var(vs...) - esc(put_var_multi(vs...)) + esc(put_var_multi(vs...)) end function make_getvar_statement(v::Symbol) - :($(v) = get_var(string($(Meta.quot(v))))) + :($(v) = get_var(string($(Meta.quot(v))))) end function make_getvar_statement(ex::Expr) - if !(ex.head == :(=)) - if ex.head == :kw - error("Must call @get_var without parenthesis if using statements") - else + if !(ex.head == :(=)) + if ex.head == :kw + error("Must call @get_var without parenthesis if using statements") + else erorr("Invalid expression for @get_var: " * string(ex)) - end - end - v::Symbol = ex.args[1] - k::Symbol = ex.args[2] - :($(v) = get_var(string($(Meta.quot(k))))) + end + end + v::Symbol = ex.args[1] + k::Symbol = ex.args[2] + :($(v) = get_var(string($(Meta.quot(k))))) + end end function get_var_multi(vs::Union{Symbol, Expr}...) - # NOTE: I supressed output by adding :nothing - nv = length(vs) - if nv == 1 - stmt = make_getvar_statement(vs[1]) - Expr(:block, stmt, :nothing) - else - stmts = Array(Expr, nv) - for i = 1:nv - stmts[i] = make_getvar_statement(vs[i]) - end - Expr(:block, stmts..., :nothing) - end + # supress output by adding :nothing + nv = length(vs) + if nv == 1 + stmt = make_getvar_statement(vs[1]) + Expr(:block, stmt, :nothing) + else + stmts = Array(Expr, nv) + for i = 1:nv + stmts[i] = make_getvar_statement(vs[i]) + end + Expr(:block, stmts..., :nothing) + end end macro get_var(vs...) - esc(get_var_multi(vs...)) + esc(get_var_multi(vs...)) end - -# END: routines modified from similar routines in MATLAB.jl From d4dbeb8361a4f7e7442fbd59244d71b899e96c18 Mon Sep 17 00:00:00 2001 From: hyzhou Date: Sun, 16 Feb 2020 01:36:22 -0500 Subject: [PATCH 22/38] Add REPL as dependency. --- Manifest.toml | 20 +++----------------- Project.toml | 3 +++ 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/Manifest.toml b/Manifest.toml index ac58105..d2e0d53 100644 --- a/Manifest.toml +++ b/Manifest.toml @@ -3,31 +3,17 @@ [[Base64]] uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" -[[Distributed]] -deps = ["Random", "Serialization", "Sockets"] -uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b" - [[InteractiveUtils]] deps = ["Markdown"] uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" -[[Logging]] -uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" - [[Markdown]] deps = ["Base64"] uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" -[[Random]] -deps = ["Serialization"] -uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" - -[[Serialization]] -uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" +[[REPL]] +deps = ["InteractiveUtils", "Markdown", "Sockets"] +uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" [[Sockets]] uuid = "6462fe0b-24de-5631-8697-dd941f90decc" - -[[Test]] -deps = ["Distributed", "InteractiveUtils", "Logging", "Random"] -uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/Project.toml b/Project.toml index 3c774fb..d62e630 100644 --- a/Project.toml +++ b/Project.toml @@ -3,6 +3,9 @@ uuid = "d8fbff9c-ffdd-4f12-b08d-aa41cc43ce74" authors = ["Bob Portmann", "Hongyang Zhou "] version = "0.1.0" +[deps] +REPL = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" + [extras] Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" From e94b93a8b12cc983bfaf3096b061e04dd157d860 Mon Sep 17 00:00:00 2001 From: hyzhou Date: Sun, 16 Feb 2020 01:37:32 -0500 Subject: [PATCH 23/38] Moved the init function one level up. --- src/IDLRPC.jl | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/src/IDLRPC.jl b/src/IDLRPC.jl index deb793e..be13cb0 100644 --- a/src/IDLRPC.jl +++ b/src/IDLRPC.jl @@ -25,33 +25,6 @@ function rpc_cleanup() return end -function __init__() - olderr = stderr - (rd, wr) = redirect_stderr() # Redirect error messages - ptr = rpc_init() - if ptr != C_NULL # Check if idlrpc is already running - global pclient = RPCclient(ptr) - else # Start up idlrpc - println("Initializing IDL") - run(`$idlrpc`, wait=false) - ptr = C_NULL - cnt = 0 - while ptr == C_NULL && cnt < 60 # Allow for startup time - ptr = rpc_init() - cnt = cnt + 1 - sleep(1) - print(".") - end - println("") - ptr == C_NULL && error("IDL.init: IDLRPC init failed") - global pclient = RPCclient(ptr, proc) - end - capture(true) # Capture output from IDL - redirect_stderr(olderr) - # Register cleanup function to be called at exit - atexit(rpc_cleanup) -end - function execute_converted(str::AbstractString) # does no conversion of interpolated vars, continuation chars, or newlines ecode = ccall((:IDL_RPCExecuteStr, libidl_rpc), Cint, (Ptr{Nothing},Ptr{UInt8}), pclient.ptr, str) From 0accb4ef464aa5667c7907cc5ed34da59ad29f80 Mon Sep 17 00:00:00 2001 From: hyzhou Date: Sun, 16 Feb 2020 01:38:46 -0500 Subject: [PATCH 24/38] Focus on RPC for now; correctly handle IDL directories; move __init__() function here. --- src/IDL.jl | 48 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/src/IDL.jl b/src/IDL.jl index 172845d..6389636 100644 --- a/src/IDL.jl +++ b/src/IDL.jl @@ -1,23 +1,65 @@ module IDL -export get_var, put_var, execute +export get_var, put_var, @get_var, @put_var, execute export help # Find IDL library directory if on Linux if Sys.isunix() - IDL_LIB_DIR = "/Applications/exelis/idl85/bin/bin.darwin.x86_64" + IDL_EXEC = chomp(read(`which idl`,String)) + if islink(IDL_EXEC) + IDL_DIR = dirname(readlink(IDL_EXEC)) + else + IDL_DIR = dirname(IDL_EXEC) + end + IDL_LIB_DIR = joinpath(IDL_DIR,"bin.darwin.x86_64") const libidl_rpc = joinpath(IDL_LIB_DIR,"libidl_rpc.dylib") - const idlrpc = "/Applications/exelis/idl85/bin/idlrpc" + const idlrpc = joinpath(IDL_DIR,"idlrpc") else # Windows const idlcall = "libidl" const idlrpc = "libidl_rpc" end +#= jl_idl_type = get(ENV, "JL_IDL_TYPE", Sys.iswindows() ? "CALLABLE" : "RPC") jl_idl_type == "RPC" ? include("IDLRPC.jl") : jl_idl_type == "CALLABLE" ? include("IDLCallable.jl") : Sys.iswindows() ? error("JL_IDL_TYPE must be CALLABLE on windows") : error("JL_IDL_TYPE must be RPC or CALLABLE") +=# + +include("IDLRPC.jl") +include("IDLREPL.jl") + +function __init__() + # Initializing RPC + olderr = stderr + (rd, wr) = redirect_stderr() # Redirect error messages + ptr = rpc_init() + if ptr != C_NULL # Check if idlrpc is already running + global pclient = RPCclient(ptr) + else # Start up idlrpc + println("Initializing IDL") + run(`$idlrpc`, wait=false) + ptr = C_NULL + cnt = 0 + while ptr == C_NULL && cnt < 60 # Allow for startup time + ptr = rpc_init() + cnt = cnt + 1 + sleep(1) + print(".") + end + println("") + ptr == C_NULL && error("IDL.init: IDLRPC init failed") + global pclient = RPCclient(ptr, proc) + end + capture(true) # Capture output from IDL + redirect_stderr(olderr) + # Register cleanup function to be called at exit + atexit(rpc_cleanup) + + # Initializing REPL + idl_repl() +end end From 4bcdb81d36fb0fb8f4e4e590f1d41f72357f6fa0 Mon Sep 17 00:00:00 2001 From: hyzhou Date: Sun, 16 Feb 2020 01:40:20 -0500 Subject: [PATCH 25/38] Updated. --- README.md | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index e37af6d..76f4d7d 100644 --- a/README.md +++ b/README.md @@ -11,12 +11,9 @@ Within Julia, use the package manager: Pkg.clone("https://github.com/BobPortmann/IDL.jl.git") ``` -`IDL.jl` should find and load the IDL library automatically on Mac and Linux. It has not been -tested on Windows so please file an issue if you use Windows and want to help make it work. +`IDL.jl` should find and load the IDL library automatically on Mac and Linux. It has not been tested on Windows so please file an issue if you use Windows and want to help make it work. -IDL can be called using either the `RPC` or `Callable` interface. On windows only the `Callable` -interface is available. You can set an environmental variable `JL_IDL_TYPE` to `RPC` or `CALLABLE` -to force the use of that interface. +IDL can be called using either the `RPC` or `Callable` interface. On windows only the `Callable` interface is available. You can set an environmental variable `JL_IDL_TYPE` to `RPC` or `CALLABLE` to force the use of that interface. Alternatively you can set `ENV["JL_IDL_TYPE"]` within julia before starting `IDL.jl`. Note that by default `IDL.jl` uses the `RPC` interface on Mac and Linux and `Callable` on Windows. The biggest difference between these is that: @@ -49,16 +46,11 @@ You can run an arbitrary chunk of code in IDL using ``` idl.execute("any valid idl code") ``` -Note that only primitive data types are supported at this time (e.g., structure variables -are not supported yet). Also, `[;|\$]` inside quotes won't be correctly recognized. +Note that only primitive data types are supported at this time (e.g., structure variables are not supported yet). Also, `[;|\$]` inside quotes won't be correctly recognized. ## REPL -You can drop into an IDL REPL by typing `>` at the Julia prompt. Then you can type any valid -IDL commands, including using continuation characters `$` for multi-line commands. One -experimental feature I have added is the use of `%var` will auto-magically import the julia -variable `var` into the IDL process. This works at the IDL prompt or in strings passed into the -`execute` function. +You can drop into an IDL REPL by typing `>` at the Julia prompt. Then you can type any valid IDL commands, including using continuation characters `$` for multi-line commands. One experimental feature I have added is the use of `%var` will auto-magically import the Julia variable `var` into the IDL process. This works at the IDL prompt or in strings passed into the `execute` function. ## ToDo From 1ce8e372d199457453dffe77dddeb5c11f7a1237 Mon Sep 17 00:00:00 2001 From: hyzhou Date: Sun, 16 Feb 2020 10:36:51 -0500 Subject: [PATCH 26/38] Rewind to 4 whitespaces. --- src/IDL.jl | 76 +++++------ src/IDLCallable.jl | 135 ++++++++++--------- src/IDLREPL.jl | 120 +++++++++-------- src/IDLRPC.jl | 200 ++++++++++++++-------------- src/common-funcs.jl | 308 +++++++++++++++++++++---------------------- src/common-macros.jl | 76 +++++------ src/idl_types.jl | 184 +++++++++++++------------- 7 files changed, 548 insertions(+), 551 deletions(-) diff --git a/src/IDL.jl b/src/IDL.jl index 6389636..ead091f 100644 --- a/src/IDL.jl +++ b/src/IDL.jl @@ -5,18 +5,18 @@ export help # Find IDL library directory if on Linux if Sys.isunix() - IDL_EXEC = chomp(read(`which idl`,String)) - if islink(IDL_EXEC) - IDL_DIR = dirname(readlink(IDL_EXEC)) - else - IDL_DIR = dirname(IDL_EXEC) - end - IDL_LIB_DIR = joinpath(IDL_DIR,"bin.darwin.x86_64") - const libidl_rpc = joinpath(IDL_LIB_DIR,"libidl_rpc.dylib") - const idlrpc = joinpath(IDL_DIR,"idlrpc") + IDL_EXEC = chomp(read(`which idl`,String)) + if islink(IDL_EXEC) + IDL_DIR = dirname(readlink(IDL_EXEC)) + else + IDL_DIR = dirname(IDL_EXEC) + end + IDL_LIB_DIR = joinpath(IDL_DIR,"bin.darwin.x86_64") + const libidl_rpc = joinpath(IDL_LIB_DIR,"libidl_rpc.dylib") + const idlrpc = joinpath(IDL_DIR,"idlrpc") else # Windows - const idlcall = "libidl" - const idlrpc = "libidl_rpc" + const idlcall = "libidl" + const idlrpc = "libidl_rpc" end #= @@ -32,34 +32,34 @@ include("IDLRPC.jl") include("IDLREPL.jl") function __init__() - # Initializing RPC - olderr = stderr - (rd, wr) = redirect_stderr() # Redirect error messages - ptr = rpc_init() - if ptr != C_NULL # Check if idlrpc is already running - global pclient = RPCclient(ptr) - else # Start up idlrpc - println("Initializing IDL") - run(`$idlrpc`, wait=false) - ptr = C_NULL - cnt = 0 - while ptr == C_NULL && cnt < 60 # Allow for startup time - ptr = rpc_init() - cnt = cnt + 1 - sleep(1) - print(".") - end - println("") - ptr == C_NULL && error("IDL.init: IDLRPC init failed") - global pclient = RPCclient(ptr, proc) - end - capture(true) # Capture output from IDL - redirect_stderr(olderr) - # Register cleanup function to be called at exit - atexit(rpc_cleanup) + # Initializing RPC + olderr = stderr + (rd, wr) = redirect_stderr() # Redirect error messages + ptr = rpc_init() + if ptr != C_NULL # Check if idlrpc is already running + global pclient = RPCclient(ptr) + else # Start up idlrpc + println("Initializing IDL") + run(`$idlrpc`, wait=false) + ptr = C_NULL + cnt = 0 + while ptr == C_NULL && cnt < 60 # Allow for startup time + ptr = rpc_init() + cnt = cnt + 1 + sleep(1) + print(".") + end + println("") + ptr == C_NULL && error("IDL.init: IDLRPC init failed") + global pclient = RPCclient(ptr, proc) + end + capture(true) # Capture output from IDL + redirect_stderr(olderr) + # Register cleanup function to be called at exit + atexit(rpc_cleanup) - # Initializing REPL - idl_repl() + # Initializing REPL + idl_repl() end end diff --git a/src/IDLCallable.jl b/src/IDLCallable.jl index 4d429ce..919d40f 100644 --- a/src/IDLCallable.jl +++ b/src/IDLCallable.jl @@ -1,4 +1,3 @@ - include("idl_types.jl") include("common-funcs.jl") include("common-macros.jl") @@ -6,17 +5,17 @@ include("common-macros.jl") using Libdl if Sys.isapple() - cd(IDL_LIB_DIR) do - Libdl.dlopen("libidl") - end + cd(IDL_LIB_DIR) do + Libdl.dlopen("libidl") + end end function init() - ecode = ccall((:IDL_Init, idlcall), Cint, (Cint, Ptr{Cint}, Ptr{Ptr{UInt8}}), - 0, C_NULL, C_NULL) - ecode == 0 && error("IDL.init: IDL init failed") - global output_cb - ccall((:IDL_ToutPush, idlcall), Nothing, (Ptr{Nothing},), output_cb) + ecode = ccall((:IDL_Init, idlcall), Cint, (Cint, Ptr{Cint}, Ptr{Ptr{UInt8}}), + 0, C_NULL, C_NULL) + ecode == 0 && error("IDL.init: IDL init failed") + global output_cb + ccall((:IDL_ToutPush, idlcall), Nothing, (Ptr{Nothing},), output_cb) end # function execute{T<:AbstractString}(strarr::Array{T,1}) @@ -31,22 +30,22 @@ end # end function execute_converted(str::AbstractString) - # does no conversion of interpolated vars, continuation chars, or newlines - ecode = ccall((:IDL_ExecuteStr, idlcall), Cint, (Ptr{UInt8},), str) - if ecode != 0 - # since error get printed by IDL, we just reset error state - ecode = ccall((:IDL_ExecuteStr, idlcall), Cint, (Ptr{UInt8},), "message, /RESET") - end - return true + # does no conversion of interpolated vars, continuation chars, or newlines + ecode = ccall((:IDL_ExecuteStr, idlcall), Cint, (Ptr{UInt8},), str) + if ecode != 0 + # since error get printed by IDL, we just reset error state + ecode = ccall((:IDL_ExecuteStr, idlcall), Cint, (Ptr{UInt8},), "message, /RESET") + end + return true end function get_output(flags::Cint, buf::Ptr{UInt8}, n::Cint) - line = unsafe_string(buf, n) - stderr = (flags & IDL_TOUT_F_STDERR) != 0 - newline = (flags & IDL_TOUT_F_NLPOST) != 0 - if newline line = line*"\n" end - print(line) - return + line = unsafe_string(buf, n) + stderr = (flags & IDL_TOUT_F_STDERR) != 0 + newline = (flags & IDL_TOUT_F_NLPOST) != 0 + if newline line = line*"\n" end + print(line) + return end output_cb = @cfunction(get_output, Nothing, (Cint, Ptr{UInt8},Cint)) @@ -61,70 +60,70 @@ output_cb = @cfunction(get_output, Nothing, (Cint, Ptr{UInt8},Cint)) const var_refs = Dict{Ptr{UInt8}, Any}() function done_with_var(p::Ptr{UInt8}) - if !haskey(var_refs, p) - error("IDL.done_with_var: ptr not found: "*string(p)) - end - delete!(var_refs, p) - return + if !haskey(var_refs, p) + error("IDL.done_with_var: ptr not found: "*string(p)) + end + delete!(var_refs, p) + return end free_cb = @cfunction(done_with_var, Nothing, (Ptr{UInt8},)) function put_var(arr::Array{T,N}, name::AbstractString) where {T,N} - if !isbits(eltype(arr)) || (idl_type(arr) < 0) - error("IDL.put_var: only works with some vars containing bits types") - end - dim = zeros(Int, IDL_MAX_ARRAY_DIM) - dim[1:N] = [size(arr)...] - vptr = ccall((:IDL_ImportNamedArray, idlcall), Ptr{IDL_Variable}, - (Ptr{UInt8}, Cint, IDL_ARRAY_DIM, Cint, Ptr{UInt8}, IDL_ARRAY_FREE_CB , Ptr{Nothing}), - name, N, dim, idl_type(arr), pointer(arr), free_cb, C_NULL) - if vptr == C_NULL - error("IDL.put_var: failed") - end - var_refs[pointer(arr)] = (name, vptr, arr) - return + if !isbits(eltype(arr)) || (idl_type(arr) < 0) + error("IDL.put_var: only works with some vars containing bits types") + end + dim = zeros(Int, IDL_MAX_ARRAY_DIM) + dim[1:N] = [size(arr)...] + vptr = ccall((:IDL_ImportNamedArray, idlcall), Ptr{IDL_Variable}, + (Ptr{UInt8}, Cint, IDL_ARRAY_DIM, Cint, Ptr{UInt8}, IDL_ARRAY_FREE_CB , Ptr{Nothing}), + name, N, dim, idl_type(arr), pointer(arr), free_cb, C_NULL) + if vptr == C_NULL + error("IDL.put_var: failed") + end + var_refs[pointer(arr)] = (name, vptr, arr) + return end function put_var(x, name::AbstractString) - # Sort of a HACK: import as one-element array and then truncate to scalar - # IDL_ImportArray(int n_dim, IDL_MEMINT dim[], int type, - # UCHAR *data, IDL_ARRAY_FREE_CB free_cb, Nothing *s) - if !isbits(x) || (idl_type(x) < 0) - error("IDL.put_var: only works with some vars containing bits types") - end - dim = zeros(Int, IDL_MAX_ARRAY_DIM) - dim[1] = 1 - ccall((:IDL_ImportNamedArray, idlcall), Ptr{Nothing}, - (Ptr{UInt8}, Cint, Ptr{IDL_MEMINT}, Cint, Ptr{UInt8}, Ptr{Nothing}, Ptr{Nothing}), - name, 1, dim, idl_type(x), pointer([x]), C_NULL, C_NULL) - execute("$name = $name[0]") - return + # Sort of a HACK: import as one-element array and then truncate to scalar + # IDL_ImportArray(int n_dim, IDL_MEMINT dim[], int type, + # UCHAR *data, IDL_ARRAY_FREE_CB free_cb, Nothing *s) + if !isbits(x) || (idl_type(x) < 0) + error("IDL.put_var: only works with some vars containing bits types") + end + dim = zeros(Int, IDL_MAX_ARRAY_DIM) + dim[1] = 1 + ccall((:IDL_ImportNamedArray, idlcall), Ptr{Nothing}, + (Ptr{UInt8}, Cint, Ptr{IDL_MEMINT}, Cint, Ptr{UInt8}, Ptr{Nothing}, Ptr{Nothing}), + name, 1, dim, idl_type(x), pointer([x]), C_NULL, C_NULL) + execute("$name = $name[0]") + return end function put_var(str::AbstractString, name::AbstractString) - # Sort of a HACK: do direcly since ImportNamedArray doesn't work - execute("$name = '$str'") - return + # Sort of a HACK: do direcly since ImportNamedArray doesn't work + execute("$name = '$str'") + return end function get_name(vptr::Ptr{IDL_Variable}) - str = ccall((:IDL_VarName, idlcall), Ptr{Cchar}, (Ptr{IDL_Variable},), vptr) - return unsafe_string(str) + str = ccall((:IDL_VarName, idlcall), Ptr{Cchar}, (Ptr{IDL_Variable},), vptr) + return unsafe_string(str) end function get_vptr(name::AbstractString) - # returns C_NULL if name not in scope - name = uppercase(name) - vptr = ccall((:IDL_GetVarAddr, idlcall), Ptr{IDL_Variable}, (Ptr{UInt8},), name) - vptr + # returns C_NULL if name not in scope + name = uppercase(name) + vptr = ccall((:IDL_GetVarAddr, idlcall), Ptr{IDL_Variable}, (Ptr{UInt8},), name) + vptr end function get_var(name::AbstractString) - name = uppercase(name) - vptr = ccall((:IDL_GetVarAddr, idlcall), Ptr{IDL_Variable}, (Ptr{UInt8},), name) - if vptr == C_NULL - error("IDL.get_var: variable $name does not exist") - end - get_var(vptr) + name = uppercase(name) + vptr = ccall((:IDL_GetVarAddr, idlcall), Ptr{IDL_Variable}, (Ptr{UInt8},), name) + if vptr == C_NULL + error("IDL.get_var: variable $name does not exist") + end + get_var(vptr) end diff --git a/src/IDLREPL.jl b/src/IDLREPL.jl index 9156921..1d8498e 100644 --- a/src/IDLREPL.jl +++ b/src/IDLREPL.jl @@ -2,77 +2,75 @@ import REPL:respond, LineEdit, mode_keymap import Base:active_repl, text_colors function idl_repl() + # Setup idl prompt + prompt = LineEdit.Prompt("IDL> "; + prompt_prefix=text_colors[:blue], + prompt_suffix=text_colors[:white]) - # Setup idl prompt - prompt = LineEdit.Prompt("IDL> "; - prompt_prefix=text_colors[:blue], - prompt_suffix=text_colors[:white]) + repl = active_repl - repl = active_repl + prompt.on_done = respond(repl,prompt) do line + ok2, line, msg = convert_continuations(line) + if !ok2 + println(msg) + println() + return + end + ok2, line, msg = replace_interpolated_vars(line) + if !ok2 + println(msg) + println() + return + end + ec = execute_converted(line) + nothing + end - prompt.on_done = respond(repl,prompt) do line - ok2, line, msg = convert_continuations(line) - if !ok2 - println(msg) - println() - return - end - ok2, line, msg = replace_interpolated_vars(line) - if !ok2 - println(msg) - println() - return - end - ec = execute_converted(line) - nothing - end + main_mode = repl.interface.modes[1] - main_mode = repl.interface.modes[1] + # replace existing IDL REPL if present + i_mode = find_prompt_in_modes(repl.interface.modes, "IDL> ") + if i_mode < 1 + push!(repl.interface.modes,prompt) + else + repl.interface.modes[i_mode] = prompt + end - # replace existing IDL REPL if present - i_mode = find_prompt_in_modes(repl.interface.modes, "IDL> ") - if i_mode < 1 - push!(repl.interface.modes,prompt) - else - repl.interface.modes[i_mode] = prompt - end + hp = main_mode.hist + hp.mode_mapping[:idl] = prompt + prompt.hist = hp + idl_keymap = Dict{Any,Any}( + '>' => function (s,args...) + if isempty(s) + if !haskey(s.mode_state,prompt) + s.mode_state[prompt] = LineEdit.init_state(repl.t,prompt) + end + LineEdit.transition(s,prompt) + else + LineEdit.edit_insert(s,'>') + end +end) - hp = main_mode.hist - hp.mode_mapping[:idl] = prompt - prompt.hist = hp +search_prompt, skeymap = LineEdit.setup_search_keymap(hp) +mk = mode_keymap(main_mode) - idl_keymap = Dict{Any,Any}( - '>' => function (s,args...) - if isempty(s) - if !haskey(s.mode_state,prompt) - s.mode_state[prompt] = LineEdit.init_state(repl.t,prompt) - end - LineEdit.transition(s,prompt) - else - LineEdit.edit_insert(s,'>') - end - end) +b = Dict{Any,Any}[skeymap, mk, LineEdit.history_keymap, +LineEdit.default_keymap, LineEdit.escape_defaults] +prompt.keymap_dict = LineEdit.keymap(b) - search_prompt, skeymap = LineEdit.setup_search_keymap(hp) - mk = mode_keymap(main_mode) - - b = Dict{Any,Any}[skeymap, mk, LineEdit.history_keymap, - LineEdit.default_keymap, LineEdit.escape_defaults] - prompt.keymap_dict = LineEdit.keymap(b) - - main_mode.keymap_dict = LineEdit.keymap_merge(main_mode.keymap_dict, - idl_keymap) - nothing +main_mode.keymap_dict = LineEdit.keymap_merge(main_mode.keymap_dict, +idl_keymap) +nothing end function find_prompt_in_modes(modes, name) - j = -1 - for (i,mode) in enumerate(modes) - if :prompt in fieldnames(typeof(mode)) && mode.prompt == name - j = i - break - end - end - return j + j = -1 + for (i,mode) in enumerate(modes) + if :prompt in fieldnames(typeof(mode)) && mode.prompt == name + j = i + break + end + end + return j end diff --git a/src/IDLRPC.jl b/src/IDLRPC.jl index be13cb0..0dfbf55 100644 --- a/src/IDLRPC.jl +++ b/src/IDLRPC.jl @@ -4,8 +4,8 @@ include("common-macros.jl") # RPC client struct RPCclient - ptr::Ptr{Nothing} - process::Union{Nothing, Base.Process} + ptr::Ptr{Nothing} + process::Union{Nothing, Base.Process} end RPCclient() = RPCclient(C_NULL, nothing) RPCclient(ptr::Ptr{Nothing}) = RPCclient(ptr, nothing) @@ -13,54 +13,54 @@ RPCclient(ptr::Ptr{Nothing}) = RPCclient(ptr, nothing) pclient = RPCclient() function rpc_init() - ccall((:IDL_RPCInit, libidl_rpc), Ptr{Nothing}, (Clong, Ptr{UInt8}), 0, C_NULL) + ccall((:IDL_RPCInit, libidl_rpc), Ptr{Nothing}, (Clong, Ptr{UInt8}), 0, C_NULL) end function rpc_cleanup() - ecode = ccall((:IDL_RPCCleanup, libidl_rpc), Cint, (Ptr{Nothing}, Cint), pclient.ptr, 0) - ecode != 1 && error("IDL.exit: failed") - if pclient.process != nothing - kill(pclient.process) - end - return + ecode = ccall((:IDL_RPCCleanup, libidl_rpc), Cint, (Ptr{Nothing}, Cint), pclient.ptr, 0) + ecode != 1 && error("IDL.exit: failed") + if pclient.process != nothing + kill(pclient.process) + end + return end function execute_converted(str::AbstractString) - # does no conversion of interpolated vars, continuation chars, or newlines - ecode = ccall((:IDL_RPCExecuteStr, libidl_rpc), Cint, (Ptr{Nothing},Ptr{UInt8}), pclient.ptr, str) - if ecode != 1 - # since error get printed by IDL, we just reset error state - ecode = ccall((:IDL_RPCExecuteStr, libidl_rpc), Cint, (Ptr{Nothing},Ptr{UInt8}), pclient.ptr, - "message, /RESET") - flush() - return false - end - flush() - return true + # does no conversion of interpolated vars, continuation chars, or newlines + ecode = ccall((:IDL_RPCExecuteStr, libidl_rpc), Cint, (Ptr{Nothing},Ptr{UInt8}), pclient.ptr, str) + if ecode != 1 + # since error get printed by IDL, we just reset error state + ecode = ccall((:IDL_RPCExecuteStr, libidl_rpc), Cint, (Ptr{Nothing},Ptr{UInt8}), pclient.ptr, + "message, /RESET") + flush() + return false + end + flush() + return true end function capture(flag::Bool) - nlines = flag ? 5000 : 0 - ecode = ccall((:IDL_RPCOutputCapture, libidl_rpc), Cint, (Ptr{Nothing}, Cint), pclient.ptr, nlines) - ecode != 1 && error("IDL.capture: IDL_RPCOutputCapture failed") - return nothing + nlines = flag ? 5000 : 0 + ecode = ccall((:IDL_RPCOutputCapture, libidl_rpc), Cint, (Ptr{Nothing}, Cint), pclient.ptr, nlines) + ecode != 1 && error("IDL.capture: IDL_RPCOutputCapture failed") + return nothing end function get_output!(line_s::IDL_RPC_LINE_S) - ecode = ccall((:IDL_RPCOutputGetStr, libidl_rpc), Cint, (Ptr{Nothing},Ref{IDL_RPC_LINE_S},Cint), - pclient.ptr, line_s, 0) - ecode == 1 ? true : false + ecode = ccall((:IDL_RPCOutputGetStr, libidl_rpc), Cint, (Ptr{Nothing},Ref{IDL_RPC_LINE_S},Cint), + pclient.ptr, line_s, 0) + ecode == 1 ? true : false end flag_set(x, flag) = (x & flag) == flag function flush() - line_s = IDL_RPC_LINE_S() - # gc() - while get_output!(line_s) - println(unsafe_string(line_s.buf)) - flag_set(line_s.flags, IDL_TOUT_F_NLPOST) && print("\n") - end + line_s = IDL_RPC_LINE_S() + # gc() + while get_output!(line_s) + println(unsafe_string(line_s.buf)) + flag_set(line_s.flags, IDL_TOUT_F_NLPOST) && print("\n") + end end # no free_cb needed in libidl_rpc (I think) @@ -71,61 +71,61 @@ free_cb = C_NULL # I think the difference is because callable idl runs in the same process but # idlrpc does not. Thus, no free_cb is needed in idlrpc version. function put_var(arr::Array{T,N}, name::AbstractString) where {T,N} - if !isbitstype(eltype(arr)) || (idl_type(arr) < 0) - error("IDL.put_var: only works with some vars containing bits types") - end - dim = zeros(Int, IDL_MAX_ARRAY_DIM) - dim[1:N] = [size(arr)...] - vptr = ccall((:IDL_RPCImportArray, libidl_rpc), Ptr{IDL_Variable}, - (Cint, IDL_ARRAY_DIM, Cint, Ptr{T}, IDL_ARRAY_FREE_CB), - N, dim, idl_type(arr), arr, free_cb) - ecode = ccall((:IDL_RPCSetVariable, libidl_rpc), Cint, - (Ptr{Nothing}, Ptr{UInt8}, Ptr{IDL_Variable}), pclient.ptr, name, vptr) - ecode != 1 && error("IDL.put_var: failed") - return + if !isbitstype(eltype(arr)) || (idl_type(arr) < 0) + error("IDL.put_var: only works with some vars containing bits types") + end + dim = zeros(Int, IDL_MAX_ARRAY_DIM) + dim[1:N] = [size(arr)...] + vptr = ccall((:IDL_RPCImportArray, libidl_rpc), Ptr{IDL_Variable}, + (Cint, IDL_ARRAY_DIM, Cint, Ptr{T}, IDL_ARRAY_FREE_CB), + N, dim, idl_type(arr), arr, free_cb) + ecode = ccall((:IDL_RPCSetVariable, libidl_rpc), Cint, + (Ptr{Nothing}, Ptr{UInt8}, Ptr{IDL_Variable}), pclient.ptr, name, vptr) + ecode != 1 && error("IDL.put_var: failed") + return end # there must be a slicker way to do this? function uint_size(x) - if sizeof(x) == 1 - UInt8 - elseif sizeof(x) == 2 - UInt16 - elseif sizeof(x) == 4 - UInt32 - elseif sizeof(x) == 8 - UInt64 - elseif sizeof(x) == 16 - UInt128 - end + if sizeof(x) == 1 + UInt8 + elseif sizeof(x) == 2 + UInt16 + elseif sizeof(x) == 4 + UInt32 + elseif sizeof(x) == 8 + UInt64 + elseif sizeof(x) == 16 + UInt128 + end end function put_var(x, name::AbstractString) - if !isbits(x) || (idl_type(x) < 0) - error("IDL.put_var: only works with some vars containing bits types") - end - vptr = get_vptr(name) - ccall((:IDL_RPCStoreScalar, libidl_rpc), Nothing, - (Ptr{IDL_Variable}, Cint, Ref{UInt128}), - vptr, idl_type(x), Ref{UInt128}(convert(UInt128,reinterpret(uint_size(x),x)))) - ecode = ccall((:IDL_RPCSetVariable, libidl_rpc), Cint, - (Ptr{Nothing}, Ptr{UInt8}, Ptr{IDL_Variable}), pclient.ptr, name, vptr) - return + if !isbits(x) || (idl_type(x) < 0) + error("IDL.put_var: only works with some vars containing bits types") + end + vptr = get_vptr(name) + ccall((:IDL_RPCStoreScalar, libidl_rpc), Nothing, + (Ptr{IDL_Variable}, Cint, Ref{UInt128}), + vptr, idl_type(x), Ref{UInt128}(convert(UInt128,reinterpret(uint_size(x),x)))) + ecode = ccall((:IDL_RPCSetVariable, libidl_rpc), Cint, + (Ptr{Nothing}, Ptr{UInt8}, Ptr{IDL_Variable}), pclient.ptr, name, vptr) + return end function put_var(x::Complex{T}, name::AbstractString) where {T} - T == Float32 || T == Float64 || error("IDL.put_var: only floating point complex types allowed") - if T == Float64 - y = (convert(UInt128, reinterpret(UInt64, imag(x))) << 64) + reinterpret(UInt64, real(x)) - else - y = (convert(UInt128, reinterpret(UInt32, imag(x))) << 32) + reinterpret(UInt32, real(x)) - end - vptr = get_vptr(name) - ccall((:IDL_RPCStoreScalar, libidl_rpc), Nothing, - (Ptr{IDL_Variable}, Cint, Ref{UInt128}), vptr, idl_type(x), Ref{UInt128}(y)) - ecode = ccall((:IDL_RPCSetVariable, libidl_rpc), Cint, - (Ptr{Nothing}, Ptr{UInt8}, Ptr{IDL_Variable}), pclient.ptr, name, vptr) - return + T == Float32 || T == Float64 || error("IDL.put_var: only floating point complex types allowed") + if T == Float64 + y = (convert(UInt128, reinterpret(UInt64, imag(x))) << 64) + reinterpret(UInt64, real(x)) + else + y = (convert(UInt128, reinterpret(UInt32, imag(x))) << 32) + reinterpret(UInt32, real(x)) + end + vptr = get_vptr(name) + ccall((:IDL_RPCStoreScalar, libidl_rpc), Nothing, + (Ptr{IDL_Variable}, Cint, Ref{UInt128}), vptr, idl_type(x), Ref{UInt128}(y)) + ecode = ccall((:IDL_RPCSetVariable, libidl_rpc), Cint, + (Ptr{Nothing}, Ptr{UInt8}, Ptr{IDL_Variable}), pclient.ptr, name, vptr) + return end # function put_var(str::AbstractString, name::AbstractString) @@ -135,35 +135,35 @@ end # end function put_var(str::AbstractString, name::AbstractString) - idl_string = IDL_String() - ccall((:IDL_RPCStrStore, libidl_rpc), Nothing, (Ptr{IDL_String}, Ptr{Cchar}), - idl_string, str) - ecode = ccall((:IDL_RPCSetVariable, libidl_rpc), Cint, - (Ptr{Nothing}, Ptr{UInt8}, Ptr{IDL_Variable}), pclient.ptr, name, vptr) - ecode != 1 && error("IDL.put_var: failed") + idl_string = IDL_String() + ccall((:IDL_RPCStrStore, libidl_rpc), Nothing, (Ptr{IDL_String}, Ptr{Cchar}), + idl_string, str) + ecode = ccall((:IDL_RPCSetVariable, libidl_rpc), Cint, + (Ptr{Nothing}, Ptr{UInt8}, Ptr{IDL_Variable}), pclient.ptr, name, vptr) + ecode != 1 && error("IDL.put_var: failed") end function get_name(vptr::Ptr{IDL_Variable}) - # not implemented for RPC - str = ccall((:IDL_RPCVarName, libidl_rpc), Ptr{Cchar}, (Ptr{IDL_Variable},), vptr) - return unsafe_string(str) + # not implemented for RPC + str = ccall((:IDL_RPCVarName, libidl_rpc), Ptr{Cchar}, (Ptr{IDL_Variable},), vptr) + return unsafe_string(str) end function get_vptr(name::AbstractString) - # returns C_NULL if name not in scope - ccall((:IDL_RPCGetMainVariable, libidl_rpc), Ptr{IDL_Variable}, - (Ptr{Nothing},Ptr{UInt8}), pclient.ptr, name) + # returns C_NULL if name not in scope + ccall((:IDL_RPCGetMainVariable, libidl_rpc), Ptr{IDL_Variable}, + (Ptr{Nothing},Ptr{UInt8}), pclient.ptr, name) end function get_var(name::AbstractString) - vptr = ccall((:IDL_RPCGetMainVariable, libidl_rpc), Ptr{IDL_Variable}, - (Ptr{Nothing},Ptr{UInt8}), pclient.ptr, name) - # NOTE: IDL_RPCGetVariable never seems to return NULL in spite of docs - if vptr == C_NULL - error("IDL.get_var: variable $name does not exist") - end - var = get_var(vptr, name) - # not sure if this is needed? - vptr = ccall((:IDL_RPCDeltmp, libidl_rpc), Nothing, (Ptr{IDL_Variable},), vptr) - var + vptr = ccall((:IDL_RPCGetMainVariable, libidl_rpc), Ptr{IDL_Variable}, + (Ptr{Nothing},Ptr{UInt8}), pclient.ptr, name) + # NOTE: IDL_RPCGetVariable never seems to return NULL in spite of docs + if vptr == C_NULL + error("IDL.get_var: variable $name does not exist") + end + var = get_var(vptr, name) + # not sure if this is needed? + vptr = ccall((:IDL_RPCDeltmp, libidl_rpc), Nothing, (Ptr{IDL_Variable},), vptr) + var end diff --git a/src/common-funcs.jl b/src/common-funcs.jl index 329cfea..10a9f58 100644 --- a/src/common-funcs.jl +++ b/src/common-funcs.jl @@ -10,192 +10,192 @@ full_reset() = execute(".full_reset_session") dotrun(filename::AbstractString) = execute(".run $filename") function execute(str::AbstractString) - ok, strarr, msg = convert_command(str) - ok || error(msg) - execute_converted(strarr) - return nothing + ok, strarr, msg = convert_command(str) + ok || error(msg) + execute_converted(strarr) + return nothing end function execute_converted(strarr::Array{T,1}) where {T<:AbstractString} - # does no conversion of interpolated vars, continuation chars, or newlines - for str in strarr - execute_converted(str) || return false - end - return true + # does no conversion of interpolated vars, continuation chars, or newlines + for str in strarr + execute_converted(str) || return false + end + return true end function put_var_from_name(name::AbstractString, abort::Bool=true) - # abort=false causes routine to not issue error - ok = true - msg = "" - if !isdefined(Main, Symbol(name)) - ok = false - msg = "IDL.put_var_from_name: undefined variable $name in Module Main" - if abort - error(msg) - else - return (ok, msg) - end - end - put_var(getfield(Main, Symbol(name)), name) - return (ok, msg) + # abort=false causes routine to not issue error + ok = true + msg = "" + if !isdefined(Main, Symbol(name)) + ok = false + msg = "IDL.put_var_from_name: undefined variable $name in Module Main" + if abort + error(msg) + else + return (ok, msg) + end + end + put_var(getfield(Main, Symbol(name)), name) + return (ok, msg) end function put_var(arr::Array{T,N}, name::AbstractString) where {T<:AbstractString,N} - # Sort of a HACK: do direcly since ImportNamedArray doesn't work - execute("$name = strarr"*replace(string(size(arr)), ",)", ")")) - for i=1:length(arr) - j = i-1 - str = arr[i] - execute("$name[$j] = '$str'") - end - return + # Sort of a HACK: do direcly since ImportNamedArray doesn't work + execute("$name = strarr"*replace(string(size(arr)), ",)", ")")) + for i=1:length(arr) + j = i-1 + str = arr[i] + execute("$name[$j] = '$str'") + end + return end const mask64 = 0x0000000000000000ffffffffffffffff const mask32 = 0x000000000000000000000000ffffffff function get_var(vptr::Ptr{IDL_Variable}, name::AbstractString="") - var = unsafe_load(vptr) - # some types not dealt with - if (var.flags & IDL_V_FILE) != 0 - error("IDL.extract_from_vptr: $name: assoc type not setup") - end - ## if (var.flags & IDL_V_DYNAMIC) != 0 - ## println("dynamic") - ## end - if (var.flags & IDL_V_NULL) != 0 - error("IDL.extract_from_vptr: $name: variable is null") - end + var = unsafe_load(vptr) + # some types not dealt with + if (var.flags & IDL_V_FILE) != 0 + error("IDL.extract_from_vptr: $name: assoc type not setup") + end + ## if (var.flags & IDL_V_DYNAMIC) != 0 + ## println("dynamic") + ## end + if (var.flags & IDL_V_NULL) != 0 + error("IDL.extract_from_vptr: $name: variable is null") + end - # array types - if (var.flags & IDL_V_ARR) != 0 - if var.vtype == IDL_TYP_STRING - parr = reinterpret(Ptr{IDL_Array}, convert(Int, var.buf)) - idl_arr = unsafe_load(parr) - pdata = reinterpret(Ptr{IDL_String}, idl_arr.data) - strarr = Array{AbstractString}(dims(idl_arr.dim, idl_arr.n_dim)) - for i = 1:idl_arr.n_elts - data = unsafe_load(pdata, i) - strarr[i] = data.slen > 0 ? unsafe_string(data.s, Int(data.slen)) : "" - end - return strarr - elseif var.vtype == IDL_TYP_STRUCT - error("IDL.extract_from_vptr: $name: STRUCT not setup") - elseif var.vtype == IDL_TYP_PTR - error("IDL.extract_from_vptr: $name: PTRARR types not setup") - elseif var.vtype == IDL_TYP_OBJREF - error("IDL.extract_from_vptr: $name: OBJARR types not setup") - else - parr = reinterpret(Ptr{IDL_Array}, convert(Int, var.buf)) - idl_arr = unsafe_load(parr) - jl_t = jl_type(var.vtype) - pdata = reinterpret(Ptr{jl_t}, idl_arr.data) - arr = unsafe_wrap(Array, pdata, dims(idl_arr.dim, idl_arr.n_dim)) - #= - arr = Array{jl_t}(undef, dims(idl_arr.dim, idl_arr.n_dim)) - for i = 1:idl_arr.n_elts + # array types + if (var.flags & IDL_V_ARR) != 0 + if var.vtype == IDL_TYP_STRING + parr = reinterpret(Ptr{IDL_Array}, convert(Int, var.buf)) + idl_arr = unsafe_load(parr) + pdata = reinterpret(Ptr{IDL_String}, idl_arr.data) + strarr = Array{AbstractString}(dims(idl_arr.dim, idl_arr.n_dim)) + for i = 1:idl_arr.n_elts + data = unsafe_load(pdata, i) + strarr[i] = data.slen > 0 ? unsafe_string(data.s, Int(data.slen)) : "" + end + return strarr + elseif var.vtype == IDL_TYP_STRUCT + error("IDL.extract_from_vptr: $name: STRUCT not setup") + elseif var.vtype == IDL_TYP_PTR + error("IDL.extract_from_vptr: $name: PTRARR types not setup") + elseif var.vtype == IDL_TYP_OBJREF + error("IDL.extract_from_vptr: $name: OBJARR types not setup") + else + parr = reinterpret(Ptr{IDL_Array}, convert(Int, var.buf)) + idl_arr = unsafe_load(parr) + jl_t = jl_type(var.vtype) + pdata = reinterpret(Ptr{jl_t}, idl_arr.data) + arr = unsafe_wrap(Array, pdata, dims(idl_arr.dim, idl_arr.n_dim)) + #= + arr = Array{jl_t}(undef, dims(idl_arr.dim, idl_arr.n_dim)) + for i = 1:idl_arr.n_elts arr[i] = unsafe_load(pdata, i) - end - =# - # If you don't copy, the pointer will be freed! - return copy(arr) - end - end + end + =# + # If you don't copy, the pointer will be freed! + return copy(arr) + end +end - # Scalar value - if var.vtype == IDL_TYP_UNDEF - error("IDL.extract_from_vptr: $name: undefined variable") - elseif var.vtype == IDL_TYP_BYTE - return reinterpret(Int8, convert(UInt8, var.buf)) - elseif var.vtype == IDL_TYP_INT - return reinterpret(Int16, convert(UInt16, var.buf)) - elseif var.vtype == IDL_TYP_LONG - return reinterpret(Int32, convert(UInt32, var.buf)) - elseif var.vtype == IDL_TYP_FLOAT - return reinterpret(Float32, convert(UInt32, var.buf)) - elseif var.vtype == IDL_TYP_DOUBLE - return reinterpret(Float64, convert(UInt64, var.buf)) - elseif var.vtype == IDL_TYP_COMPLEX - return complex(reinterpret(Float32, convert(UInt32, var.buf & mask32)), - reinterpret(Float32, convert(UInt32, var.buf >> 32))) - elseif var.vtype == IDL_TYP_STRING - slen = reinterpret(Int32, convert(UInt32,var.buf & mask32)) - stype = reinterpret(Int32, convert(UInt32,(var.buf & mask64) >> 32)) - println(stype) - s = reinterpret(Ptr{Cchar}, convert(UInt64,var.buf >> 64)) - return slen > 0 ? unsafe_string(s, slen) : "" - elseif var.vtype == IDL_TYP_STRUCT - error("IDL.extract_from_vptr: $name: STRUCT not setup") - elseif var.vtype == IDL_TYP_DCOMPLEX - return complex(reinterpret(Float64, convert(UInt64, var.buf & mask64)), - reinterpret(Float64, convert(UInt64, var.buf >> 64))) - elseif var.vtype == IDL_TYP_PTR - error("IDL.extract_from_vptr: $name: PTR not setup") - elseif var.vtype == IDL_TYP_OBJREF - error("IDL.extract_from_vptr: $name: OBJREF not setup") - elseif var.vtype == IDL_TYP_UINT - return reinterpret(UInt16, convert(UInt16, var.buf)) - elseif var.vtype == IDL_TYP_ULONG - return reinterpret(UInt32, convert(UInt32, var.buf)) - elseif var.vtype == IDL_TYP_LONG64 - return reinterpret(Int64, convert(UInt64, var.buf)) - elseif var.vtype == IDL_TYP_ULONG64 - return reinterpret(UInt64, convert(UInt64, var.buf)) - end - # should be impossible to get here - error("IDL.extract_from_vptr: $name: type is not setup") +# Scalar value +if var.vtype == IDL_TYP_UNDEF + error("IDL.extract_from_vptr: $name: undefined variable") +elseif var.vtype == IDL_TYP_BYTE + return reinterpret(Int8, convert(UInt8, var.buf)) +elseif var.vtype == IDL_TYP_INT + return reinterpret(Int16, convert(UInt16, var.buf)) +elseif var.vtype == IDL_TYP_LONG + return reinterpret(Int32, convert(UInt32, var.buf)) +elseif var.vtype == IDL_TYP_FLOAT + return reinterpret(Float32, convert(UInt32, var.buf)) +elseif var.vtype == IDL_TYP_DOUBLE + return reinterpret(Float64, convert(UInt64, var.buf)) +elseif var.vtype == IDL_TYP_COMPLEX + return complex(reinterpret(Float32, convert(UInt32, var.buf & mask32)), + reinterpret(Float32, convert(UInt32, var.buf >> 32))) +elseif var.vtype == IDL_TYP_STRING + slen = reinterpret(Int32, convert(UInt32,var.buf & mask32)) + stype = reinterpret(Int32, convert(UInt32,(var.buf & mask64) >> 32)) + println(stype) + s = reinterpret(Ptr{Cchar}, convert(UInt64,var.buf >> 64)) + return slen > 0 ? unsafe_string(s, slen) : "" +elseif var.vtype == IDL_TYP_STRUCT + error("IDL.extract_from_vptr: $name: STRUCT not setup") +elseif var.vtype == IDL_TYP_DCOMPLEX + return complex(reinterpret(Float64, convert(UInt64, var.buf & mask64)), + reinterpret(Float64, convert(UInt64, var.buf >> 64))) +elseif var.vtype == IDL_TYP_PTR + error("IDL.extract_from_vptr: $name: PTR not setup") +elseif var.vtype == IDL_TYP_OBJREF + error("IDL.extract_from_vptr: $name: OBJREF not setup") +elseif var.vtype == IDL_TYP_UINT + return reinterpret(UInt16, convert(UInt16, var.buf)) +elseif var.vtype == IDL_TYP_ULONG + return reinterpret(UInt32, convert(UInt32, var.buf)) +elseif var.vtype == IDL_TYP_LONG64 + return reinterpret(Int64, convert(UInt64, var.buf)) +elseif var.vtype == IDL_TYP_ULONG64 + return reinterpret(UInt64, convert(UInt64, var.buf)) +end +# should be impossible to get here +error("IDL.extract_from_vptr: $name: type is not setup") end function inside_string(pt::Int, line::AbstractString) - for re in (r"('[^']+')", r"(\"[^\"]+\")") - for m in eachmatch(re, line) - if m.offset+length(m.captures[1]) > pt ≥ m.offset - return true - end - end - end - return false + for re in (r"('[^']+')", r"(\"[^\"]+\")") + for m in eachmatch(re, line) + if m.offset+length(m.captures[1]) > pt ≥ m.offset + return true + end + end + end + return false end function convert_continuations(line) - # remove trailing comments and continuation lines - # currently has issue with [;|\$] inside quotes! - line = replace(strip(line), r"(;|\$).*(\n|$)"=>"") + # remove trailing comments and continuation lines + # currently has issue with [;|\$] inside quotes! + line = replace(strip(line), r"(;|\$).*(\n|$)"=>"") - return true, line, "" + return true, line, "" end function convert_newlines(line) - # separates line at newline ('\n') characters into string array - # assumes that continuation characters are already removed - # not type stable but should not matter for repl use - line = chomp(line) - if '\n' in line - line = split(line, '\n', keepempty=false) - end - return line + # separates line at newline ('\n') characters into string array + # assumes that continuation characters are already removed + # not type stable but should not matter for repl use + line = chomp(line) + if '\n' in line + line = split(line, '\n', keepempty=false) + end + return line end function replace_interpolated_vars(line) - # use %var to automatically pull var into idl and use it - while (m = match(r"\%(\w+)", line)) != nothing - if !inside_string(m.offset, line) - ok, msg = put_var_from_name(ascii(m.captures[1]), false) - if !ok - return false, line, msg - end - line = line[1:m.offset-1]*line[m.offset+1:end] - end - end - return true, line, "" + # use %var to automatically pull var into idl and use it + while (m = match(r"\%(\w+)", line)) != nothing + if !inside_string(m.offset, line) + ok, msg = put_var_from_name(ascii(m.captures[1]), false) + if !ok + return false, line, msg + end + line = line[1:m.offset-1]*line[m.offset+1:end] + end + end + return true, line, "" end function convert_command(line) - ok, line, msg = replace_interpolated_vars(line) - ok || return ok, line, msg - ok, line, msg = convert_continuations(line) # hyzhou: remove while testing - ok || return ok, line, msg - line = convert_newlines(line) - return true, line, msg + ok, line, msg = replace_interpolated_vars(line) + ok || return ok, line, msg + ok, line, msg = convert_continuations(line) # hyzhou: remove while testing + ok || return ok, line, msg + line = convert_newlines(line) + return true, line, msg end diff --git a/src/common-macros.jl b/src/common-macros.jl index f196dbd..ed2deeb 100644 --- a/src/common-macros.jl +++ b/src/common-macros.jl @@ -2,57 +2,57 @@ # E.G., @mput, @mget, _mput_multi, _mget_multi, make_getvar_statement function put_var_multi(vs::Symbol...) - nv = length(vs) - if nv == 1 - v = vs[1] - :(put_var($(v), string($(Meta.quot(v))))) - else - stmts = Array(Expr, nv) - for i = 1:nv - v = vs[i] - stmts[i] = :(put_var($(v), string($(Meta.quot(v))))) - end - Expr(:block, stmts...) - end + nv = length(vs) + if nv == 1 + v = vs[1] + :(put_var($(v), string($(Meta.quot(v))))) + else + stmts = Array(Expr, nv) + for i = 1:nv + v = vs[i] + stmts[i] = :(put_var($(v), string($(Meta.quot(v))))) + end + Expr(:block, stmts...) + end end macro put_var(vs...) - esc(put_var_multi(vs...)) + esc(put_var_multi(vs...)) end function make_getvar_statement(v::Symbol) - :($(v) = get_var(string($(Meta.quot(v))))) + :($(v) = get_var(string($(Meta.quot(v))))) end function make_getvar_statement(ex::Expr) - if !(ex.head == :(=)) - if ex.head == :kw - error("Must call @get_var without parenthesis if using statements") - else - erorr("Invalid expression for @get_var: " * string(ex)) - end - end - v::Symbol = ex.args[1] - k::Symbol = ex.args[2] - :($(v) = get_var(string($(Meta.quot(k))))) - end + if !(ex.head == :(=)) + if ex.head == :kw + error("Must call @get_var without parenthesis if using statements") + else + erorr("Invalid expression for @get_var: " * string(ex)) + end + end + v::Symbol = ex.args[1] + k::Symbol = ex.args[2] + :($(v) = get_var(string($(Meta.quot(k))))) + end end function get_var_multi(vs::Union{Symbol, Expr}...) - # supress output by adding :nothing - nv = length(vs) - if nv == 1 - stmt = make_getvar_statement(vs[1]) - Expr(:block, stmt, :nothing) - else - stmts = Array(Expr, nv) - for i = 1:nv - stmts[i] = make_getvar_statement(vs[i]) - end - Expr(:block, stmts..., :nothing) - end + # supress output by adding :nothing + nv = length(vs) + if nv == 1 + stmt = make_getvar_statement(vs[1]) + Expr(:block, stmt, :nothing) + else + stmts = Array(Expr, nv) + for i = 1:nv + stmts[i] = make_getvar_statement(vs[i]) + end + Expr(:block, stmts..., :nothing) + end end macro get_var(vs...) - esc(get_var_multi(vs...)) + esc(get_var_multi(vs...)) end diff --git a/src/idl_types.jl b/src/idl_types.jl index d470cee..12c5e66 100644 --- a/src/idl_types.jl +++ b/src/idl_types.jl @@ -44,71 +44,71 @@ const IDL_V_STRUCT = 32 const IDL_V_NULL = 64 function idl_type(jl_t) - # IDL type index from julia type - t = typeof(jl_t) - if t <: AbstractArray - t = eltype(jl_t) - end - idl_t = -1 - if t == UInt8 - idl_t = IDL_TYP_BYTE - elseif t == Int16 - idl_t = IDL_TYP_INT - elseif t == Int32 - idl_t = IDL_TYP_LONG - elseif t == Float32 - idl_t = IDL_TYP_FLOAT - elseif t == Float64 - idl_t = IDL_TYP_DOUBLE - elseif t == ComplexF64 - idl_t = IDL_TYP_COMPLEX - elseif t <: AbstractString - idl_t = IDL_TYP_STRING - elseif t == UInt16 - idl_t = IDL_TYP_UINT - elseif t == UInt32 - idl_t = IDL_TYP_ULONG - elseif t == Int64 - idl_t = IDL_TYP_LONG64 - elseif t == UInt64 - idl_t = IDL_TYP_ULONG64 - end - if idl_t < 0 error("IDL.idl_type: type not found: " * string(t)) end - return idl_t + # IDL type index from julia type + t = typeof(jl_t) + if t <: AbstractArray + t = eltype(jl_t) + end + idl_t = -1 + if t == UInt8 + idl_t = IDL_TYP_BYTE + elseif t == Int16 + idl_t = IDL_TYP_INT + elseif t == Int32 + idl_t = IDL_TYP_LONG + elseif t == Float32 + idl_t = IDL_TYP_FLOAT + elseif t == Float64 + idl_t = IDL_TYP_DOUBLE + elseif t == ComplexF64 + idl_t = IDL_TYP_COMPLEX + elseif t <: AbstractString + idl_t = IDL_TYP_STRING + elseif t == UInt16 + idl_t = IDL_TYP_UINT + elseif t == UInt32 + idl_t = IDL_TYP_ULONG + elseif t == Int64 + idl_t = IDL_TYP_LONG64 + elseif t == UInt64 + idl_t = IDL_TYP_ULONG64 + end + if idl_t < 0 error("IDL.idl_type: type not found: " * string(t)) end + return idl_t end function jl_type(idl_t) - # julia type from IDL type index - jl_t = Any - if idl_t == IDL_TYP_BYTE - jl_t = UInt8 - elseif idl_t == IDL_TYP_INT - jl_t = Int16 - elseif idl_t == IDL_TYP_LONG - jl_t = Int32 - elseif idl_t == IDL_TYP_FLOAT - jl_t = Float32 - elseif idl_t == IDL_TYP_DOUBLE - jl_t = Float64 - elseif idl_t == IDL_TYP_COMPLEX - jl_t = ComplexF64 - elseif idl_t == IDL_TYP_STRING - jl_t = Compat.String - #elseif idl_t == IDL_TYP_DCOMPLEX - # jl_t = Complex128 - elseif idl_t == IDL_TYP_UINT - jl_t = UInt16 - elseif idl_t == IDL_TYP_ULONG - jl_t = UInt32 - elseif idl_t == IDL_TYP_LONG64 - jl_t = Int64 - elseif idl_t == IDL_TYP_ULONG64 - jl_t = UInt64 - end - if jl_t == Any - error("IDL.jl_type: type not found: " * string(idl_t)) - end - return jl_t + # julia type from IDL type index + jl_t = Any + if idl_t == IDL_TYP_BYTE + jl_t = UInt8 + elseif idl_t == IDL_TYP_INT + jl_t = Int16 + elseif idl_t == IDL_TYP_LONG + jl_t = Int32 + elseif idl_t == IDL_TYP_FLOAT + jl_t = Float32 + elseif idl_t == IDL_TYP_DOUBLE + jl_t = Float64 + elseif idl_t == IDL_TYP_COMPLEX + jl_t = ComplexF64 + elseif idl_t == IDL_TYP_STRING + jl_t = Compat.String + #elseif idl_t == IDL_TYP_DCOMPLEX + # jl_t = Complex128 + elseif idl_t == IDL_TYP_UINT + jl_t = UInt16 + elseif idl_t == IDL_TYP_ULONG + jl_t = UInt32 + elseif idl_t == IDL_TYP_LONG64 + jl_t = Int64 + elseif idl_t == IDL_TYP_ULONG64 + jl_t = UInt64 + end + if jl_t == Any + error("IDL.jl_type: type not found: " * string(idl_t)) + end + return jl_t end #*************************************************************************************************# @@ -116,54 +116,54 @@ end # sizeof(buf) is max size of IDL_ALLTYPES Union (64x2=128 bits or 16 bytes on all platforms) const IDL_ALLTYPES = UInt128 struct IDL_Variable - vtype::UCHAR - flags::UCHAR - flags2::UCHAR - buf::IDL_ALLTYPES + vtype::UCHAR + flags::UCHAR + flags2::UCHAR + buf::IDL_ALLTYPES end # works as a fixed length array struct IDL_DIMS - d1::IDL_MEMINT - d2::IDL_MEMINT - d3::IDL_MEMINT - d4::IDL_MEMINT - d5::IDL_MEMINT - d6::IDL_MEMINT - d7::IDL_MEMINT - d8::IDL_MEMINT + d1::IDL_MEMINT + d2::IDL_MEMINT + d3::IDL_MEMINT + d4::IDL_MEMINT + d5::IDL_MEMINT + d6::IDL_MEMINT + d7::IDL_MEMINT + d8::IDL_MEMINT end dims(d::IDL_DIMS) = (d.d1,d.d2,d.d3,d.d4,d.d5,d.d6,d.d7,d.d8) dims(d::IDL_DIMS, ndims::Integer) = (d.d1,d.d2,d.d3,d.d4,d.d5,d.d6,d.d7,d.d8)[1:ndims] struct IDL_Array - elt_len::IDL_MEMINT # Length of element in char units - arr_len::IDL_MEMINT # Length of entire array (char) - n_elts::IDL_MEMINT # total # of elements - data::Ptr{UCHAR} # ^ to beginning of array data - n_dim::UCHAR # # of dimensions used by array - flags::UCHAR # Array block flags - file_unit::Cshort # # of assoc file if file var - dim::IDL_DIMS # dimensions - free_cb::IDL_ARRAY_FREE_CB # Free callback - offset::IDL_FILEINT # Offset to base of data for file var - data_guard::IDL_MEMINT # Guard longword + elt_len::IDL_MEMINT # Length of element in char units + arr_len::IDL_MEMINT # Length of entire array (char) + n_elts::IDL_MEMINT # total # of elements + data::Ptr{UCHAR} # ^ to beginning of array data + n_dim::UCHAR # # of dimensions used by array + flags::UCHAR # Array block flags + file_unit::Cshort # # of assoc file if file var + dim::IDL_DIMS # dimensions + free_cb::IDL_ARRAY_FREE_CB # Free callback + offset::IDL_FILEINT # Offset to base of data for file var + data_guard::IDL_MEMINT # Guard longword end struct IDL_String - slen::IDL_STRING_SLEN_T # Length of string, 0 for null - stype::Cshort # type of string, static or dynamic - s::Ptr{Cchar} # Addr of string - IDL_String() = new(0, 0, Base.unsafe_convert(Ptr{Cchar}, Array{Cchar}(undef, IDL_RPC_MAX_STRLEN))) + slen::IDL_STRING_SLEN_T # Length of string, 0 for null + stype::Cshort # type of string, static or dynamic + s::Ptr{Cchar} # Addr of string + IDL_String() = new(0, 0, Base.unsafe_convert(Ptr{Cchar}, Array{Cchar}(undef, IDL_RPC_MAX_STRLEN))) end # From idl_rpc.h const IDL_RPC_MAX_STRLEN = 512 # max string length struct IDL_RPC_LINE_S - flags::Cint - buf::Ptr{Cchar} - IDL_RPC_LINE_S() = new(0, Base.unsafe_convert(Ptr{Cchar}, Array{Cchar}(undef, IDL_RPC_MAX_STRLEN))) + flags::Cint + buf::Ptr{Cchar} + IDL_RPC_LINE_S() = new(0, Base.unsafe_convert(Ptr{Cchar}, Array{Cchar}(undef, IDL_RPC_MAX_STRLEN))) end const IDL_TOUT_F_STDERR = 1 # Output to stderr instead of stdout From accd78833f6b6acf150bc9d5eaa129d13175e8c0 Mon Sep 17 00:00:00 2001 From: hyzhou Date: Sun, 16 Feb 2020 10:45:19 -0500 Subject: [PATCH 27/38] Fix typo. --- src/common-macros.jl | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/common-macros.jl b/src/common-macros.jl index ed2deeb..d0af3af 100644 --- a/src/common-macros.jl +++ b/src/common-macros.jl @@ -28,14 +28,13 @@ function make_getvar_statement(ex::Expr) if !(ex.head == :(=)) if ex.head == :kw error("Must call @get_var without parenthesis if using statements") - else - erorr("Invalid expression for @get_var: " * string(ex)) - end + else + error("Invalid expression for @get_var: " * string(ex)) end - v::Symbol = ex.args[1] - k::Symbol = ex.args[2] - :($(v) = get_var(string($(Meta.quot(k))))) end + v::Symbol = ex.args[1] + k::Symbol = ex.args[2] + :($(v) = get_var(string($(Meta.quot(k))))) end function get_var_multi(vs::Union{Symbol, Expr}...) From 8a83e2aff14a2a89c354a60861bd7c36b1338fe9 Mon Sep 17 00:00:00 2001 From: hyzhou Date: Sun, 16 Feb 2020 11:06:31 -0500 Subject: [PATCH 28/38] Add Libdl to dependency. --- Manifest.toml | 3 +++ Project.toml | 1 + 2 files changed, 4 insertions(+) diff --git a/Manifest.toml b/Manifest.toml index d2e0d53..20f35d3 100644 --- a/Manifest.toml +++ b/Manifest.toml @@ -7,6 +7,9 @@ uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" deps = ["Markdown"] uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" +[[Libdl]] +uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" + [[Markdown]] deps = ["Base64"] uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" diff --git a/Project.toml b/Project.toml index d62e630..791f17f 100644 --- a/Project.toml +++ b/Project.toml @@ -4,6 +4,7 @@ authors = ["Bob Portmann", "Hongyang Zhou "] version = "0.1.0" [deps] +Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb" REPL = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" [extras] From 77f4f5cfb7792a07c10193a7e256cf5cd7404746 Mon Sep 17 00:00:00 2001 From: hyzhou Date: Sun, 16 Feb 2020 11:07:08 -0500 Subject: [PATCH 29/38] Rename init function. --- src/IDLCallable.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/IDLCallable.jl b/src/IDLCallable.jl index 919d40f..edaf1f9 100644 --- a/src/IDLCallable.jl +++ b/src/IDLCallable.jl @@ -5,12 +5,12 @@ include("common-macros.jl") using Libdl if Sys.isapple() - cd(IDL_LIB_DIR) do + cd(idl_lib_dir) do Libdl.dlopen("libidl") end end -function init() +function callable_init() ecode = ccall((:IDL_Init, idlcall), Cint, (Cint, Ptr{Cint}, Ptr{Ptr{UInt8}}), 0, C_NULL, C_NULL) ecode == 0 && error("IDL.init: IDL init failed") From 77d9709572aef79fd1e99eca7f5b45299a183341 Mon Sep 17 00:00:00 2001 From: hyzhou Date: Sun, 16 Feb 2020 11:07:29 -0500 Subject: [PATCH 30/38] Rename init function, called from one level up. --- src/IDLRPC.jl | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/IDLRPC.jl b/src/IDLRPC.jl index 0dfbf55..521ae8c 100644 --- a/src/IDLRPC.jl +++ b/src/IDLRPC.jl @@ -13,7 +13,31 @@ RPCclient(ptr::Ptr{Nothing}) = RPCclient(ptr, nothing) pclient = RPCclient() function rpc_init() - ccall((:IDL_RPCInit, libidl_rpc), Ptr{Nothing}, (Clong, Ptr{UInt8}), 0, C_NULL) + # Initializing RPC + olderr = stderr + (rd, wr) = redirect_stderr() # Redirect error messages + ptr = ccall((:IDL_RPCInit, libidl_rpc), Ptr{Nothing}, (Clong, Ptr{UInt8}), 0, C_NULL) + if ptr != C_NULL # Check if idlrpc is already running + global pclient = RPCclient(ptr) + else # Start up idlrpc + println("Initializing IDL") + run(`$idlrpc`, wait=false) + ptr = C_NULL + cnt = 0 + while ptr == C_NULL && cnt < 60 # Allow for startup time + ptr = ccall((:IDL_RPCInit, libidl_rpc), Ptr{Nothing}, (Clong, Ptr{UInt8}), 0, C_NULL) + cnt = cnt + 1 + sleep(1) + print(".") + end + println("") + ptr == C_NULL && error("IDL.init: IDLRPC init failed") + global pclient = RPCclient(ptr, proc) + end + capture(true) # Capture output from IDL + redirect_stderr(olderr) + # Register cleanup function to be called at exit + atexit(rpc_cleanup) end function rpc_cleanup() From a3d1f449a8687fffe7468e94de550bc66bb542b2 Mon Sep 17 00:00:00 2001 From: hyzhou Date: Sun, 16 Feb 2020 11:07:54 -0500 Subject: [PATCH 31/38] Added info about convenient functions. --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 76f4d7d..193ba14 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,16 @@ idl.execute("any valid idl code") ``` Note that only primitive data types are supported at this time (e.g., structure variables are not supported yet). Also, `[;|\$]` inside quotes won't be correctly recognized. +Many convenient functions are provided: +``` +IDL.help +IDL.idlhelp +IDL.shell_command +IDL.reset +IDL.full_reset +IDL.dotrun +``` + ## REPL You can drop into an IDL REPL by typing `>` at the Julia prompt. Then you can type any valid IDL commands, including using continuation characters `$` for multi-line commands. One experimental feature I have added is the use of `%var` will auto-magically import the Julia variable `var` into the IDL process. This works at the IDL prompt or in strings passed into the `execute` function. From d3b050370ad5917b6a50ffd26f3f6d2cc534428e Mon Sep 17 00:00:00 2001 From: hyzhou Date: Sun, 16 Feb 2020 11:09:51 -0500 Subject: [PATCH 32/38] Rename IDLCall.jl -> IDL.jl; better __init__() function. --- src/IDL.jl | 48 +++++++++++++----------------------------------- src/IDLCall.jl | 41 ----------------------------------------- 2 files changed, 13 insertions(+), 76 deletions(-) delete mode 100644 src/IDLCall.jl diff --git a/src/IDL.jl b/src/IDL.jl index ead091f..a0e30ac 100644 --- a/src/IDL.jl +++ b/src/IDL.jl @@ -1,62 +1,40 @@ module IDL export get_var, put_var, @get_var, @put_var, execute -export help # Find IDL library directory if on Linux if Sys.isunix() - IDL_EXEC = chomp(read(`which idl`,String)) - if islink(IDL_EXEC) - IDL_DIR = dirname(readlink(IDL_EXEC)) + idl_exec = chomp(read(`which idl`,String)) + if islink(idl_exec) + idl_dir = dirname(readlink(idl_exec)) else - IDL_DIR = dirname(IDL_EXEC) + idl_dir = dirname(idl_exec) end - IDL_LIB_DIR = joinpath(IDL_DIR,"bin.darwin.x86_64") - const libidl_rpc = joinpath(IDL_LIB_DIR,"libidl_rpc.dylib") - const idlrpc = joinpath(IDL_DIR,"idlrpc") + idl_lib_dir = joinpath(idl_dir,"bin.darwin.x86_64") + const libidl_rpc = joinpath(idl_lib_dir,"libidl_rpc.dylib") + const idlrpc = joinpath(idl_dir,"idlrpc") + const idlcall = joinpath(idl_lib_dir,"libidl.dylib") else # Windows const idlcall = "libidl" const idlrpc = "libidl_rpc" end -#= + jl_idl_type = get(ENV, "JL_IDL_TYPE", Sys.iswindows() ? "CALLABLE" : "RPC") jl_idl_type == "RPC" ? include("IDLRPC.jl") : jl_idl_type == "CALLABLE" ? include("IDLCallable.jl") : Sys.iswindows() ? error("JL_IDL_TYPE must be CALLABLE on windows") : error("JL_IDL_TYPE must be RPC or CALLABLE") -=# -include("IDLRPC.jl") include("IDLREPL.jl") function __init__() - # Initializing RPC - olderr = stderr - (rd, wr) = redirect_stderr() # Redirect error messages - ptr = rpc_init() - if ptr != C_NULL # Check if idlrpc is already running - global pclient = RPCclient(ptr) - else # Start up idlrpc - println("Initializing IDL") - run(`$idlrpc`, wait=false) - ptr = C_NULL - cnt = 0 - while ptr == C_NULL && cnt < 60 # Allow for startup time - ptr = rpc_init() - cnt = cnt + 1 - sleep(1) - print(".") - end - println("") - ptr == C_NULL && error("IDL.init: IDLRPC init failed") - global pclient = RPCclient(ptr, proc) + if jl_idl_type == "RPC" + rpc_init() + elseif jl_idl_type == "CALLABLE" + callable_init() # not yet working for MaxOS and Linux end - capture(true) # Capture output from IDL - redirect_stderr(olderr) - # Register cleanup function to be called at exit - atexit(rpc_cleanup) # Initializing REPL idl_repl() diff --git a/src/IDLCall.jl b/src/IDLCall.jl deleted file mode 100644 index f91cf01..0000000 --- a/src/IDLCall.jl +++ /dev/null @@ -1,41 +0,0 @@ - -module IDLCall - -#using Compat - -# Find IDL library directory if on Linux -if Sys.isunix() - # readlink??? - #IDL_LIB_DIR = chomp(readstring(`bash -c "ls -d $(IDL_DIR)/bin.*"`)) - #IDL_DIR = dirname(chomp(read(`which idl`,String))) - IDL_DIR = "/Applications/exelis/idl85" - #IDL_PATH='/Users/hyzhou/Idl:${IDL_DIR}/lib:${IDL_DIR}/lib/utilities' - #IDL_STARTUP=idlrc - #IDL_LIB_DIR = chomp(read(`bash -c "ls -d $(IDL_DIR)/bin.*"`,String)) - IDL_LIB_DIR = "/Applications/exelis/idl85/bin/bin.darwin.x86_64" - #const idlcall = IDL_LIB_DIR*"/libidl" - #const idlrpc = IDL_LIB_DIR*"/libidl_rpc" - #const idlcall = joinpath(IDL_LIB_DIR,"lib") - #const idlrpc = joinpath(IDL_LIB_DIR,"libidl_rpc") - const idlrpc = joinpath(IDL_LIB_DIR,"libidl_rpc.dylib") -else # Windows - #const idlcall = "libidl" - #const idlrpc = "libidl_rpc" -end - -export init, get_var, put_var, execute, @get_var, @put_var, idl_repl - -jl_idl_type = get(ENV, "JL_IDL_TYPE", Sys.iswindows() ? "CALLABLE" : "RPC") - -jl_idl_type == "RPC" ? include("IDLRPC.jl") : -jl_idl_type == "CALLABLE" ? include("IDLCallable.jl") : -Sys.iswindows() ? error("JL_IDL_TYPE must be CALLABLE on windows") : -error("JL_IDL_TYPE must be RPC or CALLABLE") - -include("IDLREPL.jl") - -init() -idl_repl() -repl = idl_repl - -end From bcec124e1f808b4ab0091a7d878b06cc67ab1000 Mon Sep 17 00:00:00 2001 From: hyzhou Date: Sun, 16 Feb 2020 11:46:38 -0500 Subject: [PATCH 33/38] Polish the tests. Currently only work if you comment out init_repl() in __init(). --- test/runtests.jl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index 665cd23..b83a2a2 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -2,7 +2,6 @@ using IDL, Test # scalar passing execute("a = 1") -help() execute("a += 1") a = get_var("a") @test a == 2 @@ -10,16 +9,19 @@ a = get_var("a") # string passing line = """ b = '1+1 ' +c = 'hello' """ execute(line) b = get_var("b") +@get_var c @test b == "1+1 " +@test c == "hello" # array passing a = [1,2,3] put_var(a, "a") execute("a += 1") -a = get_var("a") +@get_var a @test a == [2,3,4] From 804474f1d925279e706bac26f644aa0a2897c49e Mon Sep 17 00:00:00 2001 From: hyzhou Date: Mon, 17 Feb 2020 09:26:17 -0500 Subject: [PATCH 34/38] Fix active_repl not found for testing. --- src/IDLREPL.jl | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/src/IDLREPL.jl b/src/IDLREPL.jl index 1d8498e..ec89d52 100644 --- a/src/IDLREPL.jl +++ b/src/IDLREPL.jl @@ -1,13 +1,14 @@ import REPL:respond, LineEdit, mode_keymap -import Base:active_repl, text_colors function idl_repl() # Setup idl prompt prompt = LineEdit.Prompt("IDL> "; - prompt_prefix=text_colors[:blue], - prompt_suffix=text_colors[:white]) + prompt_prefix=Base.text_colors[:blue], + prompt_suffix=Base.text_colors[:white]) - repl = active_repl + !isdefined(Base, :active_repl) && return + + repl = Base.active_repl prompt.on_done = respond(repl,prompt) do line ok2, line, msg = convert_continuations(line) @@ -41,27 +42,27 @@ function idl_repl() prompt.hist = hp idl_keymap = Dict{Any,Any}( - '>' => function (s,args...) - if isempty(s) - if !haskey(s.mode_state,prompt) - s.mode_state[prompt] = LineEdit.init_state(repl.t,prompt) + '>' => function (s,args...) + if isempty(s) + if !haskey(s.mode_state,prompt) + s.mode_state[prompt] = LineEdit.init_state(repl.t,prompt) + end + LineEdit.transition(s,prompt) + else + LineEdit.edit_insert(s,'>') end - LineEdit.transition(s,prompt) - else - LineEdit.edit_insert(s,'>') - end -end) + end) -search_prompt, skeymap = LineEdit.setup_search_keymap(hp) -mk = mode_keymap(main_mode) + search_prompt, skeymap = LineEdit.setup_search_keymap(hp) + mk = mode_keymap(main_mode) -b = Dict{Any,Any}[skeymap, mk, LineEdit.history_keymap, -LineEdit.default_keymap, LineEdit.escape_defaults] -prompt.keymap_dict = LineEdit.keymap(b) + b = Dict{Any,Any}[skeymap, mk, LineEdit.history_keymap, + LineEdit.default_keymap, LineEdit.escape_defaults] + prompt.keymap_dict = LineEdit.keymap(b) -main_mode.keymap_dict = LineEdit.keymap_merge(main_mode.keymap_dict, -idl_keymap) -nothing + main_mode.keymap_dict = LineEdit.keymap_merge(main_mode.keymap_dict, + idl_keymap) + nothing end function find_prompt_in_modes(modes, name) From ac204df9617e0ad56094664faf10588a1df64f2c Mon Sep 17 00:00:00 2001 From: hyzhou Date: Mon, 17 Feb 2020 09:37:20 -0500 Subject: [PATCH 35/38] :IDL_Init -> :IDL_Initialize --- src/IDLCallable.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/IDLCallable.jl b/src/IDLCallable.jl index edaf1f9..96cc8b9 100644 --- a/src/IDLCallable.jl +++ b/src/IDLCallable.jl @@ -11,8 +11,8 @@ if Sys.isapple() end function callable_init() - ecode = ccall((:IDL_Init, idlcall), Cint, (Cint, Ptr{Cint}, Ptr{Ptr{UInt8}}), - 0, C_NULL, C_NULL) + ecode = ccall((:IDL_Initialize, idlcall), Cint, + (Cint, Ptr{Cint}, Ptr{Ptr{UInt8}}), 0, C_NULL, C_NULL) ecode == 0 && error("IDL.init: IDL init failed") global output_cb ccall((:IDL_ToutPush, idlcall), Nothing, (Ptr{Nothing},), output_cb) From 34597ff4af7fc66a19a9b92bb1f9730aaf2e3704 Mon Sep 17 00:00:00 2001 From: hyzhou Date: Mon, 17 Feb 2020 09:47:21 -0500 Subject: [PATCH 36/38] Update comments. --- README.md | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 193ba14..9f89a2e 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Note that by default `IDL.jl` uses the `RPC` interface on Mac and Linux and `Cal In `RPC` all arrays are copied between processes. Note that I have run into issues with IDL loading DLM's while using `Callable` (e.g., NetCDF). -- IDL `RPC` is not supported on windows +- IDL `RPC` is not supported on windows. - `Callable` is always managed by `IDL.jl` while `RPC` can be managed by `IDL.jl` or the user. By managed we mean that it is opened it when you load `IDL.jl` and closed it when you close julia. @@ -34,16 +34,16 @@ Note that by default `IDL.jl` uses the `RPC` interface on Mac and Linux and `Cal using IDL ``` You can add a Julia variable to the IDL process with -``` +```julia x = 1 put_var(x, "x") ``` and you can retrieve variable into Julia using -``` +```julia x = get_var("x") ``` You can run an arbitrary chunk of code in IDL using -``` +```julia idl.execute("any valid idl code") ``` Note that only primitive data types are supported at this time (e.g., structure variables are not supported yet). Also, `[;|\$]` inside quotes won't be correctly recognized. @@ -58,10 +58,16 @@ IDL.full_reset IDL.dotrun ``` +See more examples in the [test script](test/runtests.jl) + ## REPL You can drop into an IDL REPL by typing `>` at the Julia prompt. Then you can type any valid IDL commands, including using continuation characters `$` for multi-line commands. One experimental feature I have added is the use of `%var` will auto-magically import the Julia variable `var` into the IDL process. This works at the IDL prompt or in strings passed into the `execute` function. +## Note + +The IDL `RPC` library won't be automatically reset if you exit Julia. Therefore, currently you need to type `IDL.reset()` to cleanup the library. + ## ToDo - Make more flexible to install on all platforms From 5d4983141434a5e988f08f60e58b92b43521c3cb Mon Sep 17 00:00:00 2001 From: hyzhou Date: Mon, 17 Feb 2020 10:28:19 -0500 Subject: [PATCH 37/38] Reset IDL RPC during initialization. --- src/IDL.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/IDL.jl b/src/IDL.jl index a0e30ac..9bc556e 100644 --- a/src/IDL.jl +++ b/src/IDL.jl @@ -32,6 +32,7 @@ include("IDLREPL.jl") function __init__() if jl_idl_type == "RPC" rpc_init() + full_reset() # Reset IDL elseif jl_idl_type == "CALLABLE" callable_init() # not yet working for MaxOS and Linux end From 835ad0d4b0704bcaf4a4f0c580d25941a95b3f62 Mon Sep 17 00:00:00 2001 From: hyzhou Date: Mon, 17 Feb 2020 16:38:52 -0500 Subject: [PATCH 38/38] Mentioned callable issue on Mac. --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 9f89a2e..e06c4d6 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,9 @@ Note that by default `IDL.jl` uses the `RPC` interface on Mac and Linux and `Cal By managed we mean that it is opened it when you load `IDL.jl` and closed it when you close julia. To manage `RPC` yourself run `idlrpc` in a shell before starting `IDL.jl`. This allows the `idlrpc` session to persist and julia can be restarted without killing the `idlrpc` process. + Currently `RPC` is always reset after the initialization of `IDL.jl`. + +There is an [issue](https://github.com/JuliaLang/julia/issues/7004) of opening `libidl` on Mac. ## Quickstart