1#![doc = include_str!("../README.md")]
2
3pub mod constants;
4mod default_json;
5pub mod doc;
6pub mod utils;
7
8use crate::constants::*;
9use crate::default_json::*;
10use crate::utils::*;
11
12use chrono::Utc;
13use md5::{Digest, Md5};
14use sha2::Sha256;
15use rand::Rng;
16use regex::Regex;
17use serde_json::json;
18use serde_json::Value;
19use std::env;
20use std::fs;
21use std::path::Path;
22use std::str;
23use std::time::Duration;
24use std::time::Instant;
25use std::time::{SystemTime, UNIX_EPOCH};
26use std::io::Write;
27use std::fs::File;
28
29#[macro_use]
122mod macros {
123 macro_rules! new_child_parse {
124 ($self:expr, $source:expr, $scope:expr) => {{
125 let mut child_inherit = $self.inherit.clone();
126 let shared = &mut $self.shared;
127
128 child_inherit.alias = $self.alias.clone();
131
132 if !$self.file_path.is_empty() {
133 child_inherit.current_file = $self.file_path.clone();
134 }
135
136 if !$self.dir.is_empty() {
137 child_inherit.current_dir = $self.dir.clone();
138 }
139
140 if $scope {
144 $self.inherit.create_block_schema(shared);
145 }
146
147 let mut block = BlockParser::new(shared, &child_inherit);
148 let code = block.parse($source, $self.only);
149
150 if $scope {
152 block.update_indir(&$self.inherit.indir);
155 }
156
157 code
158 }};
159 }
160}
161
162struct BifError {
163 msg: String,
164 name: String,
165 src: String,
166}
167
168struct Shared {
170 schema: Value,
171 lang: String,
172 comments: String,
173 bisf_count: u64,
174 bisf_max: u64,
175 flags: String,
176 exit: bool,
177 has_error: bool,
178 status_code: String,
179 status_text: String,
180 status_param: String,
181 redirect_js: String,
182 filter_all: bool,
183 filter_bifs: bool,
184 cache_prefix: String,
185 cache_dir: String,
186 cache_on_post: bool,
187 cache_on_get: bool,
188 cache_on_cookies: bool,
189 cache_disable: bool,
190 disable_js: bool,
191 already_js: bool,
192 working_dir: String,
193}
194
195impl Shared {
196 fn new(schema: Value) -> Self {
197 let bisf_max = schema["config"]["infinite_loop_max_bifs"].as_u64().unwrap();
198 let comments = get_from_key(&schema["config"], "comments");
199 let lang = get_from_key(&schema["inherit"]["locale"], "current");
200 let filter_all = is_bool_key(&schema["config"], "filter_all");
201 let cache_prefix = get_from_key(&schema["config"], "cache_prefix");
202 let mut cache_dir = get_from_key(&schema["config"], "cache_dir");
203 let working_dir = env::current_dir().unwrap().to_string_lossy().into_owned();
204 let cache_on_post= is_bool_key(&schema["config"], "cache_on_post");
205 let cache_on_get= is_bool_key(&schema["config"], "cache_on_get");
206 let cache_on_cookies= is_bool_key(&schema["config"], "cache_on_cookies");
207 let cache_disable= is_bool_key(&schema["config"], "cache_disable");
208 let disable_js= is_bool_key(&schema["config"], "disable_js");
209 let mut filter_bifs = false;
210
211 if !cache_disable {
212 filter_bifs = true;
213 }
214
215 if cache_dir.is_empty() {
216 cache_dir = env::temp_dir().to_string_lossy().into_owned();
217 }
218
219 Shared {
220 schema,
221 lang,
222 comments,
223 bisf_count: 0,
224 bisf_max,
225 flags: String::new(),
226 exit: false,
227 has_error: false,
228 status_code: "200".to_string(),
229 status_text: "OK".to_string(),
230 status_param: String::new(),
231 redirect_js: String::new(),
232 filter_all,
233 filter_bifs,
234 cache_prefix,
235 cache_dir,
236 cache_on_post,
237 cache_on_get,
238 cache_on_cookies,
239 cache_disable,
240 disable_js,
241 already_js: false,
242 working_dir,
243 }
244 }
245}
246
247struct BlockInherit {
248 indir: String,
249 last_bif_out: bool,
250 last_coalesce_out: bool,
251 block_count: u64, bif_count: u64, alias: String,
254 current_file: String,
255 current_dir: String,
256 include_files: Vec<String>,
257 locale_files: Vec<String>,
258 data_files: Vec<String>,
259 in_cache: bool,
260 in_only: bool,
261}
262
263impl Clone for BlockInherit {
264 fn clone(&self) -> Self {
265 BlockInherit {
266 indir: self.indir.clone(),
267 last_bif_out: self.last_bif_out,
268 last_coalesce_out: self.last_coalesce_out,
269 block_count: self.block_count,
270 bif_count: self.bif_count,
271 alias: self.alias.clone(),
272 current_file: self.current_file.clone(),
273 current_dir: self.current_dir.clone(),
274 include_files: self.include_files.clone(),
275 locale_files: self.locale_files.clone(),
276 data_files: self.data_files.clone(),
277 in_cache: self.in_cache,
278 in_only: self.in_only,
279 }
280 }
281}
282
283impl BlockInherit {
284 fn new() -> Self {
285 BlockInherit {
286 indir: "block_0".to_string(),
287 last_bif_out: false,
288 last_coalesce_out: false,
289 block_count: 0,
290 bif_count: 0,
291 alias: String::new(),
292 current_file: String::new(),
293 current_dir: String::new(),
294 include_files: Vec::new(),
295 locale_files: Vec::new(),
296 data_files: Vec::new(),
297 in_cache: false,
298 in_only: false,
299 }
300 }
301
302 fn create_block_schema(&mut self, shared: &mut Shared) -> String {
308 let prev_id = self.indir.clone();
309 let block_id;
310
311 if self.block_count < 1 {
315 block_id = "block_1".to_string();
316 } else {
317 block_id = "block_".to_string() + self.block_count.to_string().as_str();
318 }
319
320 if prev_id != block_id {
323 shared.schema["__indir"][&block_id] = shared.schema["__indir"][&prev_id].clone();
324 }
325
326 self.indir = block_id.clone();
327
328 block_id
329 }
330}
331
332pub struct Template<'a> {
333 raw: String,
334 file_path: &'a str,
335 schema: Value,
336 shared: Shared,
337 time_start: Instant,
338 time_elapsed: Duration,
339 out: String,
340}
341
342impl<'a> Template<'a> {
346 pub fn new() -> Result<Self, String> {
350 let default_schema: Value = match serde_json::from_str(DEFAULT) {
351 Ok(value) => value,
352 Err(_) => return Err("const DEFAULT is not a valid JSON string".to_string()),
353 };
354 let shared = Shared::new(default_schema.clone());
355
356 Ok(Template {
357 raw: String::new(),
358 file_path: "",
359 schema: default_schema,
360 shared,
361 time_start: Instant::now(),
362 time_elapsed: Instant::now().elapsed(),
363 out: String::new(),
364 })
365 }
366
367 pub fn from_file_value(file_path: &'a str, schema: Value) -> Result<Self, String> {
379 let raw: String = match fs::read_to_string(file_path) {
380 Ok(s) => s,
381 Err(e) => {
382 eprintln!("Cannot be read: {}", file_path);
383 return Err(e.to_string());
384 }
385 };
386 let mut default_schema: Value = match serde_json::from_str(DEFAULT) {
387 Ok(value) => value,
388 Err(_) => {
389 eprintln!("Internal error in const DEFAULT {}, line: {}", file!(), line!());
390 return Err("const DEFAULT is not a valid JSON string".to_string());
391 }
392 };
393
394 merge_schema(&mut default_schema, &schema);
395 let shared = Shared::new(default_schema.clone());
396
397 Ok(Template {
398 raw,
399 file_path,
400 schema: default_schema,
401 shared,
402 time_start: Instant::now(),
403 time_elapsed: Instant::now().elapsed(),
404 out: String::new(),
405 })
406 }
407
408 pub fn set_src_path(&mut self, file_path: &'a str) -> Result<(), String> {
418 self.file_path = file_path;
419 self.raw = match fs::read_to_string(file_path) {
420 Ok(s) => s,
421 Err(e) => {
422 eprintln!("Cannot be read: {}", file_path);
423 return Err(e.to_string());
424 }
425 };
426
427 Ok(())
428 }
429
430 pub fn set_src_str(&mut self, source: &str) {
436 self.raw = source.to_string();
437 }
438
439 pub fn merge_schema_path(&mut self, schema_path: &str) -> Result<(), String> {
451 let schema_str: String = match fs::read_to_string(schema_path) {
452 Ok(s) => s,
453 Err(e) => {
454 eprintln!("Cannot be read: {}", schema_path);
455 return Err(e.to_string());
456 }
457 };
458 let schema_value: Value = match serde_json::from_str(&schema_str) {
459 Ok(value) => value,
460 Err(_) => {
461 return Err("Is not a valid JSON file".to_string());
462 }
463 };
464 merge_schema(&mut self.schema, &schema_value);
465
466 Ok(())
467 }
468
469 pub fn merge_schema_str(&mut self, schema: &str) -> Result<(), String> {
480 let schema_value: Value = match serde_json::from_str(schema) {
481 Ok(value) => value,
482 Err(_) => {
483 return Err("Is not a valid JSON string".to_string());
484 }
485 };
486 merge_schema(&mut self.schema, &schema_value);
487
488 Ok(())
489 }
490
491 pub fn merge_schema_value(&mut self, schema: Value) {
497 merge_schema(&mut self.schema, &schema);
498 }
499
500 pub fn render(&mut self) -> String {
509 let inherit = self.init_render();
510 self.out = BlockParser::new(&mut self.shared, &inherit).parse(&self.raw, "");
511
512 while self.out.contains("{:!cache;") {
513 let out;
514 out = BlockParser::new(&mut self.shared, &inherit).parse(&self.out, "!cache");
515 self.out = out;
516 }
517
518 self.ends_render();
519
520 self.out.clone()
521 }
522
523 fn init_render(&mut self) -> BlockInherit {
525 self.time_start = Instant::now();
526 self.shared = Shared::new(self.schema.clone());
527
528 if self.shared.comments.contains("remove") {
529 self.raw = remove_comments(&self.raw);
530 }
531
532 let mut inherit = BlockInherit::new();
534 let indir = inherit.create_block_schema(&mut self.shared);
535 self.shared.schema["__moveto"] = json!({});
536 self.shared.schema["__error"] = json!([]);
537 self.shared.schema["__indir"] = json!({});
538 self.shared.schema["__indir"][&indir] = self.shared.schema["inherit"].clone();
539 inherit.current_file = self.file_path.to_string();
540
541 filter_value(&mut self.shared.schema["data"]["CONTEXT"]);
543
544 filter_value_keys(&mut self.shared.schema["data"]["CONTEXT"]);
546
547 if !self.file_path.is_empty() {
548 let path = Path::new(&self.file_path);
549
550 if let Some(parent) = path.parent() {
551 inherit.current_dir = parent.display().to_string();
552 }
553 } else {
554 inherit.current_dir = self.shared.working_dir.clone();
555 }
556
557 inherit
558 }
559
560 fn ends_render(&mut self) {
562 self.set_moveto();
563 self.replacements();
564 self.set_status_code();
565 self.time_elapsed = self.time_start.elapsed();
566 }
567
568 fn set_status_code(&mut self) {
569 let status_code = self.shared.status_code.as_str();
570
571 if ("400"..="599").contains(&status_code) {
572 self.out = format!("{} {}", self.shared.status_code, self.shared.status_text);
573
574 return;
575 }
576
577 if status_code == "301"
578 || status_code == "302"
579 || status_code == "303"
580 || status_code == "307"
581 || status_code == "308"
582 {
583 self.out = format!(
584 "{} {}\n{}",
585 self.shared.status_code, self.shared.status_text, self.shared.status_param
586 );
587
588 return;
589 }
590
591 if !self.shared.redirect_js.is_empty() {
592 self.out = self.shared.redirect_js.clone();
593 }
594 }
595
596 fn set_moveto(&mut self) {
597 if let Value::Object(data_map) = &self.shared.schema["__moveto"] {
598 for (_key, value) in data_map {
599 if let Value::Object(inner_map) = value {
600 for (inner_key, inner_value) in inner_map {
601 let mut tag;
602
603 if !inner_key.starts_with("<") {
606 tag = format!("<{}", inner_key);
607 } else {
608 tag = inner_key.to_string();
609 }
610 if tag.ends_with(">") {
611 tag = tag[..tag.len() - 1].to_string();
612 }
613
614 let position = find_tag_position(&self.out, &tag);
616 if let Some(pos) = position {
617 let mut insert = inner_value.as_str().unwrap().to_string();
618 insert = insert.to_string();
619 self.out.insert_str(pos, &insert);
620 }
621 }
622 }
623 }
624 }
625 }
626
627 fn replacements(&mut self) {
628 let pattern = format!(r"\s*{}", BACKSPACE);
629 let re = Regex::new(&pattern).expect("Failed to create regex with constant pattern");
630 self.out = re.replace_all(&self.out, "").to_string();
631
632 self.out = self.out.replace(UNPRINTABLE, "");
634 }
635
636 pub fn get_status_code(&self) -> &String {
646 &self.shared.status_code
647 }
648
649 pub fn get_status_text(&self) -> &String {
657 &self.shared.status_text
658 }
659
660 pub fn get_status_param(&self) -> &String {
670 &self.shared.status_param
671 }
672
673 pub fn has_error(&self) -> bool {
681 self.shared.has_error
682 }
683
684 pub fn get_error(&self) -> Value {
690 self.shared.schema["__error"].clone()
691 }
692
693 pub fn get_time_duration(&self) -> Duration {
699 let duration: std::time::Duration = self.time_elapsed;
700
701 duration
702 }
703}
704
705struct BlockParser<'a> {
706 shared: &'a mut Shared,
707 inherit: BlockInherit,
708 _none: &'a str,
709}
710
711impl Drop for BlockParser<'_> {
712 fn drop(&mut self) {
713 let block_id = "block_".to_string() + self.inherit.block_count.to_string().as_str();
715
716 if block_id != "block_1" {
718 if block_id == self.inherit.indir && is_defined_key(&self.shared.schema["__indir"], &block_id) {
719 self.shared.schema["__indir"][&block_id] = json!({});
720 }
721 }
722 }
723}
724
725impl<'a> BlockParser<'a> {
726 fn new(shared: &'a mut Shared, inherit: &BlockInherit) -> Self {
727 let mut inherit = inherit.clone();
728 inherit.block_count += 1;
729
730 BlockParser {
731 shared,
732 inherit,
733 _none: "",
734 }
735 }
736
737 fn update_indir(&mut self, indir: &String) {
738 self.shared.schema["__indir"][indir] =
739 self.shared.schema["__indir"][&self.inherit.indir].clone();
740 }
741
742 fn parse(&mut self, raw_source: &'a str, only: &str) -> String {
743 let blocks;
744
745 match extract_blocks(raw_source) {
746 Ok(b) => {
747 blocks = b;
748 }
749 Err(p) => {
750 self.shared.status_code = "500".to_string();
751 self.shared.status_param = format!("Unmatched block at position {}", p);
752 eprintln!("Unmatched block at position {}", p);
753
754 if let Some(text) = STATUS_CODES.get(self.shared.status_code.as_str()) {
755 self.shared.status_text = text.to_string();
756 } else {
757 self.shared.status_text = EMPTY_STRING;
758 }
759
760 return EMPTY_STRING;
761 }
762 }
763
764 let mut prev_end = 0;
765 let mut out = String::new();
766 for (start, end) in blocks {
767 let is_comment = raw_source[start..end].starts_with(BIF_COMMENT_OPEN);
768 let is_short_circuit_coalesce =
769 self.inherit.last_coalesce_out && self.inherit.alias == "coalesce";
770
771 if self.shared.exit {
772 return out.clone();
773 }
774
775 if prev_end < start {
776 out += &raw_source[prev_end..start];
777 }
778
779 if !is_comment && !is_short_circuit_coalesce {
780 let mut bif =
781 Bif::new(&raw_source[start..end], self.shared, &mut self.inherit, only);
782 out += &bif.parse();
783 }
784
785 prev_end = end;
786 }
787 out += &raw_source[prev_end..];
788
789 out.trim().to_string()
790 }
791}
792
793struct Bif<'a> {
794 raw: &'a str,
795 shared: &'a mut Shared,
796 inherit: &'a mut BlockInherit,
797 src: String,
798 name: String,
799 alias: String,
800 code: String,
801 params: String,
802 flags: String,
803 mod_filter: bool,
804 mod_negate: bool,
805 mod_upline: bool,
806 mod_scope: bool,
807 file_path: String,
808 dir: String,
809 out: String,
810 only: &'a str,
811 _none: &'a str,
812}
813
814impl<'a> Bif<'a> {
815 fn new(raw_source: &'a str, shared: &'a mut Shared, inherit: &'a mut BlockInherit, only: &'a str) -> Self {
816 shared.bisf_count += 1;
817 let count = shared.bisf_count;
818 inherit.bif_count = shared.bisf_count;
819
820 if count > shared.bisf_max {
821 panic!(
822 "Infinite loop? {} bifs of {} max have been created.",
823 shared.bisf_max, count
824 );
825 }
826
827 Bif {
828 raw: raw_source, shared,
830 inherit,
831 src: String::new(),
832 name: String::new(),
833 alias: String::new(),
834 code: String::new(),
835 params: String::new(),
836 flags: String::new(),
837 mod_filter: false,
838 mod_negate: false,
839 mod_upline: false,
840 mod_scope: false,
841 file_path: String::new(),
842 dir: String::new(),
843 out: String::new(),
844 only,
845 _none: "",
846 }
847 }
848
849 fn parse(&mut self) -> String {
851 let bif = strip_prefix_suffix(self.raw, BIF_OPEN, BIF_CLOSE);
852 let result;
853
854 if let Some((name, src)) = bif.split_once(BIF_NAME) {
855 self.name = name.to_string();
856 self.src = src.trim().to_string();
857 } else {
858 if !self.only.is_empty() {
859 return self.raw.to_string();
860 }
861
862 let show_error = self.shared.schema["config"]["error"]["show"].as_bool().unwrap();
863 let error_line = format!("The delimiter was not found: {}", self.raw);
864 let error_line = error_line.replace(['\n', '\r'], " ");
865
866 if let Some(Value::Array(errors)) = self.shared.schema.get_mut("__error") {
867 errors.push(json!(error_line));
868 }
869
870 if show_error {
871 eprintln!("{}", error_line);
872 }
873
874 self.shared.has_error = true;
875
876 return EMPTY_STRING;
877 }
878
879 if !self.only.is_empty() && !self.name.contains(self.only) && !self.inherit.in_only {
880 return self.raw.to_string();
881 }
882
883 self.name = self.set_modifiers();
884 self.alias = self.name.clone();
885 self.inherit.in_only = true;
886
887 match &self.name[..] {
889 "" => result = self.parse_bif_var(),
890 "allow" => result = self.parse_bif_allow(),
891 "array" => result = self.parse_bif_array(),
892 "bool" => result = self.parse_bif_bool(),
893 "cache" => result = self.parse_bif_cache(),
894 "coalesce" => result = self.parse_bif_coalesce(),
895 "code" => result = self.parse_bif_code(),
896 "contains" => result = self.parse_bif_contains(),
897 "count" => result = self.parse_bif_count(),
898 "data" => result = self.parse_bif_data(),
899 "date" => result = self.parse_bif_date(),
900 "declare" => result = self.parse_bif_declare(),
901 "defined" => result = self.parse_bif_defined(),
902 "each" => result = self.parse_bif_each(),
903 "else" => result = self.parse_bif_else(),
904 "eval" => result = self.parse_bif_eval(),
905 "exit" => result = self.parse_bif_exit(),
906 "fetch" => result = self.parse_bif_fetch(),
907 "filled" => result = self.parse_bif_filled(),
908 "flg" => result = self.parse_bif_flg(),
909 "for" => result = self.parse_bif_for(),
910 "hash" => result = self.parse_bif_hash(),
911 "include" => result = self.parse_bif_include(),
912 "join" => result = self.parse_bif_join(),
913 "lang" => result = self.parse_bif_lang(),
914 "locale" => result = self.parse_bif_locale(),
915 "moveto" => result = self.parse_bif_moveto(),
916 "neutral" => result = self.parse_bif_neutral(),
917 "param" => result = self.parse_bif_param(),
918 "rand" => result = self.parse_bif_rand(),
919 "redirect" => result = self.parse_bif_redirect(),
920 "replace" => result = self.parse_bif_replace(),
921 "same" => result = self.parse_bif_same(),
922 "snippet" => result = self.parse_bif_snippet(),
923 "snip" => result = self.parse_bif_snippet(),
924 "trans" => result = self.parse_bif_trans(),
925 _ => result = self.parse_bif_unknown(),
926 }
927
928 match result {
929 Ok(()) => (),
930 Err(e) => {
931 let show_error = self.shared.schema["config"]["error"]["show"].as_bool().unwrap();
932 let error_line = format!("Error ({}) {} src: {}", e.name, e.msg, e.src);
933 let error_line = error_line.replace(['\n', '\r'], " ");
934
935 if let Some(Value::Array(errors)) = self.shared.schema.get_mut("__error") {
936 errors.push(json!(error_line));
937 }
938
939 if show_error {
940 eprintln!("{}", error_line);
941 }
942
943 self.shared.has_error = true;
944 }
945 }
946
947 self.inherit.last_bif_out = !self.out.is_empty();
948 self.inherit.last_coalesce_out = self.inherit.last_bif_out;
949
950 if self.mod_upline {
951 self.out = BACKSPACE.to_string() + &self.out;
952 self.out.trim().to_string()
953 } else {
954 self.out.trim().to_string()
955 }
956 }
957
958 fn set_modifiers(&mut self) -> String {
966 let mut index = 0;
967 while index < self.name.len() {
968 let start = &self.name[index..index + 1];
969 if start == BIF_MOD_FILTER
970 || start == BIF_MOD_NEGATE
971 || start == BIF_MOD_UPLINE
972 || start == BIF_MOD_SCOPE
973 {
974 match start {
975 BIF_MOD_FILTER => self.mod_filter = true,
976 BIF_MOD_NEGATE => self.mod_negate = true,
977 BIF_MOD_UPLINE => self.mod_upline = true,
978 BIF_MOD_SCOPE => self.mod_scope = true,
979 _ => unreachable!(),
980 }
981 index += 1;
982 } else {
983 break;
984 }
985 }
986
987 self.name[index..].to_string()
988 }
989
990 fn get_data(&self, name: &str) -> String {
1002 if name.starts_with("local::") {
1003 let local_name = name.strip_prefix("local::").unwrap_or(name);
1004 get_from_key(
1005 &self.shared.schema["__indir"][&self.inherit.indir]["data"],
1006 local_name,
1007 )
1008 } else {
1009 get_from_key(&self.shared.schema["data"], name)
1010 }
1011 }
1012
1013 fn set_data(&mut self, name: &str, value: &str) {
1021 self.shared.schema["data"][name] = json!(value);
1022 }
1023
1024 fn get_trans(&self, text: &str) -> String {
1043 get_from_key(
1044 &self.shared.schema["__indir"][&self.inherit.indir]["locale"]["trans"]
1045 [&self.shared.lang],
1046 text,
1047 )
1048 }
1049
1050 fn contains_allow(&self, source: &str) -> bool {
1057 for allow in BIF_ALLOWED {
1058 if source.contains(allow) {
1059 return true;
1060 }
1061 }
1062
1063 let source = &remove_comments(source);
1064 !(source.starts_with(BIF_VAR) && source.ends_with(BIF_CLOSE))
1065 }
1066
1067 fn extract_params_code(&mut self, parse: bool) -> bool {
1081 let position = get_code_position(&self.src);
1082 let has_code: bool = position.is_some();
1083
1084 if has_code {
1085 let code_pos = position.unwrap();
1086 self.params = self.src[0..code_pos].trim().to_string();
1087 self.code = self.src[code_pos + BIF_CODE.len()..].trim().to_string();
1088 } else {
1089 self.params = EMPTY_STRING;
1090 self.code = self.src.trim().to_string();
1091 }
1092
1093 if parse && self.params.contains(BIF_OPEN) {
1094 self.shared.flags = EMPTY_STRING;
1095 self.params = new_child_parse!(self, &self.params, false);
1096 self.flags = self.shared.flags.clone();
1097 }
1098
1099 has_code
1100 }
1101
1102 fn extract_args(&mut self) -> Vec<String> {
1103 let mut result: Vec<String> = Vec::new();
1104
1105 let delim;
1106 if let Some(first_char) = self.params.chars().next() {
1107 delim = first_char;
1108 } else {
1109 return vec!["".to_string()];
1110 }
1111
1112 let mut parts = self.params.split(delim);
1113
1114 while let Some(ref mut part) = parts.next() {
1115 let mut arg = part.to_string();
1116
1117 if arg.contains(BIF_OPEN) {
1118 arg = new_child_parse!(self, &arg, false);
1119 }
1120
1121 result.push(arg);
1122 }
1123
1124 result
1125 }
1126
1127 fn parse_bif_unknown(&mut self) -> Result<(), BifError> {
1131 self.alias = "unknown".to_string();
1132
1133 Err(BifError {
1134 msg: "unknown bif".to_string(),
1135 name: self.alias.clone(),
1136 src: self.raw.to_string(),
1137 })
1138 }
1139
1140 fn parse_bif_var(&mut self) -> Result<(), BifError> {
1145 if self.mod_scope {
1146 return Err(BifError {
1147 msg: "modifier not allowed".to_string(),
1148 name: self.alias.clone(),
1149 src: self.raw.to_string(),
1150 });
1151 }
1152
1153 if self.src.is_empty() {
1155 self.alias = "unprintable".to_string();
1158
1159 self.out = UNPRINTABLE.to_string();
1160
1161 return Ok(());
1162 }
1163
1164 self.alias = "var".to_string();
1166 let var_name;
1167
1168 if self.src.contains(BIF_OPEN) {
1170 if !self.contains_allow(&self.src) {
1171 self.out = EMPTY_STRING;
1172
1173 return Err(BifError {
1174 msg: "insecure varname".to_string(),
1175 name: self.alias.clone(),
1176 src: self.src.clone(),
1177 });
1178 }
1179
1180 var_name = new_child_parse!(self, &self.src, self.mod_scope);
1181 } else {
1182 var_name = self.src.clone();
1183 }
1184
1185 self.out = self.get_data(&var_name).to_string();
1186
1187 if (self.mod_filter || self.shared.filter_all) && !self.mod_negate {
1188 if !var_name.starts_with("CONTEXT->") {
1189 self.out = unescape_chars(&self.get_data(&var_name), true).to_string();
1191 self.out = escape_chars(&self.out, true).to_string();
1192 }
1193 } else {
1194 if self.shared.filter_bifs {
1195 self.out = self.out.replace(BIF_OPEN, BIF_SANITIZE_OPEN);
1197 self.out = self.out.replace(BIF_CLOSE, BIF_SANITIZE_CLOSE);
1198 }
1199 }
1200
1201 if self.mod_negate && !self.shared.filter_bifs && var_name.starts_with("CONTEXT->") {
1202 self.out = unescape_chars(&self.out, true).to_string();
1203 }
1204
1205 Ok(())
1206 }
1207
1208 fn parse_bif_allow(&mut self) -> Result<(), BifError> {
1212 if self.mod_filter || self.mod_scope {
1213 return Err(BifError {
1214 msg: "modifier not allowed".to_string(),
1215 name: self.alias.clone(),
1216 src: self.raw.to_string(),
1217 });
1218 }
1219
1220 self.extract_params_code(true);
1221 let mut found = String::new();
1222 let words_string = get_from_key(
1223 &self.shared.schema["__indir"][&self.inherit.indir]["declare"],
1224 &self.params,
1225 );
1226
1227 if words_string.is_empty() {
1228 return Err(BifError {
1229 msg: self.params.clone() + " declared is empty",
1230 name: self.alias.clone(),
1231 src: self.raw.to_string(),
1232 });
1233 }
1234
1235 let mut words_list: Vec<&str> = words_string.split_whitespace().collect();
1236 self.code = new_child_parse!(self, &self.code, self.mod_scope);
1237
1238 for word in &mut words_list {
1239 let lower_haystack;
1240 let mut haystack = &self.code;
1241 let mut pattern = word.to_string().clone();
1242
1243 if self.flags.contains("|partial|") || self.flags.contains("|replace|") {
1244 pattern = format!("{}{}{}", "*", pattern, "*");
1245 }
1246
1247 if self.flags.contains("|casein|") {
1248 pattern = pattern.to_lowercase();
1249 lower_haystack = self.code.clone().to_lowercase();
1250 haystack = &lower_haystack;
1251 }
1252
1253 if wildcard_match(haystack, &pattern) {
1254 found = word.to_string();
1255 break;
1256 }
1257 }
1258
1259 if !found.is_empty() ^ self.mod_negate {
1260 if self.flags.contains("|replace|") {
1261 found = found.replace("~", "");
1262 found = found.replace("*", "");
1263 found = found.replace("?", "");
1264 found = found.replace(".", "");
1265 self.out = found.to_string();
1266 } else {
1267 self.out = self.code.to_string();
1268 }
1269 } else {
1270 self.out = EMPTY_STRING;
1271 }
1272
1273 Ok(())
1274 }
1275
1276 fn parse_bif_array(&mut self) -> Result<(), BifError> {
1280 if self.mod_filter {
1281 return Err(BifError {
1282 msg: "modifier not allowed".to_string(),
1283 name: self.alias.clone(),
1284 src: self.raw.to_string(),
1285 });
1286 }
1287
1288 self.extract_params_code(true);
1289
1290 let mut varname = self.params.as_str();
1291 let mut schema = &self.shared.schema["data"];
1292
1293 if varname.starts_with("local::") {
1294 schema = &self.shared.schema["__indir"][&self.inherit.indir]["data"];
1295 varname = varname.strip_prefix("local::").unwrap_or(varname);
1296 }
1297
1298 if is_array_key(schema, varname) ^ self.mod_negate {
1299 if self.code.contains(BIF_OPEN) {
1300 self.code = new_child_parse!(self, &self.code, self.mod_scope);
1301 }
1302 self.out = self.code.to_string();
1303 }
1304
1305 Ok(())
1306 }
1307
1308 fn parse_bif_bool(&mut self) -> Result<(), BifError> {
1312 if self.mod_filter {
1313 return Err(BifError {
1314 msg: "modifier not allowed".to_string(),
1315 name: self.alias.clone(),
1316 src: self.raw.to_string(),
1317 });
1318 }
1319
1320 self.extract_params_code(true);
1321
1322 let mut varname = self.params.as_str();
1323 let mut schema = &self.shared.schema["data"];
1324
1325 if varname.starts_with("local::") {
1326 schema = &self.shared.schema["__indir"][&self.inherit.indir]["data"];
1327 varname = varname.strip_prefix("local::").unwrap_or(varname);
1328 }
1329
1330 if is_bool_key(schema, varname) ^ self.mod_negate {
1331 if self.code.contains(BIF_OPEN) {
1332 self.code = new_child_parse!(self, &self.code, self.mod_scope);
1333 }
1334 self.out = self.code.to_string();
1335 }
1336
1337 Ok(())
1338 }
1339
1340 fn parse_bif_cache(&mut self) -> Result<(), BifError> {
1347 if self.mod_filter || self.mod_scope {
1348 return Err(BifError {
1349 msg: "modifier not allowed".to_string(),
1350 name: self.alias.clone(),
1351 src: self.raw.to_string(),
1352 });
1353 }
1354
1355 self.extract_params_code(false);
1356
1357 if self.mod_negate {
1358 if self.inherit.in_cache {
1359 self.out = self.raw.to_string();
1360 } else {
1361 self.out = new_child_parse!(self, &self.code, self.mod_scope);
1363 }
1364 return Ok(());
1365 }
1366
1367 let restore_in_cache = self.inherit.in_cache;
1368 let context = &self.shared.schema["data"]["CONTEXT"];
1369 let has_post = !is_empty_key(context, "POST");
1370 let has_get = !is_empty_key(context, "GET");
1371 let has_cookies = !is_empty_key(context, "COOKIES");
1372
1373 if self.shared.cache_disable || (has_post && !self.shared.cache_on_post) || (has_get && !self.shared.cache_on_get) || (has_cookies && !self.shared.cache_on_cookies) {
1374 if self.code.contains(BIF_OPEN) {
1375 self.code = new_child_parse!(self, &self.code, self.mod_scope);
1376 }
1377 self.out = self.code.clone();
1378 return Ok(());
1379 }
1380
1381 self.inherit.in_cache = true;
1382 let args = self.extract_args();
1383 self.inherit.in_cache = restore_in_cache;
1384
1385 let expires = args.get(1)
1387 .cloned()
1388 .ok_or_else(|| {
1389 BifError {
1390 msg: "arguments 'expires' not found".to_string(),
1391 name: self.alias.clone(),
1392 src: self.raw.to_string(),
1393 }
1394 })?;
1395
1396 let mut id = args.get(2).cloned().unwrap_or("".to_string());
1398
1399 let only_custom_id: bool = match args.get(3) {
1401 Some(value) => !matches!(value.as_str(), "false" | "0" | ""),
1402 None => false,
1403 };
1404
1405 if !only_custom_id {
1406 id.push_str(&self.shared.lang);
1407 id.push_str(&expires);
1408 if has_post {
1409 id.push_str(&serde_json::to_string(&self.shared.schema["data"]["CONTEXT"]["POST"]).unwrap());
1410 }
1411 if has_get {
1412 id.push_str(&serde_json::to_string(&self.shared.schema["data"]["CONTEXT"]["GET"]).unwrap());
1413 }
1414 if has_cookies {
1415 id.push_str(&serde_json::to_string(&self.shared.schema["data"]["CONTEXT"]["COOKIES"]).unwrap());
1416 }
1417 id.push_str(&self.get_data("CONTEXT->HOST"));
1418 id.push_str(&self.get_data("CONTEXT->ROUTE"));
1419 id.push_str(&self.code);
1420 }
1421
1422 let mut hasher = Sha256::new();
1423 hasher.update(id.clone());
1424 let cache_id = format!("{:x}", hasher.finalize());
1425 let cache_dir = self.get_cache_dir(&cache_id);
1426 let file = format!("{}/{}-{}", cache_dir, &cache_id, expires);
1427 let file_path = Path::new(&file);
1428
1429 if file_path.exists() && !self.cache_file_expires(file_path, expires.parse::<u64>().unwrap_or(0)) {
1430 if let Ok(content) = fs::read_to_string(file_path) {
1431 self.out = content;
1432 } else {
1433
1434 if self.code.contains(BIF_OPEN) {
1436 self.inherit.in_cache = true;
1437 self.out = new_child_parse!(self, &self.code, self.mod_scope);
1438 self.inherit.in_cache = restore_in_cache;
1439 }
1440 return Err(BifError {
1441 msg: format!("Failed to read cache {}", file_path.display()),
1442 name: self.alias.clone(),
1443 src: self.raw.to_string(),
1444 })
1445 }
1446 } else {
1447 if self.code.contains(BIF_OPEN) {
1448 self.inherit.in_cache = true;
1449 self.code = new_child_parse!(self, &self.code, self.mod_scope);
1450 self.inherit.in_cache = restore_in_cache;
1451 }
1452
1453 self.out = self.code.clone();
1455
1456 self.set_cache_dir(&cache_dir)?;
1458
1459 match File::create(&file_path) {
1461 Ok(mut file) => {
1462 if let Err(e) = file.write_all(&self.code.as_bytes()) {
1463 return Err(BifError {
1464 msg: format!("Failed to write to cache {}: {}", file_path.display(), e.to_string()),
1465 name: self.alias.clone(),
1466 src: self.raw.to_string(),
1467 })
1468 }
1469 },
1470 Err(e) => {
1471 return Err(BifError {
1472 msg: format!("Failed to create file {}: {}", file_path.display(), e.to_string()),
1473 name: self.alias.clone(),
1474 src: self.raw.to_string(),
1475 })
1476 }
1477 }
1478 }
1479
1480 Ok(())
1481 }
1482
1483 fn cache_file_expires(&self, file_path: &Path, expires: u64) -> bool {
1484 let now: u64 = SystemTime::now()
1485 .duration_since(UNIX_EPOCH)
1486 .unwrap()
1487 .as_secs();
1488
1489 let metadata = match fs::metadata(file_path) {
1490 Ok(meta) => meta,
1491 Err(_) => return true,
1492 };
1493
1494 let modified_time = match metadata.modified() {
1495 Ok(time) => time,
1496 Err(_) => return true,
1497 };
1498
1499 let duration_since_epoch = match modified_time.duration_since(UNIX_EPOCH) {
1500 Ok(duration) => duration,
1501 Err(_) => return true,
1502 };
1503
1504 let file_modified_time = duration_since_epoch.as_secs();
1505 let expiration_time = file_modified_time + expires;
1506
1507 if now > expiration_time {
1508 return true
1509 }
1510
1511 false
1512 }
1513
1514 fn set_cache_dir(&self, cache_dir: &str) -> Result<(), BifError> {
1515 let cache_dir_levels = Path::new(&cache_dir);
1516
1517 match fs::create_dir_all(cache_dir_levels) {
1518 Ok(_) => Ok(()),
1519 Err(e) => {
1520 return Err(BifError {
1521 msg: format!("Failed to create cache directory {}: {}", cache_dir, e.to_string()),
1522 name: self.alias.clone(),
1523 src: self.raw.to_string(),
1524 })
1525 }
1526 }
1527 }
1528
1529 fn get_cache_dir(&self, file: &str) -> String {
1530 let mut cache_dir = self.shared.cache_dir.clone();
1531
1532 if !self.shared.cache_prefix.is_empty() {
1533 cache_dir.push_str("/");
1534 cache_dir.push_str(&self.shared.cache_prefix);
1535 }
1536
1537 cache_dir.push_str("/");
1538 cache_dir.push_str(&file[0..3]);
1539
1540 cache_dir.to_string()
1541 }
1542
1543 fn parse_bif_coalesce(&mut self) -> Result<(), BifError> {
1551 if self.mod_filter || self.mod_negate {
1552 return Err(BifError {
1553 msg: "modifier not allowed".to_string(),
1554 name: self.alias.clone(),
1555 src: self.raw.to_string(),
1556 });
1557 }
1558
1559 self.inherit.last_coalesce_out = false;
1561 self.out = new_child_parse!(self, &self.src, self.mod_scope);
1562
1563 Ok(())
1564 }
1565
1566 fn parse_bif_code(&mut self) -> Result<(), BifError> {
1571 if self.mod_filter || self.mod_negate {
1572 return Err(BifError {
1573 msg: "modifier not allowed".to_string(),
1574 name: self.alias.clone(),
1575 src: self.raw.to_string(),
1576 });
1577 }
1578
1579 self.extract_params_code(true);
1580
1581 if self.flags.contains("|safe|") {
1582 self.code = escape_chars(&unescape_chars(&self.code, false), false).to_string();
1583 self.code = self.code.replace(BIF_OPEN, BIF_SANITIZE_OPEN);
1584 self.code = self.code.replace(BIF_CLOSE, BIF_SANITIZE_CLOSE);
1585 } else {
1586 if self.flags.contains("|encode_tags|") {
1587 self.code = escape_chars(&unescape_chars(&self.code, false), false).to_string();
1588 }
1589
1590 if self.flags.contains("|encode_bifs|") {
1591 self.code = self.code.replace(BIF_OPEN, BIF_SANITIZE_OPEN);
1592 self.code = self.code.replace(BIF_CLOSE, BIF_SANITIZE_CLOSE);
1593 }
1594
1595 if !self.flags.contains("|noparse|") && self.code.contains(BIF_OPEN) {
1596 self.code = new_child_parse!(self, &self.code, self.mod_scope);
1597 }
1598 }
1599
1600 if self.flags.contains("|encode_tags_after|") {
1601 self.code = escape_chars(&unescape_chars(&self.code, false), false).to_string();
1602 }
1603
1604 self.out = self.code.to_string();
1605
1606 Ok(())
1607 }
1608
1609 fn parse_bif_contains(&mut self) -> Result<(), BifError> {
1613 if self.mod_filter {
1614 return Err(BifError {
1615 msg: "modifier not allowed".to_string(),
1616 name: self.alias.clone(),
1617 src: self.raw.to_string(),
1618 });
1619 }
1620
1621 self.extract_params_code(false);
1622 let args = self.extract_args();
1623
1624 let haystack = args.get(1)
1625 .cloned()
1626 .ok_or_else(|| {
1627 BifError {
1628 msg: "arguments not found".to_string(),
1629 name: self.alias.clone(),
1630 src: self.raw.to_string(),
1631 }
1632 })?;
1633
1634 let needle = args.get(2)
1635 .cloned()
1636 .ok_or_else(|| {
1637 BifError {
1638 msg: "arguments not found".to_string(),
1639 name: self.alias.clone(),
1640 src: self.raw.to_string(),
1641 }
1642 })?;
1643
1644 if haystack.contains(&needle) ^ self.mod_negate {
1645 if self.code.contains(BIF_OPEN) {
1646 self.code = new_child_parse!(self, &self.code, self.mod_scope);
1647 }
1648 self.out = self.code.to_string();
1649 } else {
1650 self.out = EMPTY_STRING;
1651 }
1652
1653 Ok(())
1654 }
1655
1656 fn parse_bif_count(&mut self) -> Result<(), BifError> {
1661 if self.mod_filter || self.mod_negate || self.mod_scope {
1662 return Err(BifError {
1663 msg: "modifier not allowed".to_string(),
1664 name: self.alias.clone(),
1665 src: self.raw.to_string(),
1666 });
1667 }
1668
1669 let is_set = self.extract_params_code(true);
1670
1671 if self.code.contains(BIF_OPEN) {
1672 self.code = new_child_parse!(self, &self.code, self.mod_scope);
1673 }
1674
1675 if is_set {
1676 let count_name = self.params.clone();
1677 let count_value = match self.code.parse::<i32>() {
1678 Ok(num) => num,
1679 Err(_) => {
1680 return Err(BifError {
1681 msg: "argument is not a number".to_string(),
1682 name: self.alias.clone(),
1683 src: self.raw.to_string(),
1684 });
1685 }
1686 };
1687
1688 self.set_data(&count_name, &count_value.to_string());
1689 self.out = EMPTY_STRING;
1690 } else {
1691 let count_name = self.code.clone();
1692 let count_value = match self.get_data(&count_name).parse::<i32>() {
1693 Ok(num) => num,
1694 Err(_) => {
1695 return Err(BifError {
1696 msg: "argument is not a number".to_string(),
1697 name: self.alias.clone(),
1698 src: self.raw.to_string(),
1699 });
1700 }
1701 };
1702 let new_value = count_value + 1;
1703
1704 self.set_data(&count_name, &new_value.to_string());
1705 self.out = count_value.to_string();
1706 }
1707
1708 Ok(())
1709 }
1710
1711 fn parse_bif_data(&mut self) -> Result<(), BifError> {
1715 if self.mod_filter || self.mod_scope {
1716 return Err(BifError {
1717 msg: "modifier not allowed".to_string(),
1718 name: self.alias.clone(),
1719 src: self.raw.to_string(),
1720 });
1721 }
1722
1723 self.extract_params_code(true);
1724
1725 if self.flags.contains("|inline|") {
1726 let data: Value = match serde_json::from_str(&self.code) {
1727 Ok(value) => value,
1728 Err(_) => {
1729 return Err(BifError {
1730 msg: "not a valid JSON file".to_string(),
1731 name: self.alias.clone(),
1732 src: self.raw.to_string(),
1733 })
1734 }
1735 };
1736
1737 let indir = &self.inherit.create_block_schema(self.shared);
1738
1739 merge_schema(
1741 &mut self.shared.schema["__indir"][indir]["data"],
1742 &data["data"],
1743 );
1744
1745 self.out = UNPRINTABLE.to_string();
1746
1747 return Ok(());
1748 }
1749
1750 self.file_path = self.code.clone();
1751
1752 if self.file_path.contains(BIF_OPEN) {
1754 if !self.contains_allow(&self.file_path) {
1755 return Err(BifError {
1756 msg: "insecure file name".to_string(),
1757 name: self.alias.clone(),
1758 src: self.raw.to_string(),
1759 });
1760 }
1761 self.file_path = new_child_parse!(self, &self.code, false);
1762 }
1763
1764 if self.file_path.starts_with("#") {
1765 self.file_path.remove(0);
1766 self.file_path = format!("{}{}", self.inherit.current_dir, self.file_path);
1767 }
1768
1769 let path = Path::new(&self.file_path);
1770 if !Path::new(path).exists() {
1771 if self.flags.contains("|require|") {
1772 return Err(BifError {
1773 msg: "file not found".to_string(),
1774 name: self.alias.clone(),
1775 src: self.raw.to_string(),
1776 });
1777 } else {
1778 self.out = EMPTY_STRING;
1779
1780 return Ok(());
1781 }
1782 }
1783
1784 let canonical_path = fs::canonicalize(path)
1785 .unwrap()
1786 .to_string_lossy()
1787 .into_owned();
1788
1789 if self.mod_negate && self.inherit.data_files.contains(&canonical_path) {
1790 self.out = UNPRINTABLE.to_string();
1791
1792 return Ok(());
1793 }
1794
1795 self.inherit.data_files.push(canonical_path);
1796 let file_raw = fs::read_to_string(&self.file_path).unwrap_or("".to_string());
1797
1798 let data: Value = match serde_json::from_str(&file_raw) {
1799 Ok(value) => value,
1800 Err(_) => {
1801 return Err(BifError {
1802 msg: "not a valid JSON file".to_string(),
1803 name: self.alias.clone(),
1804 src: self.raw.to_string(),
1805 })
1806 }
1807 };
1808
1809 let indir = &self.inherit.create_block_schema(self.shared);
1810
1811 merge_schema(
1813 &mut self.shared.schema["__indir"][indir]["data"],
1814 &data["data"],
1815 );
1816
1817 self.out = UNPRINTABLE.to_string();
1818
1819 Ok(())
1820 }
1821
1822 fn parse_bif_date(&mut self) -> Result<(), BifError> {
1827 if self.mod_filter || self.mod_negate || self.mod_scope {
1828 return Err(BifError {
1829 msg: "modifier not allowed".to_string(),
1830 name: self.alias.clone(),
1831 src: self.raw.to_string(),
1832 });
1833 }
1834
1835 self.extract_params_code(true);
1836
1837 let now = Utc::now();
1838
1839 if self.src.contains(BIF_OPEN) {
1840 self.code = new_child_parse!(self, &self.code, self.mod_scope);
1841 } else {
1842 self.code = self.src.trim().to_string();
1843 }
1844
1845 if self.code.is_empty() {
1846 self.out = now.timestamp().to_string();
1847 } else {
1848 self.out = now.format(&self.src).to_string();
1849 }
1850
1851 Ok(())
1852 }
1853
1854 fn parse_bif_declare(&mut self) -> Result<(), BifError> {
1858 if self.mod_filter || self.mod_negate || self.mod_scope {
1859 return Err(BifError {
1860 msg: "modifier not allowed".to_string(),
1861 name: self.alias.clone(),
1862 src: self.raw.to_string(),
1863 });
1864 }
1865
1866 self.extract_params_code(true);
1867
1868 if self.inherit.current_file.contains(SNIPPETS_FILES) {
1869 self.inherit.create_block_schema(self.shared);
1870 if self.code.contains(BIF_OPEN) {
1871 self.code = new_child_parse!(self, &self.code, false);
1872 self.code = self.code.replace(UNPRINTABLE, "");
1873 }
1874 self.shared.schema["__indir"][&self.inherit.indir]["declare"][&self.params] =
1875 json!(&self.code);
1876
1877 self.out = EMPTY_STRING;
1878 } else {
1879 return Err(BifError {
1880 msg: "declare cannot be set here".to_string(),
1881 name: self.alias.clone(),
1882 src: self.raw.to_string(),
1883 });
1884 }
1885
1886 Ok(())
1887 }
1888
1889 fn parse_bif_defined(&mut self) -> Result<(), BifError> {
1893 if self.mod_filter {
1894 return Err(BifError {
1895 msg: "modifier not allowed".to_string(),
1896 name: self.alias.clone(),
1897 src: self.raw.to_string(),
1898 });
1899 }
1900
1901 self.extract_params_code(true);
1902
1903 let mut varname = self.params.as_str();
1904 let mut schema = &self.shared.schema["data"];
1905
1906 if varname.starts_with("local::") {
1907 schema = &self.shared.schema["__indir"][&self.inherit.indir]["data"];
1908 varname = varname.strip_prefix("local::").unwrap_or(varname);
1909 }
1910
1911 if is_defined_key(schema, varname) ^ self.mod_negate {
1912 if self.code.contains(BIF_OPEN) {
1913 self.code = new_child_parse!(self, &self.code, self.mod_scope);
1914 }
1915 self.out = self.code.to_string();
1916 }
1917
1918 Ok(())
1919 }
1920
1921 fn parse_bif_each(&mut self) -> Result<(), BifError> {
1927 if self.mod_filter || self.mod_negate || self.mod_scope {
1928 return Err(BifError {
1929 msg: "modifier not allowed".to_string(),
1930 name: self.alias.clone(),
1931 src: self.raw.to_string(),
1932 });
1933 }
1934
1935 self.extract_params_code(true);
1936 let mut parts = self.params.split_whitespace();
1937
1938 let array_name = match parts.next() {
1939 Some(value) => value.to_string(),
1940 None => {
1941 return Err(BifError {
1942 msg: "arguments not found".to_string(),
1943 name: self.alias.clone(),
1944 src: self.raw.to_string(),
1945 })
1946 }
1947 };
1948
1949 let key_name = match parts.next() {
1950 Some(value) => value.to_string(),
1951 None => {
1952 return Err(BifError {
1953 msg: "arguments 'key' not found".to_string(),
1954 name: self.alias.clone(),
1955 src: self.raw.to_string(),
1956 })
1957 }
1958 };
1959
1960 let val_name = match parts.next() {
1961 Some(value) => value.to_string(),
1962 None => {
1963 return Err(BifError {
1964 msg: "arguments 'value' not found".to_string(),
1965 name: self.alias.clone(),
1966 src: self.raw.to_string(),
1967 })
1968 }
1969 };
1970
1971 let tmp: String = format!("{}{}", "/", array_name);
1972 let mut array = tmp.replace(BIF_ARRAY, "/");
1973 let restore_key = self.get_data(&key_name);
1974 let restore_val = self.get_data(&val_name);
1975
1976 let data_storage;
1977 if array.starts_with("/local::") {
1978 array = array.replace("/local::", "/");
1979 data_storage = &self.shared.schema["__indir"][&self.inherit.indir]["data"];
1980 } else {
1981 data_storage = &self.shared.schema["data"];
1982 }
1983
1984 if let Some(data_value) = data_storage.pointer(&array) {
1985 match data_value.to_owned() {
1986 Value::Object(obj) => {
1987 for (key, val) in obj.iter() {
1988 self.parse_bif_each_iter(&key_name, &val_name, key, val);
1989 }
1990 }
1991 Value::Array(arr) => {
1992 for (key, val) in arr.iter().enumerate() {
1993 self.parse_bif_each_iter(&key_name, &val_name, &key.to_string(), val);
1994 }
1995 }
1996 _ => {}
1997 }
1998 }
1999
2000 self.set_data(&key_name, &restore_key);
2001 self.set_data(&val_name, &restore_val);
2002
2003 Ok(())
2004 }
2005
2006 fn parse_bif_each_iter(&mut self, key_name: &str, val_name: &str, key: &String, val: &Value) {
2007 self.shared.schema["data"][key_name] = json!(key);
2008 self.shared.schema["data"][val_name] = json!(val);
2009 self.out += &new_child_parse!(self, &self.code, false);
2010 }
2011
2012 fn parse_bif_else(&mut self) -> Result<(), BifError> {
2018 if self.mod_filter {
2019 return Err(BifError {
2020 msg: "modifier not allowed".to_string(),
2021 name: self.alias.clone(),
2022 src: self.raw.to_string(),
2023 });
2024 }
2025
2026 self.extract_params_code(true);
2027
2028 if self.inherit.last_bif_out ^ self.mod_negate {
2029 self.out = EMPTY_STRING;
2030
2031 return Ok(());
2032 }
2033
2034 if self.code.contains(BIF_OPEN) {
2035 self.code = new_child_parse!(self, &self.code, self.mod_scope);
2036 }
2037
2038 self.out = self.code.to_string();
2039
2040 Ok(())
2041 }
2042
2043 fn parse_bif_eval(&mut self) -> Result<(), BifError> {
2047 if self.mod_filter {
2048 return Err(BifError {
2049 msg: "modifier not allowed".to_string(),
2050 name: self.alias.clone(),
2051 src: self.raw.to_string(),
2052 });
2053 }
2054
2055 self.extract_params_code(false);
2056
2057 if self.params.contains(BIF_OPEN) {
2058 self.params = new_child_parse!(self, &self.params, self.mod_scope);
2059 }
2060
2061 if (self.params != EMPTY_STRING) ^ self.mod_negate {
2062 if self.code.contains(BIF_OPEN) {
2063 let restore_eval = self.get_data("__eval__");
2064 self.set_data("__eval__", &self.params.clone());
2065 self.code = new_child_parse!(self, &self.code, self.mod_scope);
2066 self.set_data("__eval__", &restore_eval);
2067 }
2068 self.out = self.code.clone();
2069 } else {
2070 self.out = EMPTY_STRING;
2071 }
2072
2073 Ok(())
2074 }
2075
2076 fn parse_bif_exit(&mut self) -> Result<(), BifError> {
2083 if self.mod_filter || self.mod_scope {
2084 return Err(BifError {
2085 msg: "modifier not allowed".to_string(),
2086 name: self.alias.clone(),
2087 src: self.raw.to_string(),
2088 });
2089 }
2090
2091 if self.inherit.in_cache {
2092 self.out = format!("{}{}{}", "{:!cache;", self.raw.to_string(), ":}");
2093 } else {
2094 self.out = EMPTY_STRING;
2095 }
2096
2097 let has_status_params = self.extract_params_code(true);
2098
2099 if self.code.contains(BIF_OPEN) {
2100 self.code = new_child_parse!(self, &self.src, false);
2101 }
2102
2103 let mut status_code = "200";
2104 let mut status_param = "";
2105
2106 if has_status_params {
2107 if !self.params.is_empty() {
2108 status_code = self.params.as_str();
2109 }
2110 status_param = &self.code;
2111 } else if !self.code.is_empty() {
2112 status_code = self.code.as_str();
2113 }
2114
2115 self.shared.status_code = status_code.to_string();
2116 self.shared.status_param = status_param.to_string();
2117
2118 if let Some(text) = STATUS_CODES.get(status_code) {
2119 self.shared.status_text = text.to_string();
2120 } else {
2121 self.shared.status_text = EMPTY_STRING;
2122 }
2123
2124 self.shared.exit = true ^ self.mod_negate;
2125
2126 Ok(())
2127 }
2128
2129
2130 fn parse_bif_fetch(&mut self) -> Result<(), BifError> {
2134 if self.mod_filter || self.mod_negate || self.mod_scope {
2135 return Err(BifError {
2136 msg: "modifier not allowed".to_string(),
2137 name: self.alias.clone(),
2138 src: self.raw.to_string(),
2139 });
2140 }
2141
2142 self.extract_params_code(true);
2143 let args = self.extract_args();
2144
2145 let url = args.get(1)
2146 .cloned()
2147 .ok_or_else(|| {
2148 BifError {
2149 msg: "argument 'url' not found".to_string(),
2150 name: self.alias.clone(),
2151 src: self.raw.to_string(),
2152 }
2153 })?;
2154
2155 let event = args.get(2).cloned().unwrap_or("".to_string());
2156 let wrap = args.get(3).cloned().unwrap_or("".to_string());
2157 let class = args.get(4).cloned().unwrap_or("".to_string());
2158 let id = args.get(5).cloned().unwrap_or("".to_string());
2159 let name = args.get(6).cloned().unwrap_or("".to_string());
2160 let div;
2161
2162 match event.as_str() {
2163 "form" => div = DIV_FETCH_FORM,
2164 "none" => div = DIV_FETCH_NONE,
2165 "visible" => div = DIV_FETCH_VISIBLE,
2166 "click" => div = DIV_FETCH_CLICK,
2167 "auto" => div = DIV_FETCH_AUTO,
2168 _ => div = DIV_FETCH_AUTO,
2169 }
2170
2171 if self.code.contains(BIF_OPEN) {
2172 self.code = new_child_parse!(self, &self.code, self.mod_scope);
2173 }
2174
2175 self.out = div
2176 .replace("{id}", &id)
2177 .replace("{name}", &name)
2178 .replace("{wrap}", &wrap)
2179 .replace("{class}", &class)
2180 .replace("{body}", &self.code)
2181 .replace("{endpoint}", &url);
2182
2183 if !self.shared.disable_js && !self.shared.already_js {
2184 self.out = format!("{}{}{}{}", self.out, "{:!cache;{:moveto;</body>>", NEUTRAL_JS.to_string(), ":}:}");
2185 self.shared.already_js = true;
2186 }
2187
2188 Ok(())
2189 }
2190
2191 fn parse_bif_filled(&mut self) -> Result<(), BifError> {
2198 if self.mod_filter {
2199 return Err(BifError {
2200 msg: "modifier not allowed".to_string(),
2201 name: self.alias.clone(),
2202 src: self.raw.to_string(),
2203 });
2204 }
2205
2206 self.extract_params_code(true);
2207
2208 let mut varname = self.params.as_str();
2209 let mut schema = &self.shared.schema["data"];
2210
2211 if varname.starts_with("local::") {
2212 schema = &self.shared.schema["__indir"][&self.inherit.indir]["data"];
2213 varname = varname.strip_prefix("local::").unwrap_or(varname);
2214 }
2215
2216 if !is_empty_key(schema, varname) ^ self.mod_negate {
2217 if self.code.contains(BIF_OPEN) {
2218 self.code = new_child_parse!(self, &self.code, self.mod_scope);
2219 }
2220
2221 self.out = self.code.to_string();
2222 }
2223
2224 Ok(())
2225 }
2226
2227 fn parse_bif_flg(&mut self) -> Result<(), BifError> {
2232 if self.mod_filter || self.mod_negate || self.mod_upline || self.mod_scope {
2233 return Err(BifError {
2234 msg: "modifier not allowed".to_string(),
2235 name: self.alias.clone(),
2236 src: self.raw.to_string(),
2237 });
2238 }
2239
2240 self.extract_params_code(true);
2241
2242 if self.code.contains(BIF_OPEN) {
2243 self.code = new_child_parse!(self, &self.code, false);
2244 }
2245
2246 let flags = format!(" {} ", self.code);
2247 self.shared.flags = flags.replace(" ", "|");
2248 self.out = EMPTY_STRING;
2249
2250 Ok(())
2251 }
2252
2253 fn parse_bif_for(&mut self) -> Result<(), BifError> {
2259 if self.mod_filter || self.mod_negate || self.mod_scope {
2260 return Err(BifError {
2261 msg: "modifier not allowed".to_string(),
2262 name: self.alias.clone(),
2263 src: self.raw.to_string(),
2264 });
2265 }
2266
2267 self.extract_params_code(true);
2268 self.params = self.params.replace("..", " ");
2269 let mut parts = self.params.split_whitespace();
2270
2271 let var_name = match parts.next() {
2272 Some(value) => value.to_string(),
2273 None => {
2274 return Err(BifError {
2275 msg: "arguments not found".to_string(),
2276 name: self.alias.clone(),
2277 src: self.raw.to_string(),
2278 })
2279 }
2280 };
2281
2282 let from = match parts.next() {
2283 Some(value) => match value.parse::<i32>() {
2284 Ok(num) => num,
2285 Err(_) => {
2286 return Err(BifError {
2287 msg: "argument is not a number".to_string(),
2288 name: self.alias.clone(),
2289 src: self.raw.to_string(),
2290 })
2291 }
2292 },
2293 None => {
2294 return Err(BifError {
2295 msg: "arguments 'from' and 'to' not found".to_string(),
2296 name: self.alias.clone(),
2297 src: self.raw.to_string(),
2298 })
2299 }
2300 };
2301
2302 let to = match parts.next() {
2303 Some(value) => match value.parse::<i32>() {
2304 Ok(num) => num,
2305 Err(_) => {
2306 return Err(BifError {
2307 msg: "argument is not a number".to_string(),
2308 name: self.alias.clone(),
2309 src: self.raw.to_string(),
2310 })
2311 }
2312 },
2313 None => {
2314 return Err(BifError {
2315 msg: "arguments 'to' not found".to_string(),
2316 name: self.alias.clone(),
2317 src: self.raw.to_string(),
2318 })
2319 }
2320 };
2321
2322 let range = if from > to {
2323 (to..=from).rev().collect::<Vec<i32>>()
2324 } else {
2325 (from..=to).collect::<Vec<i32>>()
2326 };
2327
2328 let restore_var = self.get_data(&var_name);
2329 for i in range {
2330 self.set_data(&var_name, &i.to_string());
2331 self.out += &new_child_parse!(self, &self.code, self.mod_scope);
2332 }
2333 self.set_data(&var_name, &restore_var);
2334
2335 Ok(())
2336 }
2337
2338 fn parse_bif_hash(&mut self) -> Result<(), BifError> {
2343 if self.mod_filter || self.mod_negate || self.mod_scope {
2344 return Err(BifError {
2345 msg: "modifier not allowed".to_string(),
2346 name: self.alias.clone(),
2347 src: self.raw.to_string(),
2348 });
2349 }
2350
2351 self.code = self.src.trim().to_string();
2352
2353 if self.src.contains(BIF_OPEN) {
2354 self.code = new_child_parse!(self, &self.code, self.mod_scope);
2355 } else {
2356 self.code = self.code.trim().to_string();
2357 }
2358
2359 if self.code.is_empty() {
2360 let mut hasher = Md5::new();
2361 let mut rng = rand::rng();
2362 let rand = rng.random_range(100000000..=999999999).to_string();
2363 hasher.update(&rand);
2364 self.out = format!("{:x}", hasher.finalize())
2365 } else {
2366 let mut hasher = Md5::new();
2367 hasher.update(&self.code);
2368 self.out = format!("{:x}", hasher.finalize());
2369 }
2370
2371 Ok(())
2372 }
2373
2374 fn parse_bif_include(&mut self) -> Result<(), BifError> {
2379 if self.mod_filter || self.mod_scope {
2380 return Err(BifError {
2381 msg: "modifier not allowed".to_string(),
2382 name: self.alias.clone(),
2383 src: self.raw.to_string(),
2384 });
2385 }
2386
2387 self.extract_params_code(true);
2388 self.file_path = self.code.clone();
2389
2390 if self.file_path.contains(BIF_OPEN) {
2392 if !self.contains_allow(&self.file_path) {
2393 return Err(BifError {
2394 msg: "insecure file name".to_string(),
2395 name: self.alias.clone(),
2396 src: self.raw.to_string(),
2397 });
2398 }
2399 self.file_path = new_child_parse!(self, &self.code, false);
2400 }
2401
2402 if self.file_path.starts_with("#") {
2403 self.file_path.remove(0);
2404 self.file_path = format!("{}{}", self.inherit.current_dir, self.file_path);
2405 }
2406
2407 let path = Path::new(&self.file_path);
2408 if !path.exists() {
2409 if self.flags.contains("|require|") {
2410 return Err(BifError {
2411 msg: "file not found".to_string(),
2412 name: self.alias.clone(),
2413 src: self.raw.to_string(),
2414 });
2415 } else {
2416 return Ok(());
2417 }
2418 }
2419
2420 if let Some(parent) = path.parent() {
2421 self.dir = parent.display().to_string();
2422 }
2423
2424 let canonical_path = fs::canonicalize(path)
2425 .unwrap()
2426 .to_string_lossy()
2427 .into_owned();
2428
2429 if self.mod_negate && self.inherit.include_files.contains(&canonical_path) {
2430 self.out = EMPTY_STRING;
2431
2432 return Ok(());
2433 }
2434
2435 if self.flags.contains("|safe|") {
2436 self.code = fs::read_to_string(&self.file_path).unwrap_or("".to_string());
2437 self.code = escape_chars(&unescape_chars(&self.code, false), false).to_string();
2438 self.code = self.code.replace(BIF_OPEN, BIF_SANITIZE_OPEN);
2439 self.code = self.code.replace(BIF_CLOSE, BIF_SANITIZE_CLOSE);
2440 self.out = self.code.clone();
2441
2442 return Ok(());
2443 }
2444
2445 if self.flags.contains("|noparse|") {
2446 self.code = fs::read_to_string(&self.file_path).unwrap_or("".to_string());
2447 self.out = self.code.clone();
2448
2449 return Ok(());
2450 }
2451
2452 self.inherit.include_files.push(canonical_path);
2453
2454 let mut file_raw = fs::read_to_string(&self.file_path).unwrap_or("".to_string());
2455 if self.shared.comments.contains("remove") {
2456 file_raw = remove_comments(&file_raw);
2457 }
2458
2459 self.out = new_child_parse!(self, &file_raw, true);
2460
2461 Ok(())
2462 }
2463
2464 fn parse_bif_join(&mut self) -> Result<(), BifError> {
2471 if self.mod_filter || self.mod_negate || self.mod_scope {
2472 return Err(BifError {
2473 msg: "modifier not allowed".to_string(),
2474 name: self.alias.clone(),
2475 src: self.raw.to_string(),
2476 });
2477 }
2478
2479 self.params = self.src.clone();
2480 let args = self.extract_args();
2481
2482 let mut array_name = args.get(1)
2483 .cloned()
2484 .ok_or_else(|| {
2485 BifError {
2486 msg: "arguments 'array' not found".to_string(),
2487 name: self.alias.clone(),
2488 src: self.raw.to_string(),
2489 }
2490 })?;
2491
2492 let separator = args.get(2)
2493 .cloned()
2494 .ok_or_else(|| {
2495 BifError {
2496 msg: "arguments 'separator' not found".to_string(),
2497 name: self.alias.clone(),
2498 src: self.raw.to_string(),
2499 }
2500 })?;
2501
2502 let use_keys = args.get(3).cloned().unwrap_or("".to_string());
2504
2505 let keys: bool = match use_keys.as_str() {
2506 "" => false,
2507 "false" => false,
2508 "0" => false,
2509 _ => true,
2510 };
2511
2512 let data_storage;
2513 array_name = format!("{}{}", "/", array_name);
2514 array_name = array_name.replace(BIF_ARRAY, "/");
2515 if array_name.starts_with("/local::") {
2516 array_name = array_name.replace("/local::", "/");
2517 data_storage = &self.shared.schema["__indir"][&self.inherit.indir]["data"];
2518 } else {
2519 data_storage = &self.shared.schema["data"];
2520 }
2521
2522 let mut joined = String::new();
2523 if let Some(data_value) = data_storage.pointer(&array_name) {
2524 match data_value.to_owned() {
2525 Value::Object(obj) => {
2526 if keys {
2527 joined = obj
2528 .keys()
2529 .map(|k| k.to_string()) .collect::<Vec<String>>()
2531 .join(&separator);
2532 } else {
2533 joined = obj
2534 .values()
2535 .map(|v| match v {
2536 Value::Object(_) => "".to_string(),
2537 Value::Array(_) => "".to_string(),
2538 Value::String(s) => s.to_string(),
2539 Value::Number(n) => n.to_string(),
2540 Value::Bool(b) => b.to_string(),
2541 _ => v.to_string(),
2542 })
2543 .collect::<Vec<String>>()
2544 .join(&separator);
2545 }
2546 }
2547 Value::Array(arr) => {
2548 if keys {
2549 joined = (0..arr.len())
2550 .map(|i| i.to_string())
2551 .collect::<Vec<String>>()
2552 .join(&separator);
2553 } else {
2554 joined = arr
2555 .iter()
2556 .map(|v| v.as_str().unwrap_or(""))
2557 .collect::<Vec<&str>>()
2558 .join(&separator);
2559 }
2560 }
2561 _ => {}
2562 }
2563 }
2564
2565 self.out = joined.to_string();
2566 Ok(())
2567 }
2568
2569 fn parse_bif_lang(&mut self) -> Result<(), BifError> {
2573 if self.mod_filter || self.mod_negate || self.mod_scope {
2574 return Err(BifError {
2575 msg: "modifier not allowed".to_string(),
2576 name: self.alias.clone(),
2577 src: self.raw.to_string(),
2578 });
2579 }
2580
2581 self.out = self.shared.lang.to_string();
2582
2583 Ok(())
2584 }
2585
2586 fn parse_bif_locale(&mut self) -> Result<(), BifError> {
2590 if self.mod_filter || self.mod_scope {
2591 return Err(BifError {
2592 msg: "modifier not allowed".to_string(),
2593 name: self.alias.clone(),
2594 src: self.raw.to_string(),
2595 });
2596 }
2597
2598 self.extract_params_code(true);
2599
2600 if self.flags.contains("|inline|") {
2601 if self.code.contains(BIF_OPEN) {
2603 self.code = new_child_parse!(self, &self.code, false);
2604 }
2605
2606 let locale: Value = match serde_json::from_str(&self.code) {
2607 Ok(value) => value,
2608 Err(_) => {
2609 return Err(BifError {
2610 msg: "not a valid JSON string".to_string(),
2611 name: self.alias.clone(),
2612 src: self.raw.to_string(),
2613 })
2614 }
2615 };
2616
2617 let indir = &self.inherit.create_block_schema(self.shared);
2618
2619 merge_schema(&mut self.shared.schema["__indir"][indir]["locale"], &locale);
2621
2622 self.out = EMPTY_STRING;
2623
2624 return Ok(());
2625 }
2626
2627 self.file_path = self.code.clone();
2628
2629 if self.file_path.contains(BIF_OPEN) {
2631 if !self.contains_allow(&self.file_path) {
2632 return Err(BifError {
2633 msg: "insecure file name".to_string(),
2634 name: self.alias.clone(),
2635 src: self.raw.to_string(),
2636 });
2637 }
2638 self.file_path = new_child_parse!(self, &self.code, false);
2639 }
2640
2641 if self.file_path.starts_with("#") {
2642 self.file_path.remove(0);
2643 self.file_path = format!("{}{}", self.inherit.current_dir, self.file_path);
2644 }
2645
2646 let path = Path::new(&self.file_path);
2647 if !Path::new(path).exists() {
2648 if self.flags.contains("|require|") {
2649 return Err(BifError {
2650 msg: "file not found".to_string(),
2651 name: self.alias.clone(),
2652 src: self.raw.to_string(),
2653 });
2654 } else {
2655 return Ok(());
2656 }
2657 }
2658
2659 let canonical_path = fs::canonicalize(path)
2660 .unwrap()
2661 .to_string_lossy()
2662 .into_owned();
2663 if self.mod_negate && self.inherit.locale_files.contains(&canonical_path) {
2664 self.out = UNPRINTABLE.to_string();
2665
2666 return Ok(());
2667 }
2668
2669 self.inherit.locale_files.push(canonical_path);
2670 let mut file_raw = fs::read_to_string(&self.file_path).unwrap_or("".to_string());
2671
2672 if !self.flags.contains("|noparse|") {
2673 if file_raw.contains(BIF_OPEN) {
2675 file_raw = new_child_parse!(self, &file_raw, false);
2676 }
2677 }
2678
2679 let locale: Value = match serde_json::from_str(&file_raw) {
2680 Ok(value) => value,
2681 Err(_) => {
2682 return Err(BifError {
2683 msg: "not a valid JSON file".to_string(),
2684 name: self.alias.clone(),
2685 src: self.raw.to_string(),
2686 })
2687 }
2688 };
2689
2690 let indir = &self.inherit.create_block_schema(self.shared);
2691
2692 merge_schema(&mut self.shared.schema["__indir"][indir]["locale"], &locale);
2694
2695 self.out = UNPRINTABLE.to_string();
2696
2697 Ok(())
2698 }
2699
2700 fn parse_bif_moveto(&mut self) -> Result<(), BifError> {
2705 if self.mod_filter || self.mod_negate || self.mod_scope {
2706 return Err(BifError {
2707 msg: "modifier not allowed".to_string(),
2708 name: self.alias.clone(),
2709 src: self.raw.to_string(),
2710 });
2711 }
2712
2713 if self.inherit.in_cache {
2714 self.out = format!("{}{}{}", "{:!cache;", self.raw.to_string(), ":}");
2715 } else {
2716 self.out = EMPTY_STRING;
2717 }
2718
2719 self.extract_params_code(true);
2720
2721 if self.code.contains(BIF_OPEN) {
2722 self.code = new_child_parse!(self, &self.code, self.mod_scope);
2723 }
2724
2725 self.moveto(&self.params.clone(), &self.code.clone());
2726
2727 Ok(())
2728 }
2729
2730 fn moveto(&mut self, to: &str, code: &str) {
2731 let mut moveto = json!({});
2732 let mut hasher = Md5::new();
2733
2734 hasher.update(code.replace("\n", "").replace(" ", ""));
2736 let code_hash = hasher.finalize();
2737 let code_hash = format!("{:x}", code_hash);
2738
2739 moveto[to] = json!(code);
2740 self.shared.schema["__moveto"][&code_hash] = moveto;
2741 }
2742
2743 fn parse_bif_neutral(&mut self) -> Result<(), BifError> {
2747 if self.mod_filter || self.mod_negate || self.mod_scope {
2748 return Err(BifError {
2749 msg: "modifier not allowed".to_string(),
2750 name: self.alias.clone(),
2751 src: self.raw.to_string(),
2752 });
2753 }
2754
2755 self.out = self.raw.to_string();
2756
2757 Ok(())
2758 }
2759
2760 fn parse_bif_param(&mut self) -> Result<(), BifError> {
2765 if self.mod_filter || self.mod_negate || self.mod_scope {
2766 return Err(BifError {
2767 msg: "modifier not allowed".to_string(),
2768 name: self.alias.clone(),
2769 src: self.raw.to_string(),
2770 });
2771 }
2772
2773 let is_set = self.extract_params_code(true);
2774 if is_set {
2775 if self.inherit.alias == "code" {
2776 if self.code.contains(BIF_OPEN) {
2777 self.code = new_child_parse!(self, &self.code, self.mod_scope);
2778 }
2779
2780 self.inherit.create_block_schema(self.shared);
2781 self.shared.schema["__indir"][&self.inherit.indir]["params"][&self.params] =
2782 json!(&self.code);
2783 self.out = EMPTY_STRING;
2784
2785 Ok(())
2786 } else {
2787 Err(BifError {
2788 msg: "param cannot be set here".to_string(),
2789 name: self.alias.clone(),
2790 src: self.raw.to_string(),
2791 })
2792 }
2793 } else {
2794 if self.code.contains(BIF_OPEN) {
2795 self.code = new_child_parse!(self, &self.code, self.mod_scope);
2796 }
2797
2798 self.code = get_from_key(
2799 &self.shared.schema["__indir"][&self.inherit.indir]["params"],
2800 &self.code,
2801 );
2802 self.out = self.code.to_string();
2803
2804 Ok(())
2805 }
2806 }
2807
2808 fn parse_bif_rand(&mut self) -> Result<(), BifError> {
2813 if self.mod_filter || self.mod_negate || self.mod_scope {
2814 return Err(BifError {
2815 msg: "modifier not allowed".to_string(),
2816 name: self.alias.clone(),
2817 src: self.raw.to_string(),
2818 });
2819 }
2820
2821 let mut rng = rand::rng();
2822 self.code = self.src.trim().to_string();
2823
2824 if self.src.contains(BIF_OPEN) {
2825 self.code = new_child_parse!(self, &self.code, self.mod_scope);
2826 } else {
2827 self.code = self.src.trim().to_string();
2828 }
2829
2830 if self.code.is_empty() {
2831 self.out = rng.random_range(100000000..=999999999).to_string();
2832 } else {
2833 self.code = self.code.replace("..", " ");
2835 let mut parts = self.code.split_whitespace();
2836
2837 let from = match parts.next() {
2838 Some(value) => match value.parse::<i32>() {
2839 Ok(num) => num,
2840 Err(_) => {
2841 return Err(BifError {
2842 msg: "argument is not a number".to_string(),
2843 name: self.alias.clone(),
2844 src: self.raw.to_string(),
2845 })
2846 }
2847 },
2848 None => {
2849 return Err(BifError {
2850 msg: "arguments not found".to_string(),
2851 name: self.alias.clone(),
2852 src: self.raw.to_string(),
2853 })
2854 }
2855 };
2856
2857 let to = match parts.next() {
2858 Some(value) => match value.parse::<i32>() {
2859 Ok(num) => num,
2860 Err(_) => {
2861 return Err(BifError {
2862 msg: "argument is not a number".to_string(),
2863 name: self.alias.clone(),
2864 src: self.raw.to_string(),
2865 })
2866 }
2867 },
2868 None => {
2869 return Err(BifError {
2870 msg: "arguments not found".to_string(),
2871 name: self.alias.clone(),
2872 src: self.raw.to_string(),
2873 })
2874 }
2875 };
2876
2877 if from > to {
2878 return Err(BifError {
2879 msg: "from > to".to_string(),
2880 name: self.alias.clone(),
2881 src: self.raw.to_string(),
2882 });
2883 }
2884
2885 self.out = rng.random_range(from..=to).to_string();
2886 }
2887
2888 Ok(())
2889 }
2890
2891 fn parse_bif_redirect(&mut self) -> Result<(), BifError> {
2896 if self.mod_filter || self.mod_scope || self.mod_negate {
2897 return Err(BifError {
2898 msg: "modifier not allowed".to_string(),
2899 name: self.alias.clone(),
2900 src: self.raw.to_string(),
2901 });
2902 }
2903
2904 if self.inherit.in_cache {
2905 self.out = format!("{}{}{}", "{:!cache;", self.raw.to_string(), ":}");
2906 } else {
2907 self.out = EMPTY_STRING;
2908 }
2909
2910 let status_code;
2911 let has_status_params = self.extract_params_code(true);
2912
2913 if self.code.contains(BIF_OPEN) {
2914 self.code = new_child_parse!(self, &self.src, false);
2915 }
2916
2917 if has_status_params {
2918 status_code = match self.params.as_str() {
2920 "301" => {
2921 if self.code.is_empty() {
2922 return Err(BifError {
2923 msg: "this redirection requires URL".to_string(),
2924 name: self.alias.clone(),
2925 src: self.raw.to_string(),
2926 });
2927 }
2928
2929 "301"
2930 }
2931 "302" => {
2932 if self.code.is_empty() {
2933 return Err(BifError {
2934 msg: "this redirection requires URL".to_string(),
2935 name: self.alias.clone(),
2936 src: self.raw.to_string(),
2937 });
2938 }
2939
2940 "302"
2941 }
2942 "303" => {
2943 if self.code.is_empty() {
2944 return Err(BifError {
2945 msg: "this redirection requires URL".to_string(),
2946 name: self.alias.clone(),
2947 src: self.raw.to_string(),
2948 });
2949 }
2950
2951 "303"
2952 }
2953 "307" => {
2954 if self.code.is_empty() {
2955 return Err(BifError {
2956 msg: "this redirection requires URL".to_string(),
2957 name: self.alias.clone(),
2958 src: self.raw.to_string(),
2959 });
2960 }
2961
2962 "307"
2963 }
2964 "308" => {
2965 if self.code.is_empty() {
2966 return Err(BifError {
2967 msg: "this redirection requires URL".to_string(),
2968 name: self.alias.clone(),
2969 src: self.raw.to_string(),
2970 });
2971 }
2972
2973 "308"
2974 }
2975 "js:reload:top" => {
2976 self.shared.redirect_js = REDIR_JS_RELOAD_TOP.to_string();
2977
2978 "200"
2979 }
2980 "js:reload:self" => {
2981 self.shared.redirect_js = REDIR_JS_RELOAD_SELF.to_string();
2982
2983 "200"
2984 }
2985 "js:redirect:top" => {
2986 if self.code.is_empty() {
2987 return Err(BifError {
2988 msg: "this redirection requires URL".to_string(),
2989 name: self.alias.clone(),
2990 src: self.raw.to_string(),
2991 });
2992 }
2993 self.shared.redirect_js =
2995 REDIR_JS_REDIRECT_TOP.replace("{}", &self.code).to_string();
2996
2997 "200"
2998 }
2999 "js:redirect:self" => {
3000 if self.code.is_empty() {
3001 return Err(BifError {
3002 msg: "this redirection requires URL".to_string(),
3003 name: self.alias.clone(),
3004 src: self.raw.to_string(),
3005 });
3006 }
3007 self.shared.redirect_js =
3009 REDIR_JS_REDIRECT_SELF.replace("{}", &self.code).to_string();
3010
3011 "200"
3012 }
3013 _ => {
3014 if !self.code.contains("js:reload:self") || !self.code.contains("js:reload:top")
3016 {
3017 return Err(BifError {
3018 msg: "status code not allowed".to_string(),
3019 name: self.alias.clone(),
3020 src: self.raw.to_string(),
3021 });
3022 } else {
3023 "200"
3024 }
3025 }
3026 };
3027 } else {
3028 status_code = match self.code.as_str() {
3030 "js:reload:top" => {
3031 self.shared.redirect_js = REDIR_JS_RELOAD_TOP.to_string();
3032
3033 "200"
3034 }
3035 "js:reload:self" => {
3036 self.shared.redirect_js = REDIR_JS_RELOAD_SELF.to_string();
3037
3038 "200"
3039 }
3040 _ => {
3041 return Err(BifError {
3042 msg: "redirect type not allowed".to_string(),
3043 name: self.alias.clone(),
3044 src: self.raw.to_string(),
3045 })
3046 }
3047 };
3048 }
3049
3050 self.shared.status_param = self.code.to_string();
3051 self.shared.status_code = status_code.to_string();
3052
3053 if let Some(text) = STATUS_CODES.get(status_code) {
3054 self.shared.status_text = text.to_string();
3055 } else {
3056 self.shared.status_text = EMPTY_STRING;
3057 }
3058
3059 self.shared.exit = true ^ self.mod_negate;
3060
3061 Ok(())
3062 }
3063
3064 fn parse_bif_replace(&mut self) -> Result<(), BifError> {
3069 if self.mod_filter || self.mod_negate || self.mod_scope {
3070 return Err(BifError {
3071 msg: "modifier not allowed".to_string(),
3072 name: self.alias.clone(),
3073 src: self.raw.to_string(),
3074 });
3075 }
3076
3077 self.extract_params_code(false);
3078 let args = self.extract_args();
3079
3080 let from = args.get(1)
3081 .cloned()
3082 .ok_or_else(|| {
3083 BifError {
3084 msg: "arguments not found".to_string(),
3085 name: self.alias.clone(),
3086 src: self.raw.to_string(),
3087 }
3088 })?;
3089
3090 let to = args.get(2)
3091 .cloned()
3092 .ok_or_else(|| {
3093 BifError {
3094 msg: "arguments not found".to_string(),
3095 name: self.alias.clone(),
3096 src: self.raw.to_string(),
3097 }
3098 })?;
3099
3100 if self.code.contains(BIF_OPEN) {
3101 self.code = new_child_parse!(self, &self.code, self.mod_scope);
3102 }
3103
3104 self.out = self.code.replace(&from, &to);
3105
3106 Ok(())
3107 }
3108
3109 fn parse_bif_same(&mut self) -> Result<(), BifError> {
3113 if self.mod_filter {
3114 return Err(BifError {
3115 msg: "modifier not allowed".to_string(),
3116 name: self.alias.clone(),
3117 src: self.raw.to_string(),
3118 });
3119 }
3120
3121 self.extract_params_code(false);
3122 let args = self.extract_args();
3123
3124 let param1 = args.get(1)
3125 .cloned()
3126 .ok_or_else(|| {
3127 BifError {
3128 msg: "arguments not found".to_string(),
3129 name: self.alias.clone(),
3130 src: self.raw.to_string(),
3131 }
3132 })?;
3133
3134 let param2 = args.get(2)
3135 .cloned()
3136 .ok_or_else(|| {
3137 BifError {
3138 msg: "arguments not found".to_string(),
3139 name: self.alias.clone(),
3140 src: self.raw.to_string(),
3141 }
3142 })?;
3143
3144 if (param1 == param2) ^ self.mod_negate {
3145 if self.code.contains(BIF_OPEN) {
3146 self.code = new_child_parse!(self, &self.code, self.mod_scope);
3147 }
3148 self.out = self.code.to_string();
3149 } else {
3150 self.out = EMPTY_STRING;
3151 }
3152
3153 Ok(())
3154 }
3155
3156 fn parse_bif_snippet(&mut self) -> Result<(), BifError> {
3166 if self.mod_filter || self.mod_negate || self.mod_scope {
3167 return Err(BifError {
3168 msg: "modifier not allowed".to_string(),
3169 name: self.alias.clone(),
3170 src: self.raw.to_string(),
3171 });
3172 }
3173
3174 self.alias = "snippet".to_string();
3175
3176 let is_set = self.extract_params_code(true);
3177 if is_set {
3178 if self.inherit.current_file.contains(SNIPPETS_FILES) || self.inherit.alias == "snippet"
3180 {
3181 if self.flags.contains("|static|") {
3182 self.code = new_child_parse!(self, &self.code, self.mod_scope);
3183 } else {
3184 self.inherit.create_block_schema(self.shared);
3186 }
3187 self.shared.schema["__indir"][&self.inherit.indir]["snippets"][&self.params] =
3188 json!(&self.code);
3189
3190 self.shared.schema["__indir"][&self.inherit.indir]["snippets_set_dir"][&self.params] =
3192 json!(&self.inherit.current_dir);
3193
3194 self.out = EMPTY_STRING;
3195
3196 Ok(())
3197 } else {
3198 Err(BifError {
3199 msg: "snippet cannot be set here".to_string(),
3200 name: self.alias.clone(),
3201 src: self.raw.to_string(),
3202 })
3203 }
3204 } else {
3205 if self.code.contains(BIF_OPEN) {
3207 self.code = new_child_parse!(self, &self.code, false);
3208 }
3209 let snip_name = self.code.clone();
3210
3211 self.code = get_from_key(
3212 &self.shared.schema["__indir"][&self.inherit.indir]["snippets"],&self.code,
3213 );
3214
3215 if self.code.contains(BIF_OPEN) {
3216
3217 let set_dir = get_from_key(
3219 &self.shared.schema["__indir"][&self.inherit.indir]["snippets_set_dir"],&snip_name,
3220 );
3221
3222 if !set_dir.is_empty() {
3223 self.inherit.current_dir = set_dir;
3224 }
3225
3226 self.code = new_child_parse!(self, &self.code, self.code.contains("{:snip"));
3228 }
3229
3230 self.out = self.code.to_string();
3231
3232 Ok(())
3233 }
3234 }
3235
3236 fn parse_bif_trans(&mut self) -> Result<(), BifError> {
3240 if self.mod_filter || self.mod_scope {
3241 return Err(BifError {
3242 msg: "modifier not allowed".to_string(),
3243 name: self.alias.clone(),
3244 src: self.raw.to_string(),
3245 });
3246 }
3247
3248 if self.src.contains(BIF_OPEN) {
3250 self.src = new_child_parse!(self, &self.src, self.mod_scope);
3251 }
3252
3253 let trans = self.get_trans(&self.src);
3254
3255 if trans.is_empty() {
3257 if self.mod_negate {
3258 self.out = EMPTY_STRING;
3259 } else {
3260 self.out = self.src.clone();
3261 }
3262 } else {
3263 self.out = trans;
3264 }
3265
3266 Ok(())
3267 }
3268}