chrono = "0.4.11"
select = "0.4.3"
roxmltree = "0.11.0"
+base64 = "0.12.3"
file, reading lazily only as much as is needed. Due to the compact
internal string representation, also extremely large files can be
efficiently processed with Scryer Prolog in this way.
-* [`charsio`](src/lib/charsio.pl) Various predicates that are
- useful for parsing and reasoning about characters, notably
- `char_type/2` to classify characters according to their type.
+* [`charsio`](src/lib/charsio.pl) Various predicates that are useful
+ for parsing and reasoning about characters, notably `char_type/2` to
+ classify characters according to their type, and conversion
+ predicates for different encodings of strings.
* [`error`](src/lib/error.pl)
`must_be/2` and `can_be/2` complement the type checks provided by
[`library(si)`](src/lib/si.pl), and are especially useful for
GetEnv,
SetEnv,
UnsetEnv,
+ CharsBase64,
}
impl SystemClauseType {
&SystemClauseType::GetEnv => clause_name!("$getenv"),
&SystemClauseType::SetEnv => clause_name!("$setenv"),
&SystemClauseType::UnsetEnv => clause_name!("$unsetenv"),
+ &SystemClauseType::CharsBase64 => clause_name!("$chars_base64"),
}
}
("$getenv", 2) => Some(SystemClauseType::GetEnv),
("$setenv", 2) => Some(SystemClauseType::SetEnv),
("$unsetenv", 1) => Some(SystemClauseType::UnsetEnv),
+ ("$chars_base64", 4) => Some(SystemClauseType::CharsBase64),
_ => None,
}
}
get_single_char/1,
read_line_to_chars/3,
read_term_from_chars/2,
- write_term_to_chars/3]).
+ write_term_to_chars/3,
+ chars_base64/3]).
:- use_module(library(dcgs)).
:- use_module(library(iso_ext)).
; read_line_to_chars(Stream, Rest, Cs)
)
).
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ Relation between a list of characters Cs and its Base64 encoding Bs,
+ also a list of characters.
+
+ Options are:
+
+ - padding(Boolean)
+ Whether to use padding: true (the default) or false.
+ - charset(C)
+ Either 'standard' (RFC 4648 §4, the default) or 'url' (RFC 4648 §5).
+
+ Example:
+
+ ?- chars_base64("hello", Bs, []).
+ Bs = "aGVsbG8="
+ ; false.
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+chars_base64(Cs, Bs, Options) :-
+ must_be(list, Options),
+ ( member(O, Options), var(O) ->
+ instantiation_error(chars_base64/3)
+ ; ( member(padding(Padding), Options) -> true
+ ; Padding = true
+ ),
+ ( member(charset(Charset), Options) -> true
+ ; Charset = standard
+ )
+ ),
+ must_be(boolean, Padding),
+ ( var(Cs) ->
+ must_be(list, Bs),
+ maplist(must_be(character), Bs),
+ '$chars_base64'(Cs, Bs, Padding, Charset)
+ ; must_be(list, Cs),
+ maplist(must_be(character), Cs),
+ '$chars_base64'(Cs, Bs, Padding, Charset)
+ ).
extern crate select;
use roxmltree;
+use base64;
pub fn get_key() -> KeyEvent {
let key;
let key = self.heap_pstr_iter(self[temp_v!(1)]).to_string();
env::remove_var(key);
}
+ &SystemClauseType::CharsBase64 => {
+ let mut options = vec![];
+
+ for i in 3..5 {
+ match self.store(self.deref(self[temp_v!(i)])) {
+ Addr::Con(h) if self.heap.atom_at(h) => {
+ if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] {
+ options.push(atom.as_str());
+ } else {
+ unreachable!()
+ }
+ }
+ _ => {
+ unreachable!()
+ }
+ };
+ }
+
+ let config =
+ if options[0] == "true" {
+ if options[1] == "standard" {
+ base64::STANDARD
+ } else {
+ base64::URL_SAFE
+ }
+ } else {
+ if options[1] == "standard" {
+ base64::STANDARD_NO_PAD
+ } else {
+ base64::URL_SAFE_NO_PAD
+ }
+ };
+
+ if self.store(self.deref(self[temp_v!(1)])).is_ref() {
+ let b64 = self.heap_pstr_iter(self[temp_v!(2)]).to_string();
+ let bytes = base64::decode_config(b64, config);
+
+ match bytes {
+ Ok(bs) => {
+ let mut string = String::new();
+ for c in bs {
+ string.push(c as char);
+ }
+ let cstr = self.heap.put_complete_string(&string);
+ self.unify(self[temp_v!(1)], cstr);
+ }
+ _ => {
+ self.fail = true;
+ return Ok(());
+ }
+ }
+ } else {
+ let mut bytes = vec![];
+ for c in self.heap_pstr_iter(self[temp_v!(1)]).to_string().chars() {
+ bytes.push(c as u8);
+ }
+ let b64 = base64::encode_config(bytes, config);
+
+ let cstr = self.heap.put_complete_string(&b64);
+ self.unify(self[temp_v!(2)], cstr);
+ }
+ }
};
return_from_clause!(self.last_call, self)