use std::borrow::Cow;
use std::ffi::{CStr, CString};
use std::path::Path;
use std::ptr;
use ll::*;
use tcl::{TclResult, TclEnvironment};
use object::{Object, TclObject};
pub enum EvalScope {
Local = 0,
Global = TCL_EVAL_GLOBAL as isize,
}
pub enum ByteCompile {
Compile = 0,
Direct = TCL_EVAL_DIRECT as isize
}
pub enum SetVariableScope {
Standard = 0,
GlobalOnly = TCL_GLOBAL_ONLY as isize,
NamespaceOnly = TCL_NAMESPACE_ONLY as isize,
}
pub enum GetVariableScope {
Standard = 0,
GlobalOnly = TCL_GLOBAL_ONLY as isize,
}
pub enum LeaveError {
No = 0,
Yes = TCL_LEAVE_ERR_MSG as isize
}
pub enum AppendStyle {
Replace = 0,
Append = TCL_APPEND_VALUE as isize,
ReplaceAsList = TCL_LIST_ELEMENT as isize,
AppendAsList = (TCL_APPEND_VALUE | TCL_LIST_ELEMENT) as isize
}
pub struct Interpreter<'env> {
_env: &'env TclEnvironment,
raw: *mut Tcl_Interp
}
impl <'env> Drop for Interpreter<'env> {
fn drop(&mut self) {
unsafe { Tcl_DeleteInterp(self.raw) };
}
}
impl<'env> Interpreter<'env> {
pub fn new(env: &TclEnvironment) -> Result<Interpreter, &str> {
unsafe {
let raw = Tcl_CreateInterp();
if raw == ptr::null_mut() {
Err("Failed to create interpreter")
} else {
if Tcl_Init(raw) != TCL_OK {
Err("Couldn't initialize interpreter")
} else {
Ok(Interpreter {
_env: env,
raw: raw
})
}
}
}
}
pub unsafe fn raw(&mut self) -> *mut Tcl_Interp {
self.raw
}
pub fn is_safe(&self) -> bool {
unsafe { Tcl_IsSafe(self.raw) == 1 }
}
pub fn make_safe(&mut self) -> TclResult {
let result = unsafe { Tcl_MakeSafe(self.raw) };
TclResult::from_ll(result, self)
}
pub fn string_result(&self) -> Cow<str> {
unsafe {
let string = Tcl_GetStringResult(self.raw);
String::from_utf8_lossy(CStr::from_ptr(string).to_bytes())
}
}
pub fn object_result(&self) -> Object<'env> {
unsafe {
let object = Tcl_GetObjResult(self.raw);
Object::from_raw(self._env, object)
}
}
pub fn eval_file(&mut self, path: &Path) -> TclResult {
let buf = CString::new(path.to_string_lossy().as_bytes()).unwrap().as_ptr();
let result = unsafe {
Tcl_EvalFile(self.raw, buf)
};
TclResult::from_ll(result, self)
}
pub fn eval(&mut self, code: &str, eval_scope: EvalScope) -> TclResult {
let buf = CString::new(code.as_bytes()).unwrap().as_ptr();
let flags = eval_scope as i32;
let result = unsafe {
Tcl_EvalEx(self.raw, buf, code.len() as i32, flags)
};
TclResult::from_ll(result, self)
}
pub fn eval_object(&mut self, code: &Object, eval_scope: EvalScope, byte_compile: ByteCompile) -> TclResult {
let flags = (eval_scope as i32) | (byte_compile as i32);
let result = unsafe {
Tcl_EvalObjEx(self.raw, code.raw(), flags)
};
TclResult::from_ll(result, self)
}
pub fn list_append(&mut self, target: &mut Object, source: &Object) -> TclResult {
let result = unsafe {
Tcl_ListObjAppendElement(self.raw, target.raw(), source.raw())
};
TclResult::from_ll(result, self)
}
pub fn expression_boolean<'a>(&'a mut self, expr: &str) -> Result<bool, Cow<'a, str>> {
let mut output = 0;
let buf = CString::new(expr.as_bytes()).unwrap().as_ptr();
unsafe {
if Tcl_ExprBoolean(self.raw, buf, &mut output) == TCL_OK {
Ok(output == 1)
} else {
Err(self.string_result())
}
}
}
pub fn expression_boolean_from_object<'a>(&'a mut self, expr: &Object) -> Result<bool, Cow<'a, str>> {
let mut output = 0;
unsafe {
if Tcl_ExprBooleanObj(self.raw, expr.raw(), &mut output) == TCL_OK {
Ok(output == 1)
} else {
Err(self.string_result())
}
}
}
pub fn expression_double<'a>(&'a mut self, expr: &str) -> Result<f64, Cow<'a, str>> {
let mut output = 0.0;
let buf = CString::new(expr.as_bytes()).unwrap().as_ptr();
unsafe {
if Tcl_ExprDouble(self.raw, buf, &mut output) == TCL_OK {
Ok(output)
} else {
Err(self.string_result())
}
}
}
pub fn expression_double_from_object<'a>(&'a mut self, expr: &Object) -> Result<f64, Cow<'a, str>> {
let mut output = 0.0;
unsafe {
if Tcl_ExprDoubleObj(self.raw, expr.raw(), &mut output) == TCL_OK {
Ok(output)
} else {
Err(self.string_result())
}
}
}
pub fn expression_long<'a>(&'a mut self, expr: &str) -> Result<i64, Cow<'a, str>> {
let mut output = 0;
let buf = CString::new(expr.as_bytes()).unwrap().as_ptr();
unsafe {
if Tcl_ExprLong(self.raw, buf, &mut output) == TCL_OK {
Ok(output)
} else {
Err(self.string_result())
}
}
}
pub fn expression_long_from_object<'a>(&'a mut self, expr: &Object) -> Result<i64, Cow<'a, str>> {
let mut output = 0;
unsafe {
if Tcl_ExprLongObj(self.raw, expr.raw(), &mut output) == TCL_OK {
Ok(output)
} else {
Err(self.string_result())
}
}
}
pub fn expression_object_from_object<'a>(&'a mut self, expr: &Object) -> Result<Object<'env>, Cow<'a, str>> {
let mut output = ptr::null_mut();
unsafe {
if Tcl_ExprObj(self.raw, expr.raw(), &mut output) == TCL_OK {
Ok(Object::from_raw(self._env, output))
} else {
Err(self.string_result())
}
}
}
pub fn expression_string(&mut self, expr: &str) -> TclResult {
let buf = CString::new(expr.as_bytes()).unwrap().as_ptr();
let result = unsafe {
Tcl_ExprString(self.raw, buf)
};
TclResult::from_ll(result, self)
}
pub fn set_string_variable(&mut self, var_name: &str, new_value: &str,
scope: SetVariableScope, leave_error: LeaveError, append_style: AppendStyle) -> String {
let flags = scope as i32 | leave_error as i32 | append_style as i32;
let var_buf = CString::new(var_name.as_bytes()).unwrap().as_ptr();
let val_buf = CString::new(new_value.as_bytes()).unwrap().as_ptr();
unsafe {
let result = Tcl_SetVar(self.raw, var_buf, val_buf, flags);
String::from_utf8_lossy(CStr::from_ptr(result).to_bytes()).to_string()
}
}
pub fn set_variable<V: TclObject>(&mut self, var_name: &str, new_value: V)
-> Option<Object<'env>> {
self.set_object_variable(
&Object::new(self._env, var_name), &Object::new(self._env, new_value),
SetVariableScope::Standard,
LeaveError::No,
AppendStyle::Replace
)
}
pub fn set_object_variable(&mut self, var_name: &Object, new_value: &Object,
scope: SetVariableScope, leave_error: LeaveError, append_style: AppendStyle) -> Option<Object<'env>> {
let flags = scope as i32 | leave_error as i32 | append_style as i32;
unsafe {
let result = Tcl_ObjSetVar2(self.raw, var_name.raw(), ptr::null_mut(), new_value.raw(), flags);
if result == ptr::null_mut() {
None
} else {
Some(Object::from_raw(self._env, result))
}
}
}
pub fn get_variable(&mut self, var_name: &str, scope: GetVariableScope, leave_error: LeaveError) -> Option<String> {
let flags = scope as i32 | leave_error as i32;
let var_buf = CString::new(var_name.as_bytes()).unwrap().as_ptr();
unsafe {
let result = Tcl_GetVar(self.raw, var_buf, flags);
if result != ptr::null() {
Some(String::from_utf8_lossy(CStr::from_ptr(result).to_bytes()).to_string())
} else {
None
}
}
}
pub fn get_object_variable(&mut self, var_name: &str, scope: GetVariableScope, leave_error: LeaveError) -> Option<Object<'env>> {
let flags = scope as i32 | leave_error as i32;
let var_buf = CString::new(var_name.as_bytes()).unwrap().as_ptr();
unsafe {
let result = Tcl_GetVar2Ex(self.raw, var_buf, ptr::null_mut(), flags);
if result == ptr::null_mut() {
None
} else {
Some(Object::from_raw(self._env, result))
}
}
}
pub fn unset_variable(&mut self, var_name: &str, scope: GetVariableScope, leave_error: LeaveError) -> TclResult {
let flags = scope as i32 | leave_error as i32;
let buf = CString::new(var_name.as_bytes()).unwrap().as_ptr();
let result = unsafe {
Tcl_UnsetVar(self.raw, buf, flags)
};
TclResult::from_ll(result, self)
}
}