neutralts/
lib.rs

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 rand::Rng;
15use regex::Regex;
16use serde_json::json;
17use serde_json::Value;
18use std::env;
19use std::fs;
20use std::path::Path;
21use std::str;
22use std::time::Duration;
23use std::time::Instant;
24
25//  Build-in function layout
26//
27//  .-------------------------------------------------------------> open bif
28//  | .-----------------------------------------------------------> modifier
29//  | |   .-------------------------------------------------------> bif name
30//  | |   |   .---------------------------------------------------> bif name separator
31//  | |   |   |      .--------------------------------------------> bif params
32//  | |   |   |      |       .------------------------------------> params / code separator
33//  | |   |   |      |       |             .----------------------> comment
34//  | |   |   |      |       |             |   .------------------> bif code
35//  | |   |   |      |       |             |   |               .--> close bif
36//  | |   |   |      |       |             |   |               |
37//  v v   v   v      v       v             |   v               v
38//  - - ----- - ------------ -- -----------v------------------ --
39//  {:!snippet; snippet_name >> <div>... {:* ... *:} ...</div> :}
40//  -------------------------------------------------------------
41//          ^  -----------------------------------------------
42//          |                      ^
43//          |                      |
44//          |                      ·------------------------------> bif src
45//          ·-----------------------------------------------------> bif: Build-in function
46
47//  Same level Bif:
48//
49//                  .-----> .-----> {:code:
50//                  |       |           {:code: ... :}
51//                  |       |           {:code: ... :}
52//                  |       |           {:code: ... :}
53//  Level block --> |       ·-----> :}
54//                  |        -----> {:code: ... :}
55//                  |       .-----> {:code:
56//                  |       |           {:code: ... :}
57//                  ·-----> ·-----> :}
58
59//  Flow
60//
61//      .-------------------------------.
62//      │         new Template          │
63//      ·-------------------------------·
64//                     |
65//                     v
66//      .-------------------------------.
67//      │       new BlockParser         │ <------.
68//      |-------------------------------|        |
69//      │      each same level bif      │        |
70//      ·-------------------------------·        |
71//                     |                         |
72//                     v                         |
73//      .-------------------------------.        |
74//      │           new Bif             │        |
75//      |-------------------------------|        |
76//      │         nested bifs? ---------│--------·
77//      ·-------------------------------·
78//                     |
79//                     v
80//          .----------------------.
81//         │       end render       │
82//          ·----------------------·
83
84// Inherit, macro: new_child_parse
85// -------------------------------
86// Inheritance is implemented with this macro. It is also used for the inheritance
87// of the application itself.
88//
89//
90// Block level scope example:
91//    {:code; <--------------------------.
92//        {:* block *:}                  |<---- Block
93//        {:param; name >> value :} <----|----- Set "name" for this block and its children
94//        {:param; name :} <-------------|----- "name" has the value "value".
95//        {:code;                        |
96//            {:* child block *:}        |
97//            {:param; name :} <---------|----- "name" has the value "value".
98//        :}                             |
99//    :} <-------------------------------·
100//    {:param; name :} <----------------------- outside block, no value or a previous value if any.
101//
102//
103// "include" has a block scope, then:
104//    {:code;
105//        {:* include for set "snippet-name" *:}
106//        {:include; snippet.ntpl :}
107//        {:snippet; snippet-name :} {:* Ok, "snippet-name" is set *:}
108//    :}
109//    {:snippet; snippet-name :} {:* Ko, "snippet-name" is not set *:}
110//
111// The modifier scope (+) adds the scope to the current level to make it possible to do this:
112//    {:+bool; something >>
113//        {:include; snippet.ntpl :}
114//    :}
115//    {:snippet; snippet-name :} {:* Ok, "snippet-name" is set *:}
116//
117#[macro_use]
118mod macros {
119    macro_rules! new_child_parse {
120        ($self:expr, $source:expr, $scope:expr) => {{
121            let mut child_inherit = $self.inherit.clone();
122            let shared = &mut $self.shared;
123
124            //  "bif.alias" is used and not "bif.name" because in "var" or "unprintable"
125            // its name is an empty string and could have more meanings.
126            child_inherit.alias = $self.alias.clone();
127
128            if !$self.file_path.is_empty() {
129                child_inherit.current_file = $self.file_path.clone();
130            }
131
132            if !$self.dir.is_empty() {
133                child_inherit.current_dir = $self.dir.clone();
134            }
135
136            // Create a new version of the schema if mod_scope
137            // This is necessary because indirections are used,
138            // and create_block_schema takes care of that.
139            if $scope {
140                $self.inherit.create_block_schema(shared);
141            }
142
143            let mut block = BlockParser::new(shared, &child_inherit);
144            let code = block.parse($source);
145
146            // Update this block with the data generated in the child
147            if $scope {
148                // el código que estaba aquí lo he movido a la función
149                // update_indir para evitar un error de prestamo.
150                block.update_indir(&$self.inherit.indir);
151            }
152
153            code
154        }};
155    }
156}
157
158struct BifError {
159    code: i32,
160    msg: String,
161    name: String,
162    src: String,
163}
164
165// Global shared variables
166struct Shared {
167    schema: Value,
168    lang: String,
169    comments: String,
170    bisf_count: u64,
171    bisf_max: u64,
172    flags: String,
173    exit: bool,
174    has_error: bool,
175    status_code: String,
176    status_text: String,
177    status_param: String,
178    redirect_js: String,
179    filter_all: bool,
180    // working_dir: String,
181}
182
183impl Shared {
184    fn new(mut schema: Value) -> Self {
185        let bisf_max = schema["config"]["infinite_loop_max_bifs"].as_u64().unwrap();
186        let comments = get_from_key(&schema["config"], "comments");
187        let lang = get_from_key(&schema["inherit"]["locale"], "current");
188        let working_dir = get_from_key(&schema["config"], "working_dir");
189        let filter_all = is_bool_key(&schema["config"], "filter_all");
190
191        if !working_dir.is_empty() {
192            env::set_current_dir(&working_dir).unwrap();
193            schema["data"]["CONTEXT"]["working_dir"] = json!(working_dir);
194        } else {
195            schema["data"]["CONTEXT"]["working_dir"] = json!(env::current_dir().unwrap());
196        }
197
198        Shared {
199            schema,
200            lang,
201            comments,
202            bisf_count: 0,
203            bisf_max,
204            flags: String::new(),
205            exit: false,
206            has_error: false,
207            status_code: "200".to_string(),
208            status_text: "OK".to_string(),
209            status_param: String::new(),
210            redirect_js: String::new(),
211            filter_all,
212            // working_dir,
213        }
214    }
215}
216
217struct BlockInherit {
218    indir: String,
219    last_bif_out: bool,
220    last_coalesce_out: bool,
221    block_count: u64, // u64 is default type in Value nums
222    bif_count: u64,   // u64 is default type in Value nums
223    alias: String,
224    current_file: String,
225    current_dir: String,
226    include_files: Vec<String>,
227    locale_files: Vec<String>,
228    data_files: Vec<String>,
229}
230
231impl Clone for BlockInherit {
232    fn clone(&self) -> Self {
233        BlockInherit {
234            indir: self.indir.clone(),
235            last_bif_out: self.last_bif_out,
236            last_coalesce_out: self.last_coalesce_out,
237            block_count: self.block_count,
238            bif_count: self.bif_count,
239            alias: self.alias.clone(),
240            current_file: self.current_file.clone(),
241            current_dir: self.current_dir.clone(),
242            include_files: self.include_files.clone(),
243            locale_files: self.locale_files.clone(),
244            data_files: self.data_files.clone(),
245        }
246    }
247}
248
249impl BlockInherit {
250    fn new() -> Self {
251        BlockInherit {
252            indir: "block_0".to_string(),
253            last_bif_out: false,
254            last_coalesce_out: false,
255            block_count: 0,
256            bif_count: 0,
257            alias: String::new(),
258            current_file: String::new(),
259            current_dir: String::new(),
260            include_files: Vec::new(),
261            locale_files: Vec::new(),
262            data_files: Vec::new(),
263        }
264    }
265
266    // Create version of data for inheritance at the block level.
267    // For performance reasons, instead of inheriting the complete cloned schema,
268    // we inherit a reference to the data in the root schema.
269    // Therefore, this function should be called before creating data
270    // that needs to be inherited to obtain the reference to the storage.
271    fn create_block_schema(&mut self, shared: &mut Shared) -> String {
272        let prev_id = self.indir.clone();
273        let block_id;
274
275        // If this function is called before creating the first block.
276        // It may be necessary to initialize values.
277        // The first block is not 0, is 1.
278        if self.block_count < 1 {
279            block_id = "block_1".to_string();
280        } else {
281            block_id = "block_".to_string() + self.block_count.to_string().as_str();
282        }
283
284        // It can be called several times from the same level, in which case
285        // it does not need to be cloned again.
286        if prev_id != block_id {
287            // This line consumes more than 50% of the execution time with an average
288            // amount of data, with a lot of data it could consume much more, therefore
289            // this site is the first one to look at when improving performance.
290            shared.schema["__indir"][&block_id] = shared.schema["__indir"][&prev_id].clone();
291        }
292
293        self.indir = block_id.clone();
294
295        block_id
296    }
297}
298
299pub struct Template<'a> {
300    raw: String,
301    file_path: &'a str,
302    schema: Value,
303    shared: Shared,
304    time_start: Instant,
305    time_elapsed: Duration,
306    out: String,
307}
308
309/// A struct representing a template that can be rendered.
310///
311/// This struct is used to handle the rendering of templates.
312impl<'a> Template<'a> {
313    /// Constructs a new `Template` instance with default settings.
314    ///
315    /// It allows you to set up a template and schema with different types.
316    pub fn new() -> Result<Self, String> {
317        let default_schema: Value = match serde_json::from_str(DEFAULT) {
318            Ok(value) => value,
319            Err(_) => return Err("const DEFAULT is not a valid JSON string".to_string()),
320        };
321        let shared = Shared::new(default_schema.clone());
322
323        Ok(Template {
324            raw: String::new(),
325            file_path: "",
326            schema: default_schema,
327            shared,
328            time_start: Instant::now(),
329            time_elapsed: Instant::now().elapsed(),
330            out: String::new(),
331        })
332    }
333
334    /// Constructs a new `Template` instance from a file path and a JSON schema.
335    ///
336    /// # Arguments
337    ///
338    /// * `file_path` - A reference to the path of the file containing the template content.
339    /// * `schema` - A JSON value representing the custom schema to be used with the template.
340    ///
341    /// # Returns
342    ///
343    /// A `Result` containing the new `Template` instance or an error message if:
344    /// - The file cannot be read.
345    pub fn from_file_value(file_path: &'a str, schema: Value) -> Result<Self, String> {
346        let raw: String = match fs::read_to_string(file_path) {
347            Ok(s) => s,
348            Err(e) => {
349                eprintln!("Cannot be read: {}", file_path);
350                return Err(e.to_string());
351            }
352        };
353        let mut default_schema: Value = match serde_json::from_str(DEFAULT) {
354            Ok(value) => value,
355            Err(_) => {
356                eprintln!("Internal error in const DEFAULT {}, line: {}", file!(), line!());
357                return Err("const DEFAULT is not a valid JSON string".to_string());
358            }
359        };
360
361        merge_schema(&mut default_schema, &schema);
362        let shared = Shared::new(default_schema.clone());
363
364        Ok(Template {
365            raw,
366            file_path,
367            schema: default_schema,
368            shared,
369            time_start: Instant::now(),
370            time_elapsed: Instant::now().elapsed(),
371            out: String::new(),
372        })
373    }
374
375    /// Sets the source path of the template.
376    ///
377    /// # Arguments
378    ///
379    /// * `file_path` - A reference to the path of the file containing the template content.
380    ///
381    /// # Returns
382    ///
383    /// A `Result` indicating success or an error message if the file cannot be read
384    pub fn set_src_path(&mut self, file_path: &'a str) -> Result<(), String> {
385        self.file_path = file_path;
386        self.raw = match fs::read_to_string(file_path) {
387            Ok(s) => s,
388            Err(e) => {
389                eprintln!("Cannot be read: {}", file_path);
390                return Err(e.to_string());
391            }
392        };
393
394        Ok(())
395    }
396
397    /// Sets the content of the template from a string.
398    ///
399    /// # Arguments
400    ///
401    /// * `source` - A reference to the new string content to be set as the raw content.
402    pub fn set_src_str(&mut self, source: &str) {
403        self.raw = source.to_string();
404    }
405
406    /// Merges the schema from a file with the current template schema.
407    ///
408    /// # Arguments
409    ///
410    /// * `schema_path` - A reference to the path of the file containing the schema content.
411    ///
412    /// # Returns
413    ///
414    /// A `Result` indicating success or an error message if:
415    /// - The file cannot be read.
416    /// - The file's content is not a valid JSON string.
417    pub fn merge_schema_path(&mut self, schema_path: &str) -> Result<(), String> {
418        let schema_str: String = match fs::read_to_string(schema_path) {
419            Ok(s) => s,
420            Err(e) => {
421                eprintln!("Cannot be read: {}", schema_path);
422                return Err(e.to_string());
423            }
424        };
425        let schema_value: Value = match serde_json::from_str(&schema_str) {
426            Ok(value) => value,
427            Err(_) => {
428                return Err("Is not a valid JSON file".to_string());
429            }
430        };
431        merge_schema(&mut self.schema, &schema_value);
432
433        Ok(())
434    }
435
436    /// Merges the schema from a JSON string with the current template schema.
437    ///
438    /// # Arguments
439    ///
440    /// * `schema` - A reference to the JSON string of the schema content.
441    ///
442    /// # Returns
443    ///
444    /// A `Result` indicating success or an error message if:
445    /// - The file's content is not a valid JSON string.
446    pub fn merge_schema_str(&mut self, schema: &str) -> Result<(), String> {
447        let schema_value: Value = match serde_json::from_str(schema) {
448            Ok(value) => value,
449            Err(_) => {
450                return Err("Is not a valid JSON string".to_string());
451            }
452        };
453        merge_schema(&mut self.schema, &schema_value);
454
455        Ok(())
456    }
457
458    /// Merges the provided JSON value with the current schema.
459    ///
460    /// # Arguments
461    ///
462    /// * `schema` - The JSON Value to be merged with the current schema.
463    pub fn merge_schema_value(&mut self, schema: Value) {
464        merge_schema(&mut self.schema, &schema);
465    }
466
467    /// Renders the template content.
468    ///
469    /// This function initializes the rendering process.
470    /// The resulting output is returned as a string.
471    ///
472    /// # Returns
473    ///
474    /// The rendered template content as a string.
475    pub fn render(&mut self) -> String {
476        let inherit = self.init_render();
477        self.out = BlockParser::new(&mut self.shared, &inherit).parse(&self.raw);
478        self.ends_render();
479
480        self.out.clone()
481    }
482
483    // Restore vars for render
484    fn init_render(&mut self) -> BlockInherit {
485        self.time_start = Instant::now();
486        self.shared = Shared::new(self.schema.clone());
487
488        if self.shared.comments.contains("remove") {
489            self.raw = remove_comments(&self.raw);
490        }
491
492        // init inherit
493        let mut inherit = BlockInherit::new();
494        let indir = inherit.create_block_schema(&mut self.shared);
495        self.shared.schema["__moveto"] = json!({});
496        self.shared.schema["__error"] = json!([]);
497        self.shared.schema["__indir"] = json!({});
498        self.shared.schema["__indir"][&indir] = self.shared.schema["inherit"].clone();
499        inherit.current_file = self.file_path.to_string();
500
501        if !self.file_path.is_empty() {
502            let path = Path::new(&self.file_path);
503
504            if let Some(parent) = path.parent() {
505                inherit.current_dir = parent.display().to_string();
506            }
507        } else {
508            inherit.current_dir = self.shared.schema["data"]["CONTEXT"]["working_dir"].to_string();
509        }
510
511        inherit
512    }
513
514    // Rendering ends
515    fn ends_render(&mut self) {
516        self.set_moveto();
517        self.replacements();
518        self.set_status_code();
519        self.time_elapsed = self.time_start.elapsed();
520    }
521
522    fn set_status_code(&mut self) {
523        let status_code = self.shared.status_code.as_str();
524
525        if ("400"..="599").contains(&status_code) {
526            self.out = format!("{} {}", self.shared.status_code, self.shared.status_text);
527
528            return;
529        }
530
531        if status_code == "301"
532            || status_code == "302"
533            || status_code == "303"
534            || status_code == "307"
535            || status_code == "308"
536        {
537            self.out = format!(
538                "{} {}\n{}",
539                self.shared.status_code, self.shared.status_text, self.shared.status_param
540            );
541
542            return;
543        }
544
545        if !self.shared.redirect_js.is_empty() {
546            self.out = self.shared.redirect_js.clone();
547        }
548    }
549
550    fn set_moveto(&mut self) {
551        if let Value::Object(data_map) = &self.shared.schema["__moveto"] {
552            for (_key, value) in data_map {
553                if let Value::Object(inner_map) = value {
554                    for (inner_key, inner_value) in inner_map {
555                        let mut tag;
556
557                        // although it should be "<tag" or "</tag" it also supports
558                        // "tag", "/tag", "<tag>" and "</tag>
559                        if !inner_key.starts_with("<") {
560                            tag = format!("<{}", inner_key);
561                        } else {
562                            tag = inner_key.to_string();
563                        }
564                        if tag.ends_with(">") {
565                            tag = tag[..tag.len() - 1].to_string();
566                        }
567
568                        // if it does not find it, it does nothing
569                        let position = find_tag_position(&self.out, &tag);
570                        if let Some(pos) = position {
571                            let mut insert = inner_value.as_str().unwrap().to_string();
572                            insert = insert.to_string();
573                            self.out.insert_str(pos, &insert);
574                        }
575                    }
576                }
577            }
578        }
579    }
580
581    fn replacements(&mut self) {
582        let pattern = format!(r"\s*{}", BACKSPACE);
583        let re = Regex::new(&pattern).expect("Failed to create regex with constant pattern");
584        self.out = re.replace_all(&self.out, "").to_string();
585
586        // UNPRINTABLE should be substituted after BACKSPACE
587        self.out = self.out.replace(UNPRINTABLE, "");
588    }
589
590    /// Retrieves the status code.
591    ///
592    /// The status code is "200" unless "exit", "redirect" is used or the
593    /// template contains a syntax error, which will return a status code
594    /// of "500". Although the codes are numeric, a string is returned.
595    ///
596    /// # Returns
597    ///
598    /// A reference to the status code as a string.
599    pub fn get_status_code(&self) -> &String {
600        &self.shared.status_code
601    }
602
603    /// Retrieves the status text.
604    ///
605    /// It will correspond to the one set by the HTTP protocol.
606    ///
607    /// # Returns
608    ///
609    /// A reference to the status text as a string.
610    pub fn get_status_text(&self) -> &String {
611        &self.shared.status_text
612    }
613
614    /// Retrieves the status parameter.
615    ///
616    /// Some statuses such as 301 (redirect) may contain additional data, such
617    /// as the destination URL, and in similar cases “param” will contain
618    /// that value.
619    ///
620    /// # Returns
621    ///
622    /// A reference to the status parameter as a string.
623    pub fn get_status_param(&self) -> &String {
624        &self.shared.status_param
625    }
626
627    /// Checks if there is an error.
628    ///
629    /// If any error has occurred, in the parse or otherwise, it will return true.
630    ///
631    /// # Returns
632    ///
633    /// A boolean indicating whether there is an error.
634    pub fn has_error(&self) -> bool {
635        self.shared.has_error
636    }
637
638    /// Get bifs errors list
639    ///
640    /// # Returns
641    ///
642    /// * `Value`: A clone of the value with the list of errors in the bifs during rendering.
643    pub fn get_error(&self) -> Value {
644        self.shared.schema["__error"].clone()
645    }
646
647    /// Retrieves the time duration for template rendering.
648    ///
649    /// # Returns
650    ///
651    /// The time duration elapsed .
652    pub fn get_time_duration(&self) -> Duration {
653        let duration: std::time::Duration = self.time_elapsed;
654
655        duration
656    }
657}
658
659struct BlockParser<'a> {
660    shared: &'a mut Shared,
661    inherit: BlockInherit,
662    _none: &'a str,
663}
664
665impl Drop for BlockParser<'_> {
666    fn drop(&mut self) {
667        // release memory
668        let block_id = "block_".to_string() + self.inherit.block_count.to_string().as_str();
669        if block_id == self.inherit.indir && is_defined_key(&self.shared.schema["__indir"], &block_id) {
670            self.shared.schema["__indir"][&block_id] = json!({});
671        }
672    }
673}
674
675impl<'a> BlockParser<'a> {
676    fn new(shared: &'a mut Shared, inherit: &BlockInherit) -> Self {
677        let mut inherit = inherit.clone();
678        inherit.block_count += 1;
679
680        BlockParser {
681            shared,
682            inherit,
683            _none: "",
684        }
685    }
686
687    fn update_indir(&mut self, indir: &String) {
688        self.shared.schema["__indir"][indir] =
689            self.shared.schema["__indir"][&self.inherit.indir].clone();
690    }
691
692    fn parse(&mut self, raw_source: &'a str) -> String {
693        let blocks;
694
695        match extract_blocks(raw_source) {
696            Ok(b) => {
697                blocks = b;
698            }
699            Err(p) => {
700                self.shared.status_code = "500".to_string();
701                self.shared.status_param = format!("Unmatched block at position {}", p);
702                eprintln!("Unmatched block at position {}", p);
703
704                if let Some(text) = STATUS_CODES.get(self.shared.status_code.as_str()) {
705                    self.shared.status_text = text.to_string();
706                } else {
707                    self.shared.status_text = EMPTY_STRING;
708                }
709
710                return EMPTY_STRING;
711            }
712        }
713
714        let mut prev_end = 0;
715        let mut out = String::new();
716        for (start, end) in blocks {
717            let is_comment = raw_source[start..end].starts_with(BIF_COMMENT_OPEN);
718            let is_short_circuit_coalesce =
719                self.inherit.last_coalesce_out && self.inherit.alias == "coalesce";
720
721            if self.shared.exit {
722                return out.clone();
723            }
724
725            if prev_end < start {
726                out += &raw_source[prev_end..start];
727            }
728
729            if !is_comment && !is_short_circuit_coalesce {
730                let mut bif =
731                    Bif::new(&raw_source[start..end], self.shared, &mut self.inherit);
732                out += &bif.parse();
733            }
734
735            prev_end = end;
736        }
737        out += &raw_source[prev_end..];
738
739        out.trim().to_string()
740    }
741}
742
743struct Bif<'a> {
744    raw: &'a str,
745    shared: &'a mut Shared,
746    inherit: &'a mut BlockInherit,
747    src: String,
748    name: String,
749    alias: String,
750    code: String,
751    params: String,
752    flags: String,
753    mod_filter: bool,
754    mod_negate: bool,
755    mod_upline: bool,
756    mod_scope: bool,
757    file_path: String,
758    dir: String,
759    out: String,
760    _none: &'a str,
761}
762
763impl<'a> Bif<'a> {
764    fn new(raw_source: &'a str, shared: &'a mut Shared, inherit: &'a mut BlockInherit) -> Self {
765        shared.bisf_count += 1;
766        let count = shared.bisf_count;
767        inherit.bif_count = shared.bisf_count;
768
769        if count > shared.bisf_max {
770            panic!(
771                "Infinite loop? {} bifs of {} max have been created.",
772                shared.bisf_max, count
773            );
774        }
775
776        Bif {
777            raw: raw_source, // should not be modified
778            shared,
779            inherit,
780            src: String::new(),
781            name: String::new(),
782            alias: String::new(),
783            code: String::new(),
784            params: String::new(),
785            flags: String::new(),
786            mod_filter: false,
787            mod_negate: false,
788            mod_upline: false,
789            mod_scope: false,
790            file_path: String::new(),
791            dir: String::new(),
792            out: String::new(),
793            _none: "",
794        }
795    }
796
797    // Divides the bif into its parts and executes the bif parse function.
798    fn parse(&mut self) -> String {
799        let bif = strip_prefix_suffix(self.raw, BIF_OPEN, BIF_CLOSE);
800        let result;
801
802        if let Some((name, src)) = bif.split_once(BIF_NAME) {
803            self.name = name.to_string();
804            if name == "neutral" {
805                self.src = src.to_string();
806            } else {
807                self.src = src.trim().to_string();
808            }
809        } else {
810            let show_error = self.shared.schema["config"]["error"]["show"].as_bool().unwrap();
811            let error_line = format!("The delimiter was not found: {}", self.raw);
812            let error_line = error_line.replace(['\n', '\r'], " ");
813
814            if let Some(Value::Array(ref mut errors)) = self.shared.schema.get_mut("__error") {
815                errors.push(json!(error_line));
816            }
817
818            if show_error {
819                eprintln!("{}", error_line);
820            }
821
822            self.shared.has_error = true;
823
824            return EMPTY_STRING;
825        }
826        self.name = self.set_modifiers();
827        self.alias = self.name.clone();
828
829        // exec the function of each bif
830        match &self.name[..] {
831            "" => result = self.parse_bif_var(),
832            "allow" => result = self.parse_bif_allow(),
833            "array" => result = self.parse_bif_array(),
834            "bool" => result = self.parse_bif_bool(),
835            "coalesce" => result = self.parse_bif_coalesce(),
836            "code" => result = self.parse_bif_code(),
837            "count" => result = self.parse_bif_count(),
838            "data" => result = self.parse_bif_data(),
839            "date" => result = self.parse_bif_date(),
840            "declare" => result = self.parse_bif_declare(),
841            "defined" => result = self.parse_bif_defined(),
842            "each" => result = self.parse_bif_each(),
843            "else" => result = self.parse_bif_else(),
844            "eval" => result = self.parse_bif_eval(),
845            "exit" => result = self.parse_bif_exit(),
846            "filled" => result = self.parse_bif_filled(),
847            "flg" => result = self.parse_bif_flg(),
848            "for" => result = self.parse_bif_for(),
849            "hash" => result = self.parse_bif_hash(),
850            "include" => result = self.parse_bif_include(),
851            "lang" => result = self.parse_bif_lang(),
852            "locale" => result = self.parse_bif_locale(),
853            "moveto" => result = self.parse_bif_moveto(),
854            "neutral" => result = self.parse_bif_neutral(),
855            "param" => result = self.parse_bif_param(),
856            "rand" => result = self.parse_bif_rand(),
857            "redirect" => result = self.parse_bif_redirect(),
858            "replace" => result = self.parse_bif_replace(),
859            "same" => result = self.parse_bif_same(),
860            "snippet" => result = self.parse_bif_snippet(),
861            "snip" => result = self.parse_bif_snippet(),
862            "trans" => result = self.parse_bif_trans(),
863            _ => result = self.parse_bif_unknown(),
864        }
865
866        match result {
867            Ok(()) => (),
868            Err(e) => {
869                let show_error = self.shared.schema["config"]["error"]["show"].as_bool().unwrap();
870                let error_line = format!("Error {} ({}) {}  src: {}", e.code, e.name, e.msg, e.src);
871                let error_line = error_line.replace(['\n', '\r'], " ");
872
873                if let Some(Value::Array(ref mut errors)) = self.shared.schema.get_mut("__error") {
874                    errors.push(json!(error_line));
875                }
876
877                if show_error {
878                    eprintln!("{}", error_line);
879                }
880
881                self.shared.has_error = true;
882            }
883        }
884
885        self.inherit.last_bif_out = !self.out.is_empty();
886        self.inherit.last_coalesce_out = self.inherit.last_bif_out;
887
888        if self.mod_upline {
889            self.out = BACKSPACE.to_string() + &self.out;
890            self.out.trim().to_string()
891        } else {
892            self.out.trim().to_string()
893        }
894    }
895
896    //  Determines which modifiers are being used
897    //
898    //    .------ modifier
899    //    |
900    //    v
901    //  {:!snippet; ...
902    //
903    fn set_modifiers(&mut self) -> String {
904        let mut index = 0;
905        while index < self.name.len() {
906            let start = &self.name[index..index + 1];
907            if start == BIF_MOD_FILTER
908                || start == BIF_MOD_NEGATE
909                || start == BIF_MOD_UPLINE
910                || start == BIF_MOD_SCOPE
911            {
912                match start {
913                    BIF_MOD_FILTER => self.mod_filter = true,
914                    BIF_MOD_NEGATE => self.mod_negate = true,
915                    BIF_MOD_UPLINE => self.mod_upline = true,
916                    BIF_MOD_SCOPE => self.mod_scope = true,
917                    _ => unreachable!(),
918                }
919                index += 1;
920            } else {
921                break;
922            }
923        }
924
925        self.name[index..].to_string()
926    }
927
928    // Get key from schema data o local data
929    //
930    // {
931    //     "config": {},
932    //     "inherit": {},
933    //     "data": {}  <------------ schema data get from
934    //     "__indir": {
935    //          "X": {
936    //             "data": {} <----- local data get from
937    //     ...
938    // }
939    fn get_data(&self, name: &str) -> String {
940        if name.starts_with("local::") {
941            let local_name = name.strip_prefix("local::").unwrap_or(name);
942            get_from_key(
943                &self.shared.schema["__indir"][&self.inherit.indir]["data"],
944                local_name,
945            )
946        } else {
947            get_from_key(&self.shared.schema["data"], name)
948        }
949    }
950
951    // Set key to schema data
952    //
953    // {
954    //     "config": {},
955    //     "inherit": {},
956    //     "data": {}  <-------- set to
957    // }
958    fn set_data(&mut self, name: &str, value: &str) {
959        self.shared.schema["data"][name] = json!(value);
960    }
961
962    // Get key from schema locale, an indirection is used instead of its initial position
963    // {
964    //     "config": {},
965    //     "inherit": {
966    //     "locale": { ------------------.
967    //        "current": "en",           |
968    //        "trans": {                 |
969    //           "es": {}                |
970    //         }                         | moved on init Template
971    //     },                            |
972    //     "data": {},                   |
973    //     "__indir": {                  |
974    //          "X": {                   |
975    //             "locale": { <---------·
976    //                 "trans": {
977    //                     "es": {} <----- get from
978    //     ...
979    // }
980    fn get_trans(&self, text: &str) -> String {
981        get_from_key(
982            &self.shared.schema["__indir"][&self.inherit.indir]["locale"]["trans"]
983                [&self.shared.lang],
984            text,
985        )
986    }
987
988    /*
989        dynamic evaluation
990
991        This is not allowed: {:;{:;refvarname:}:}
992        Use instead: {:; {:allow; allowed >> {:;refvarname:} :} :}
993    */
994    fn contains_allow(&self, source: &str) -> bool {
995        for allow in BIF_ALLOWED {
996            if source.contains(allow) {
997                return true;
998            }
999        }
1000
1001        let source = &remove_comments(source);
1002        !(source.starts_with(BIF_VAR) && source.ends_with(BIF_CLOSE))
1003    }
1004
1005    // Split params/code and parse params if parse is true.
1006    // It is possible that it has no parameters, in which case
1007    // it is all code and the parameters are an empty string.
1008    // To set flags, parameters are required.
1009    //
1010    //                   .------------------------------> params
1011    //                   |       .----------------------> separator
1012    //                   |       |
1013    //                   |       |                 .----> code
1014    //                   |       |                 |
1015    //                   v       v                 v
1016    //              ------------ -- ------------------------------
1017    //  {:!snippet; snippet_name >> <div>... {:* ... *:} ...</div> :}
1018    fn extract_params_code(&mut self, parse: bool) -> bool {
1019        let position = get_code_position(&self.src);
1020        let has_code: bool = position.is_some();
1021
1022        if has_code {
1023            let code_pos = position.unwrap();
1024            self.params = self.src[0..code_pos].trim().to_string();
1025            self.code = self.src[code_pos + BIF_CODE.len()..].trim().to_string();
1026        } else {
1027            self.params = EMPTY_STRING;
1028            self.code = self.src.trim().to_string();
1029        }
1030
1031        if parse && self.params.contains(BIF_OPEN) {
1032            self.shared.flags = EMPTY_STRING;
1033            self.params = new_child_parse!(self, &self.params, false);
1034            self.flags = self.shared.flags.clone();
1035        }
1036
1037        has_code
1038    }
1039
1040    /*
1041        unknown bif
1042    */
1043    fn parse_bif_unknown(&mut self) -> Result<(), BifError> {
1044        self.alias = "unknown".to_string();
1045
1046        Err(BifError {
1047            code: 101,
1048            msg: "unknown bif".to_string(),
1049            name: self.alias.clone(),
1050            src: self.raw.to_string(),
1051        })
1052    }
1053
1054    /*
1055        {:;varname:}
1056        {:;:}
1057    */
1058    fn parse_bif_var(&mut self) -> Result<(), BifError> {
1059        if self.mod_scope {
1060            return Err(BifError {
1061                code: 102,
1062                msg: "modifier not allowed".to_string(),
1063                name: self.alias.clone(),
1064                src: self.raw.to_string(),
1065            });
1066        }
1067
1068        // Unprintable: {:;:} / {:; :}
1069        if self.src.is_empty() {
1070            // "bif.alias" is used and not "bif.name" because in "var" or "unprintable"
1071            // its name is an empty string.
1072            self.alias = "unprintable".to_string();
1073
1074            self.out = UNPRINTABLE.to_string();
1075
1076            return Ok(());
1077        }
1078
1079        // Var: {:;varname:}
1080        self.alias = "var".to_string();
1081
1082        // For security requires {:allow; in some cases.
1083        if self.src.contains(BIF_OPEN) {
1084            if !self.contains_allow(&self.src) {
1085                self.out = EMPTY_STRING;
1086
1087                return Err(BifError {
1088                    code: 103,
1089                    msg: "insecure varname".to_string(),
1090                    name: self.alias.clone(),
1091                    src: self.src.clone(),
1092                });
1093            }
1094
1095            let var_name = &new_child_parse!(self, &self.src, self.mod_scope);
1096            self.out = self.get_data(var_name).to_string();
1097
1098            return Ok(());
1099        }
1100
1101        let var_name = &self.src;
1102
1103        if (self.mod_filter || self.shared.filter_all || var_name.starts_with("CONTEXT->")) && !self.mod_negate {
1104            // Prevent double encoding
1105            self.out = unescape_chars(&self.get_data(var_name), true).to_string();
1106            self.out = escape_chars(&self.out, true).to_string();
1107        } else {
1108            self.out = self.get_data(var_name).to_string();
1109        }
1110
1111        Ok(())
1112    }
1113
1114    /*
1115        {:allow; {:flg; partial casein replace :} name >> ... :}
1116    */
1117    fn parse_bif_allow(&mut self) -> Result<(), BifError> {
1118        if self.mod_filter || self.mod_scope {
1119            return Err(BifError {
1120                code: 104,
1121                msg: "modifier not allowed".to_string(),
1122                name: self.alias.clone(),
1123                src: self.raw.to_string(),
1124            });
1125        }
1126
1127        self.extract_params_code(true);
1128        let mut found = String::new();
1129        let words_string = get_from_key(
1130            &self.shared.schema["__indir"][&self.inherit.indir]["declare"],
1131            &self.params,
1132        );
1133
1134        if words_string.is_empty() {
1135            return Err(BifError {
1136                code: 105,
1137                msg: self.params.clone() + " declared is empty",
1138                name: self.alias.clone(),
1139                src: self.raw.to_string(),
1140            });
1141        }
1142
1143        let mut words_list: Vec<&str> = words_string.split_whitespace().collect();
1144        self.code = new_child_parse!(self, &self.code, self.mod_scope);
1145
1146        for word in &mut words_list {
1147            let lower_haystack;
1148            let mut haystack = &self.code;
1149            let mut pattern = word.to_string().clone();
1150
1151            if self.flags.contains("|partial|") || self.flags.contains("|replace|") {
1152                pattern = format!("{}{}{}", "*", pattern, "*");
1153            }
1154
1155            if self.flags.contains("|casein|") {
1156                pattern = pattern.to_lowercase();
1157                lower_haystack = self.code.clone().to_lowercase();
1158                haystack = &lower_haystack;
1159            }
1160
1161            if wildcard_match(haystack, &pattern) {
1162                found = word.to_string();
1163                break;
1164            }
1165        }
1166
1167        if !found.is_empty() ^ self.mod_negate {
1168            if self.flags.contains("|replace|") {
1169                found = found.replace("~", "");
1170                found = found.replace("*", "");
1171                found = found.replace("?", "");
1172                found = found.replace(".", "");
1173                self.out = found.to_string();
1174            } else {
1175                self.out = self.code.to_string();
1176            }
1177        } else {
1178            self.out = EMPTY_STRING;
1179        }
1180
1181        Ok(())
1182    }
1183
1184    /*
1185        {:array; varname >> ... :}
1186    */
1187    fn parse_bif_array(&mut self) -> Result<(), BifError> {
1188        if self.mod_filter {
1189            return Err(BifError {
1190                code: 106,
1191                msg: "modifier not allowed".to_string(),
1192                name: self.alias.clone(),
1193                src: self.raw.to_string(),
1194            });
1195        }
1196
1197        self.extract_params_code(true);
1198
1199        let mut varname = self.params.as_str();
1200        let mut schema = &self.shared.schema["data"];
1201
1202        if varname.starts_with("local::") {
1203            schema = &self.shared.schema["__indir"][&self.inherit.indir]["data"];
1204            varname = varname.strip_prefix("local::").unwrap_or(varname);
1205        }
1206
1207        if is_array_key(schema, varname) ^ self.mod_negate {
1208            if self.code.contains(BIF_OPEN) {
1209                self.code = new_child_parse!(self, &self.code, self.mod_scope);
1210            }
1211            self.out = self.code.to_string();
1212        }
1213
1214        Ok(())
1215    }
1216
1217    /*
1218        {:bool; varname >> ... :}
1219    */
1220    fn parse_bif_bool(&mut self) -> Result<(), BifError> {
1221        if self.mod_filter {
1222            return Err(BifError {
1223                code: 107,
1224                msg: "modifier not allowed".to_string(),
1225                name: self.alias.clone(),
1226                src: self.raw.to_string(),
1227            });
1228        }
1229
1230        self.extract_params_code(true);
1231
1232        let mut varname = self.params.as_str();
1233        let mut schema = &self.shared.schema["data"];
1234
1235        if varname.starts_with("local::") {
1236            schema = &self.shared.schema["__indir"][&self.inherit.indir]["data"];
1237            varname = varname.strip_prefix("local::").unwrap_or(varname);
1238        }
1239
1240        if is_bool_key(schema, varname) ^ self.mod_negate {
1241            if self.code.contains(BIF_OPEN) {
1242                self.code = new_child_parse!(self, &self.code, self.mod_scope);
1243            }
1244            self.out = self.code.to_string();
1245        }
1246
1247        Ok(())
1248    }
1249
1250    /*
1251       {:coalesce;
1252           {:code;  :}
1253           {:code; this is output :}
1254           {:code; ... :}
1255       :}
1256    */
1257    fn parse_bif_coalesce(&mut self) -> Result<(), BifError> {
1258        if self.mod_filter || self.mod_negate {
1259            return Err(BifError {
1260                code: 108,
1261                msg: "modifier not allowed".to_string(),
1262                name: self.alias.clone(),
1263                src: self.raw.to_string(),
1264            });
1265        }
1266
1267        // This var so as not to overwrite the original: inherit.last_bif_out
1268        self.inherit.last_coalesce_out = false;
1269        self.out = new_child_parse!(self, &self.src, self.mod_scope);
1270
1271        Ok(())
1272    }
1273
1274    /*
1275        {:code; ...  :}
1276        {:code; {:flags; safe noparse encode_tags encode_tags_after encode_bifs :} >>  <div>...</div>  :}
1277    */
1278    fn parse_bif_code(&mut self) -> Result<(), BifError> {
1279        if self.mod_filter || self.mod_negate {
1280            return Err(BifError {
1281                code: 109,
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        if self.flags.contains("|safe|") {
1291            self.code = escape_chars(&unescape_chars(&self.code, false), false).to_string();
1292            self.code = self.code.replace(BIF_OPEN, BIF_SANITIZE_OPEN);
1293            self.code = self.code.replace(BIF_CLOSE, BIF_SANITIZE_CLOSE);
1294        } else {
1295            if self.flags.contains("|encode_tags|") {
1296                self.code = escape_chars(&unescape_chars(&self.code, false), false).to_string();
1297            }
1298
1299            if self.flags.contains("|encode_bifs|") {
1300                self.code = self.code.replace(BIF_OPEN, BIF_SANITIZE_OPEN);
1301                self.code = self.code.replace(BIF_CLOSE, BIF_SANITIZE_CLOSE);
1302            }
1303
1304            if !self.flags.contains("|noparse|") && self.code.contains(BIF_OPEN) {
1305                self.code = new_child_parse!(self, &self.code, self.mod_scope);
1306            }
1307        }
1308
1309        if self.flags.contains("|encode_tags_after|") {
1310            self.code = escape_chars(&unescape_chars(&self.code, false), false).to_string();
1311        }
1312
1313        self.out = self.code.to_string();
1314
1315        Ok(())
1316    }
1317
1318    /*
1319        {:count; name >> 0 :}
1320        {:count; name :}
1321    */
1322    fn parse_bif_count(&mut self) -> Result<(), BifError> {
1323        if self.mod_filter || self.mod_negate || self.mod_scope {
1324            return Err(BifError {
1325                code: 110,
1326                msg: "modifier not allowed".to_string(),
1327                name: self.alias.clone(),
1328                src: self.raw.to_string(),
1329            });
1330        }
1331
1332        let is_set = self.extract_params_code(true);
1333
1334        if self.code.contains(BIF_OPEN) {
1335            self.code = new_child_parse!(self, &self.code, self.mod_scope);
1336        }
1337
1338        if is_set {
1339            let count_name = self.params.clone();
1340            let count_value = match self.code.parse::<i32>() {
1341                Ok(num) => num,
1342                Err(_) => {
1343                    return Err(BifError {
1344                        code: 111,
1345                        msg: "argument is not a number".to_string(),
1346                        name: self.alias.clone(),
1347                        src: self.raw.to_string(),
1348                    });
1349                }
1350            };
1351
1352            self.set_data(&count_name, &count_value.to_string());
1353            self.out = EMPTY_STRING;
1354        } else {
1355            let count_name = self.code.clone();
1356            let count_value = match self.get_data(&count_name).parse::<i32>() {
1357                Ok(num) => num,
1358                Err(_) => {
1359                    return Err(BifError {
1360                        code: 112,
1361                        msg: "argument is not a number".to_string(),
1362                        name: self.alias.clone(),
1363                        src: self.raw.to_string(),
1364                    });
1365                }
1366            };
1367            let new_value = count_value + 1;
1368
1369            self.set_data(&count_name, &new_value.to_string());
1370            self.out = count_value.to_string();
1371        }
1372
1373        Ok(())
1374    }
1375
1376    /*
1377        {:data; file-path :} {:* local data *}
1378    */
1379    fn parse_bif_data(&mut self) -> Result<(), BifError> {
1380        if self.mod_filter || self.mod_scope {
1381            return Err(BifError {
1382                code: 113,
1383                msg: "modifier not allowed".to_string(),
1384                name: self.alias.clone(),
1385                src: self.raw.to_string(),
1386            });
1387        }
1388
1389        self.extract_params_code(true);
1390
1391        if self.flags.contains("|inline|") {
1392            let data: Value = match serde_json::from_str(&self.code) {
1393                Ok(value) => value,
1394                Err(_) => {
1395                    return Err(BifError {
1396                        code: 116,
1397                        msg: "not a valid JSON file".to_string(),
1398                        name: self.alias.clone(),
1399                        src: self.raw.to_string(),
1400                    })
1401                }
1402            };
1403
1404            let indir = &self.inherit.create_block_schema(self.shared);
1405
1406            // Merge new locale data in curren local data.
1407            merge_schema(
1408                &mut self.shared.schema["__indir"][indir]["data"],
1409                &data["data"],
1410            );
1411
1412            self.out = UNPRINTABLE.to_string();
1413
1414            return Ok(());
1415        }
1416
1417        self.file_path = self.code.clone();
1418
1419        // For security requires {:allow;
1420        if self.file_path.contains(BIF_OPEN) {
1421            if !self.contains_allow(&self.file_path) {
1422                return Err(BifError {
1423                    code: 114,
1424                    msg: "insecure file name".to_string(),
1425                    name: self.alias.clone(),
1426                    src: self.raw.to_string(),
1427                });
1428            }
1429            self.file_path = new_child_parse!(self, &self.code, false);
1430        }
1431
1432        if self.file_path.starts_with("#") {
1433            self.file_path.remove(0);
1434            self.file_path = format!("{}{}", self.inherit.current_dir, self.file_path);
1435        }
1436
1437        let path = Path::new(&self.file_path);
1438        if !Path::new(path).exists() {
1439            if self.flags.contains("|require|") {
1440                return Err(BifError {
1441                    code: 115,
1442                    msg: "file not found".to_string(),
1443                    name: self.alias.clone(),
1444                    src: self.raw.to_string(),
1445                });
1446            } else {
1447                self.out = EMPTY_STRING;
1448
1449                return Ok(());
1450            }
1451        }
1452
1453        let canonical_path = fs::canonicalize(path)
1454            .unwrap()
1455            .to_string_lossy()
1456            .into_owned();
1457
1458        if self.mod_negate && self.inherit.data_files.contains(&canonical_path) {
1459            self.out = UNPRINTABLE.to_string();
1460
1461            return Ok(());
1462        }
1463
1464        self.inherit.data_files.push(canonical_path);
1465        let file_raw = fs::read_to_string(&self.file_path).unwrap_or("".to_string());
1466
1467        let data: Value = match serde_json::from_str(&file_raw) {
1468            Ok(value) => value,
1469            Err(_) => {
1470                return Err(BifError {
1471                    code: 116,
1472                    msg: "not a valid JSON file".to_string(),
1473                    name: self.alias.clone(),
1474                    src: self.raw.to_string(),
1475                })
1476            }
1477        };
1478
1479        let indir = &self.inherit.create_block_schema(self.shared);
1480
1481        // Merge new locale data in curren local data.
1482        merge_schema(
1483            &mut self.shared.schema["__indir"][indir]["data"],
1484            &data["data"],
1485        );
1486
1487        self.out = UNPRINTABLE.to_string();
1488
1489        Ok(())
1490    }
1491
1492    /*
1493        {:date;  :} timestamp
1494        {:date; %Y-%m-%d %H:%M:%S  :} UTC
1495    */
1496    fn parse_bif_date(&mut self) -> Result<(), BifError> {
1497        if self.mod_filter || self.mod_negate || self.mod_scope {
1498            return Err(BifError {
1499                code: 117,
1500                msg: "modifier not allowed".to_string(),
1501                name: self.alias.clone(),
1502                src: self.raw.to_string(),
1503            });
1504        }
1505
1506        self.extract_params_code(true);
1507
1508        let now = Utc::now();
1509
1510        if self.src.contains(BIF_OPEN) {
1511            self.code = new_child_parse!(self, &self.code, self.mod_scope);
1512        } else {
1513            self.code = self.src.trim().to_string();
1514        }
1515
1516        if self.code.is_empty() {
1517            self.out = now.timestamp().to_string();
1518        } else {
1519            self.out = now.format(&self.src).to_string();
1520        }
1521
1522        Ok(())
1523    }
1524
1525    /*
1526        {:declare; name >> words list :}
1527    */
1528    fn parse_bif_declare(&mut self) -> Result<(), BifError> {
1529        if self.mod_filter || self.mod_negate || self.mod_scope {
1530            return Err(BifError {
1531                code: 118,
1532                msg: "modifier not allowed".to_string(),
1533                name: self.alias.clone(),
1534                src: self.raw.to_string(),
1535            });
1536        }
1537
1538        self.extract_params_code(true);
1539
1540        if self.inherit.current_file.contains(SNIPPETS_FILES) {
1541            self.inherit.create_block_schema(self.shared);
1542            if self.code.contains(BIF_OPEN) {
1543                self.code = new_child_parse!(self, &self.code, false);
1544                self.code = self.code.replace(UNPRINTABLE, "");
1545            }
1546            self.shared.schema["__indir"][&self.inherit.indir]["declare"][&self.params] =
1547                json!(&self.code);
1548
1549            self.out = EMPTY_STRING;
1550        } else {
1551            return Err(BifError {
1552                code: 119,
1553                msg: "declare cannot be set here".to_string(),
1554                name: self.alias.clone(),
1555                src: self.raw.to_string(),
1556            });
1557        }
1558
1559        Ok(())
1560    }
1561
1562    /*
1563        {:defined; varname >> ... :}
1564    */
1565    fn parse_bif_defined(&mut self) -> Result<(), BifError> {
1566        if self.mod_filter {
1567            return Err(BifError {
1568                code: 120,
1569                msg: "modifier not allowed".to_string(),
1570                name: self.alias.clone(),
1571                src: self.raw.to_string(),
1572            });
1573        }
1574
1575        self.extract_params_code(true);
1576
1577        let mut varname = self.params.as_str();
1578        let mut schema = &self.shared.schema["data"];
1579
1580        if varname.starts_with("local::") {
1581            schema = &self.shared.schema["__indir"][&self.inherit.indir]["data"];
1582            varname = varname.strip_prefix("local::").unwrap_or(varname);
1583        }
1584
1585        if is_defined_key(schema, varname) ^ self.mod_negate {
1586            if self.code.contains(BIF_OPEN) {
1587                self.code = new_child_parse!(self, &self.code, self.mod_scope);
1588            }
1589            self.out = self.code.to_string();
1590        }
1591
1592        Ok(())
1593    }
1594
1595    /*
1596        {:each; array-name name-for-key name-for-value  >>
1597            {:;name-for-key:}={:;name-for-value:}
1598        :}
1599    */
1600    fn parse_bif_each(&mut self) -> Result<(), BifError> {
1601        if self.mod_filter || self.mod_negate || self.mod_scope {
1602            return Err(BifError {
1603                code: 121,
1604                msg: "modifier not allowed".to_string(),
1605                name: self.alias.clone(),
1606                src: self.raw.to_string(),
1607            });
1608        }
1609
1610        self.extract_params_code(true);
1611        let mut parts = self.params.split_whitespace();
1612
1613        let array_name = match parts.next() {
1614            Some(value) => value.to_string(),
1615            None => {
1616                return Err(BifError {
1617                    code: 122,
1618                    msg: "arguments not found".to_string(),
1619                    name: self.alias.clone(),
1620                    src: self.raw.to_string(),
1621                })
1622            }
1623        };
1624
1625        let key_name = match parts.next() {
1626            Some(value) => value.to_string(),
1627            None => {
1628                return Err(BifError {
1629                    code: 123,
1630                    msg: "arguments 'key' not found".to_string(),
1631                    name: self.alias.clone(),
1632                    src: self.raw.to_string(),
1633                })
1634            }
1635        };
1636
1637        let val_name = match parts.next() {
1638            Some(value) => value.to_string(),
1639            None => {
1640                return Err(BifError {
1641                    code: 124,
1642                    msg: "arguments 'value' not found".to_string(),
1643                    name: self.alias.clone(),
1644                    src: self.raw.to_string(),
1645                })
1646            }
1647        };
1648
1649        let tmp: String = format!("{}{}", "/", array_name);
1650        let mut array = tmp.replace(BIF_ARRAY, "/");
1651        let restore_key = self.get_data(&key_name);
1652        let restore_val = self.get_data(&val_name);
1653
1654        let data_storage;
1655        if array.starts_with("/local::") {
1656            array = array.replace("/local::", "/");
1657            data_storage = &self.shared.schema["__indir"][&self.inherit.indir]["data"];
1658        } else {
1659            data_storage = &self.shared.schema["data"];
1660        }
1661
1662        if let Some(data_value) = data_storage.pointer(&array) {
1663            match data_value.to_owned() {
1664                Value::Object(obj) => {
1665                    for (key, val) in obj.iter() {
1666                        self.parse_bif_each_iter(&key_name, &val_name, key, val);
1667                    }
1668                }
1669                Value::Array(arr) => {
1670                    for (key, val) in arr.iter().enumerate() {
1671                        self.parse_bif_each_iter(&key_name, &val_name, &key.to_string(), val);
1672                    }
1673                }
1674                _ => {}
1675            }
1676        }
1677
1678        self.set_data(&key_name, &restore_key);
1679        self.set_data(&val_name, &restore_val);
1680
1681        Ok(())
1682    }
1683
1684    fn parse_bif_each_iter(&mut self, key_name: &str, val_name: &str, key: &String, val: &Value) {
1685        self.shared.schema["data"][key_name] = json!(key);
1686        self.shared.schema["data"][val_name] = json!(val);
1687        self.out += &new_child_parse!(self, &self.code, false);
1688    }
1689
1690    /*
1691       {:else; ... :}
1692       {:code; :}{:else; this is output :}
1693       {:code; not empty :}{:!else; this is output :}
1694    */
1695    fn parse_bif_else(&mut self) -> Result<(), BifError> {
1696        if self.mod_filter {
1697            return Err(BifError {
1698                code: 125,
1699                msg: "modifier not allowed".to_string(),
1700                name: self.alias.clone(),
1701                src: self.raw.to_string(),
1702            });
1703        }
1704
1705        self.extract_params_code(true);
1706
1707        if self.inherit.last_bif_out ^ self.mod_negate {
1708            self.out = EMPTY_STRING;
1709
1710            return Ok(());
1711        }
1712
1713        if self.code.contains(BIF_OPEN) {
1714            self.code = new_child_parse!(self, &self.code, self.mod_scope);
1715        }
1716
1717        self.out = self.code.to_string();
1718
1719        Ok(())
1720    }
1721
1722    /*
1723        {:eval; code >> ... {:;__eval__:} ... :} {:* embbedding *:}
1724    */
1725    fn parse_bif_eval(&mut self) -> Result<(), BifError> {
1726        if self.mod_filter {
1727            return Err(BifError {
1728                code: 126,
1729                msg: "modifier not allowed".to_string(),
1730                name: self.alias.clone(),
1731                src: self.raw.to_string(),
1732            });
1733        }
1734
1735        self.extract_params_code(false);
1736
1737        if self.params.contains(BIF_OPEN) {
1738            self.params = new_child_parse!(self, &self.params, self.mod_scope);
1739        }
1740
1741        if (self.params != EMPTY_STRING) ^ self.mod_negate {
1742            if self.code.contains(BIF_OPEN) {
1743                let restore_eval = self.get_data("__eval__");
1744                self.set_data("__eval__", &self.params.clone());
1745                self.code = new_child_parse!(self, &self.code, self.mod_scope);
1746                self.set_data("__eval__", &restore_eval);
1747            }
1748            self.out = self.code.clone();
1749        } else {
1750            self.out = EMPTY_STRING;
1751        }
1752
1753        Ok(())
1754    }
1755
1756    /*
1757        {:exit; :}
1758        {:exit; 404 :}
1759        {:!exit; 202 :} {:* only sets the status code :}
1760        {:exit; 301 >> /page :}
1761    */
1762    fn parse_bif_exit(&mut self) -> Result<(), BifError> {
1763        if self.mod_filter || self.mod_scope {
1764            return Err(BifError {
1765                code: 127,
1766                msg: "modifier not allowed".to_string(),
1767                name: self.alias.clone(),
1768                src: self.raw.to_string(),
1769            });
1770        }
1771
1772        let has_status_params = self.extract_params_code(true);
1773
1774        if self.code.contains(BIF_OPEN) {
1775            self.code = new_child_parse!(self, &self.src, false);
1776        }
1777
1778        let mut status_code = "200";
1779        let mut status_param = "";
1780
1781        if has_status_params {
1782            if !self.params.is_empty() {
1783                status_code = self.params.as_str();
1784            }
1785            status_param = &self.code;
1786        } else if !self.code.is_empty() {
1787            status_code = self.code.as_str();
1788        }
1789
1790        self.shared.status_code = status_code.to_string();
1791        self.shared.status_param = status_param.to_string();
1792
1793        if let Some(text) = STATUS_CODES.get(status_code) {
1794            self.shared.status_text = text.to_string();
1795        } else {
1796            self.shared.status_text = EMPTY_STRING;
1797        }
1798
1799        self.shared.exit = true ^ self.mod_negate;
1800        self.out = EMPTY_STRING;
1801
1802        Ok(())
1803    }
1804
1805    /*
1806        {:filled; varname >> ... :}
1807
1808        *** It is only not filled if it has nothing "", if it is not defined
1809        or is null, the rest “false”, “0” etc. is something.
1810    */
1811    fn parse_bif_filled(&mut self) -> Result<(), BifError> {
1812        if self.mod_filter {
1813            return Err(BifError {
1814                code: 128,
1815                msg: "modifier not allowed".to_string(),
1816                name: self.alias.clone(),
1817                src: self.raw.to_string(),
1818            });
1819        }
1820
1821        self.extract_params_code(true);
1822
1823        let mut varname = self.params.as_str();
1824        let mut schema = &self.shared.schema["data"];
1825
1826        if varname.starts_with("local::") {
1827            schema = &self.shared.schema["__indir"][&self.inherit.indir]["data"];
1828            varname = varname.strip_prefix("local::").unwrap_or(varname);
1829        }
1830
1831        if !is_empty_key(schema, varname) ^ self.mod_negate {
1832            if self.code.contains(BIF_OPEN) {
1833                self.code = new_child_parse!(self, &self.code, self.mod_scope);
1834            }
1835
1836            self.out = self.code.to_string();
1837        }
1838
1839        Ok(())
1840    }
1841
1842    /*
1843        {:flg; flag-name1 flag-name2 ... :}
1844        {:code; {:flg; safe :} >>  <div>...</div> :}
1845    */
1846    fn parse_bif_flg(&mut self) -> Result<(), BifError> {
1847        if self.mod_filter || self.mod_negate || self.mod_upline || self.mod_scope {
1848            return Err(BifError {
1849                code: 129,
1850                msg: "modifier not allowed".to_string(),
1851                name: self.alias.clone(),
1852                src: self.raw.to_string(),
1853            });
1854        }
1855
1856        self.extract_params_code(true);
1857
1858        if self.code.contains(BIF_OPEN) {
1859            self.code = new_child_parse!(self, &self.code, false);
1860        }
1861
1862        let flags = format!(" {} ", self.code);
1863        self.shared.flags = flags.replace(" ", "|");
1864        self.out = EMPTY_STRING;
1865
1866        Ok(())
1867    }
1868
1869    /*
1870       {:for; varname 1 10 >>
1871           var is:{:;varname:}
1872       :}
1873    */
1874    fn parse_bif_for(&mut self) -> Result<(), BifError> {
1875        if self.mod_filter || self.mod_negate || self.mod_scope {
1876            return Err(BifError {
1877                code: 130,
1878                msg: "modifier not allowed".to_string(),
1879                name: self.alias.clone(),
1880                src: self.raw.to_string(),
1881            });
1882        }
1883
1884        self.extract_params_code(true);
1885        self.params = self.params.replace("..", " ");
1886        let mut parts = self.params.split_whitespace();
1887
1888        let var_name = match parts.next() {
1889            Some(value) => value.to_string(),
1890            None => {
1891                return Err(BifError {
1892                    code: 131,
1893                    msg: "arguments not found".to_string(),
1894                    name: self.alias.clone(),
1895                    src: self.raw.to_string(),
1896                })
1897            }
1898        };
1899
1900        let from = match parts.next() {
1901            Some(value) => match value.parse::<i32>() {
1902                Ok(num) => num,
1903                Err(_) => {
1904                    return Err(BifError {
1905                        code: 132,
1906                        msg: "argument is not a number".to_string(),
1907                        name: self.alias.clone(),
1908                        src: self.raw.to_string(),
1909                    })
1910                }
1911            },
1912            None => {
1913                return Err(BifError {
1914                    code: 133,
1915                    msg: "arguments 'from' and 'to' not found".to_string(),
1916                    name: self.alias.clone(),
1917                    src: self.raw.to_string(),
1918                })
1919            }
1920        };
1921
1922        let to = match parts.next() {
1923            Some(value) => match value.parse::<i32>() {
1924                Ok(num) => num,
1925                Err(_) => {
1926                    return Err(BifError {
1927                        code: 134,
1928                        msg: "argument is not a number".to_string(),
1929                        name: self.alias.clone(),
1930                        src: self.raw.to_string(),
1931                    })
1932                }
1933            },
1934            None => {
1935                return Err(BifError {
1936                    code: 135,
1937                    msg: "arguments 'to' not found".to_string(),
1938                    name: self.alias.clone(),
1939                    src: self.raw.to_string(),
1940                })
1941            }
1942        };
1943
1944        let range = if from > to {
1945            (to..=from).rev().collect::<Vec<i32>>()
1946        } else {
1947            (from..=to).collect::<Vec<i32>>()
1948        };
1949
1950        let restore_var = self.get_data(&var_name);
1951        for i in range {
1952            self.set_data(&var_name, &i.to_string());
1953            self.out += &new_child_parse!(self, &self.code, self.mod_scope);
1954        }
1955        self.set_data(&var_name, &restore_var);
1956
1957        Ok(())
1958    }
1959
1960    /*
1961        {:hash;  :}
1962        {:hash; text :}
1963    */
1964    fn parse_bif_hash(&mut self) -> Result<(), BifError> {
1965        if self.mod_filter || self.mod_negate || self.mod_scope {
1966            return Err(BifError {
1967                code: 136,
1968                msg: "modifier not allowed".to_string(),
1969                name: self.alias.clone(),
1970                src: self.raw.to_string(),
1971            });
1972        }
1973
1974        self.code = self.src.trim().to_string();
1975
1976        if self.src.contains(BIF_OPEN) {
1977            self.code = new_child_parse!(self, &self.code, self.mod_scope);
1978        } else {
1979            self.code = self.code.trim().to_string();
1980        }
1981
1982        if self.code.is_empty() {
1983            let mut hasher = Md5::new();
1984            let mut rng = rand::rng();
1985            let rand = rng.random_range(100000000..=999999999).to_string();
1986            hasher.update(&rand);
1987            self.out = format!("{:x}", hasher.finalize())
1988        } else {
1989            let mut hasher = Md5::new();
1990            hasher.update(&self.code);
1991            self.out = format!("{:x}", hasher.finalize());
1992        }
1993
1994        Ok(())
1995    }
1996
1997    /*
1998        {:include; file-path :}
1999        {:include; {:flg; require safe noparse :} >> file-path :}
2000    */
2001    fn parse_bif_include(&mut self) -> Result<(), BifError> {
2002        if self.mod_filter || self.mod_scope {
2003            return Err(BifError {
2004                code: 137,
2005                msg: "modifier not allowed".to_string(),
2006                name: self.alias.clone(),
2007                src: self.raw.to_string(),
2008            });
2009        }
2010
2011        self.extract_params_code(true);
2012        self.file_path = self.code.clone();
2013
2014        // For security requires {:allow;
2015        if self.file_path.contains(BIF_OPEN) {
2016            if !self.contains_allow(&self.file_path) {
2017                return Err(BifError {
2018                    code: 138,
2019                    msg: "insecure file name".to_string(),
2020                    name: self.alias.clone(),
2021                    src: self.raw.to_string(),
2022                });
2023            }
2024            self.file_path = new_child_parse!(self, &self.code, false);
2025        }
2026
2027        if self.file_path.starts_with("#") {
2028            self.file_path.remove(0);
2029            self.file_path = format!("{}{}", self.inherit.current_dir, self.file_path);
2030        }
2031
2032        let path = Path::new(&self.file_path);
2033        if !path.exists() {
2034            if self.flags.contains("|require|") {
2035                return Err(BifError {
2036                    code: 139,
2037                    msg: "file not found".to_string(),
2038                    name: self.alias.clone(),
2039                    src: self.raw.to_string(),
2040                });
2041            } else {
2042                return Ok(());
2043            }
2044        }
2045
2046        if let Some(parent) = path.parent() {
2047            self.dir = parent.display().to_string();
2048        }
2049
2050        let canonical_path = fs::canonicalize(path)
2051            .unwrap()
2052            .to_string_lossy()
2053            .into_owned();
2054
2055        if self.mod_negate && self.inherit.include_files.contains(&canonical_path) {
2056            self.out = EMPTY_STRING;
2057
2058            return Ok(());
2059        }
2060
2061        if self.flags.contains("|safe|") {
2062            self.code = fs::read_to_string(&self.file_path).unwrap_or("".to_string());
2063            self.code = escape_chars(&unescape_chars(&self.code, false), false).to_string();
2064            self.code = self.code.replace(BIF_OPEN, BIF_SANITIZE_OPEN);
2065            self.code = self.code.replace(BIF_CLOSE, BIF_SANITIZE_CLOSE);
2066            self.out = self.code.clone();
2067
2068            return Ok(());
2069        }
2070
2071        if self.flags.contains("|noparse|") {
2072            self.code = fs::read_to_string(&self.file_path).unwrap_or("".to_string());
2073            self.out = self.code.clone();
2074
2075            return Ok(());
2076        }
2077
2078        self.inherit.include_files.push(canonical_path);
2079
2080        let mut file_raw = fs::read_to_string(&self.file_path).unwrap_or("".to_string());
2081        if self.shared.comments.contains("remove") {
2082            file_raw = remove_comments(&file_raw);
2083        }
2084
2085        self.out = new_child_parse!(self, &file_raw, true);
2086
2087        Ok(())
2088    }
2089
2090    /*
2091       {:lang; ... :}
2092    */
2093    fn parse_bif_lang(&mut self) -> Result<(), BifError> {
2094        if self.mod_filter || self.mod_negate || self.mod_scope {
2095            return Err(BifError {
2096                code: 140,
2097                msg: "modifier not allowed".to_string(),
2098                name: self.alias.clone(),
2099                src: self.raw.to_string(),
2100            });
2101        }
2102
2103        self.out = self.shared.lang.to_string();
2104
2105        Ok(())
2106    }
2107
2108    /*
2109        {:locale; file-path :}
2110    */
2111    fn parse_bif_locale(&mut self) -> Result<(), BifError> {
2112        if self.mod_filter || self.mod_scope {
2113            return Err(BifError {
2114                code: 141,
2115                msg: "modifier not allowed".to_string(),
2116                name: self.alias.clone(),
2117                src: self.raw.to_string(),
2118            });
2119        }
2120
2121        self.extract_params_code(true);
2122
2123        if self.flags.contains("|inline|") {
2124            // Parse possible bifs included in json
2125            if self.code.contains(BIF_OPEN) {
2126                self.code = new_child_parse!(self, &self.code, false);
2127            }
2128
2129            let locale: Value = match serde_json::from_str(&self.code) {
2130                Ok(value) => value,
2131                Err(_) => {
2132                    return Err(BifError {
2133                        code: 142,
2134                        msg: "not a valid JSON string".to_string(),
2135                        name: self.alias.clone(),
2136                        src: self.raw.to_string(),
2137                    })
2138                }
2139            };
2140
2141            let indir = &self.inherit.create_block_schema(self.shared);
2142
2143            // Merge new locale data in curren locale.
2144            merge_schema(&mut self.shared.schema["__indir"][indir]["locale"], &locale);
2145
2146            self.out = EMPTY_STRING;
2147
2148            return Ok(());
2149        }
2150
2151        self.file_path = self.code.clone();
2152
2153        // For security requires {:allow;
2154        if self.file_path.contains(BIF_OPEN) {
2155            if !self.contains_allow(&self.file_path) {
2156                return Err(BifError {
2157                    code: 143,
2158                    msg: "insecure file name".to_string(),
2159                    name: self.alias.clone(),
2160                    src: self.raw.to_string(),
2161                });
2162            }
2163            self.file_path = new_child_parse!(self, &self.code, false);
2164        }
2165
2166        if self.file_path.starts_with("#") {
2167            self.file_path.remove(0);
2168            self.file_path = format!("{}{}", self.inherit.current_dir, self.file_path);
2169        }
2170
2171        let path = Path::new(&self.file_path);
2172        if !Path::new(path).exists() {
2173            if self.flags.contains("|require|") {
2174                return Err(BifError {
2175                    code: 144,
2176                    msg: "file not found".to_string(),
2177                    name: self.alias.clone(),
2178                    src: self.raw.to_string(),
2179                });
2180            } else {
2181                return Ok(());
2182            }
2183        }
2184
2185        let canonical_path = fs::canonicalize(path)
2186            .unwrap()
2187            .to_string_lossy()
2188            .into_owned();
2189        if self.mod_negate && self.inherit.locale_files.contains(&canonical_path) {
2190            self.out = UNPRINTABLE.to_string();
2191
2192            return Ok(());
2193        }
2194
2195        self.inherit.locale_files.push(canonical_path);
2196        let mut file_raw = fs::read_to_string(&self.file_path).unwrap_or("".to_string());
2197
2198        if !self.flags.contains("|noparse|") {
2199            // Parse possible bifs included in json
2200            if file_raw.contains(BIF_OPEN) {
2201                file_raw = new_child_parse!(self, &file_raw, false);
2202            }
2203        }
2204
2205        let locale: Value = match serde_json::from_str(&file_raw) {
2206            Ok(value) => value,
2207            Err(_) => {
2208                return Err(BifError {
2209                    code: 145,
2210                    msg: "not a valid JSON file".to_string(),
2211                    name: self.alias.clone(),
2212                    src: self.raw.to_string(),
2213                })
2214            }
2215        };
2216
2217        let indir = &self.inherit.create_block_schema(self.shared);
2218
2219        // Merge new locale data in curren locale.
2220        merge_schema(&mut self.shared.schema["__indir"][indir]["locale"], &locale);
2221
2222        self.out = UNPRINTABLE.to_string();
2223
2224        Ok(())
2225    }
2226
2227    /*
2228        {:moveto; <tag >> ... :}
2229        {:moveto; </tag >> ... :}
2230    */
2231    fn parse_bif_moveto(&mut self) -> Result<(), BifError> {
2232        if self.mod_filter || self.mod_negate || self.mod_scope {
2233            return Err(BifError {
2234                code: 146,
2235                msg: "modifier not allowed".to_string(),
2236                name: self.alias.clone(),
2237                src: self.raw.to_string(),
2238            });
2239        }
2240
2241        self.extract_params_code(true);
2242        let mut moveto = json!({});
2243        let mut hasher = Md5::new();
2244
2245        if self.code.contains(BIF_OPEN) {
2246            self.code = new_child_parse!(self, &self.code, self.mod_scope);
2247        }
2248
2249        // the same code moves only once
2250        hasher.update(&self.code);
2251        let code_hash = hasher.finalize();
2252        let code_hash = format!("{:x}", code_hash);
2253
2254        moveto[&self.params] = json!(&self.code);
2255        self.shared.schema["__moveto"][&code_hash] = moveto;
2256        self.out = EMPTY_STRING;
2257
2258        Ok(())
2259    }
2260
2261    /*
2262        {:neutral; ... :}
2263    */
2264    fn parse_bif_neutral(&mut self) -> Result<(), BifError> {
2265        if self.mod_filter || self.mod_negate || self.mod_scope {
2266            return Err(BifError {
2267                code: 147,
2268                msg: "modifier not allowed".to_string(),
2269                name: self.alias.clone(),
2270                src: self.raw.to_string(),
2271            });
2272        }
2273
2274        self.out = format!(
2275            "{}{}{}{}{}",
2276            BIF_OPEN, self.name, BIF_NAME, self.src, BIF_CLOSE
2277        );
2278
2279        Ok(())
2280    }
2281
2282    /*
2283        Play param: {:param; param-name :}
2284        Set param:  {:param; param-name >> content to set :}
2285    */
2286    fn parse_bif_param(&mut self) -> Result<(), BifError> {
2287        if self.mod_filter || self.mod_negate || self.mod_scope {
2288            return Err(BifError {
2289                code: 148,
2290                msg: "modifier not allowed".to_string(),
2291                name: self.alias.clone(),
2292                src: self.raw.to_string(),
2293            });
2294        }
2295
2296        let is_set = self.extract_params_code(true);
2297        if is_set {
2298            if self.inherit.alias == "code" {
2299                if self.code.contains(BIF_OPEN) {
2300                    self.code = new_child_parse!(self, &self.code, self.mod_scope);
2301                }
2302
2303                self.inherit.create_block_schema(self.shared);
2304                self.shared.schema["__indir"][&self.inherit.indir]["params"][&self.params] =
2305                    json!(&self.code);
2306                self.out = EMPTY_STRING;
2307
2308                Ok(())
2309            } else {
2310                Err(BifError {
2311                    code: 149,
2312                    msg: "param cannot be set here".to_string(),
2313                    name: self.alias.clone(),
2314                    src: self.raw.to_string(),
2315                })
2316            }
2317        } else {
2318            if self.code.contains(BIF_OPEN) {
2319                self.code = new_child_parse!(self, &self.code, self.mod_scope);
2320            }
2321
2322            self.code = get_from_key(
2323                &self.shared.schema["__indir"][&self.inherit.indir]["params"],
2324                &self.code,
2325            );
2326            self.out = self.code.to_string();
2327
2328            Ok(())
2329        }
2330    }
2331
2332    /*
2333        {:rand;  :}
2334        {:rand; 1..100 :}
2335    */
2336    fn parse_bif_rand(&mut self) -> Result<(), BifError> {
2337        if self.mod_filter || self.mod_negate || self.mod_scope {
2338            return Err(BifError {
2339                code: 150,
2340                msg: "modifier not allowed".to_string(),
2341                name: self.alias.clone(),
2342                src: self.raw.to_string(),
2343            });
2344        }
2345
2346        let mut rng = rand::rng();
2347        self.code = self.src.trim().to_string();
2348
2349        if self.src.contains(BIF_OPEN) {
2350            self.code = new_child_parse!(self, &self.code, self.mod_scope);
2351        } else {
2352            self.code = self.src.trim().to_string();
2353        }
2354
2355        if self.code.is_empty() {
2356            self.out = rng.random_range(100000000..=999999999).to_string();
2357        } else {
2358            // TODO comprobar rangos
2359            self.code = self.code.replace("..", " ");
2360            let mut parts = self.code.split_whitespace();
2361
2362            let from = match parts.next() {
2363                Some(value) => match value.parse::<i32>() {
2364                    Ok(num) => num,
2365                    Err(_) => {
2366                        return Err(BifError {
2367                            code: 151,
2368                            msg: "argument is not a number".to_string(),
2369                            name: self.alias.clone(),
2370                            src: self.raw.to_string(),
2371                        })
2372                    }
2373                },
2374                None => {
2375                    return Err(BifError {
2376                        code: 152,
2377                        msg: "arguments not found".to_string(),
2378                        name: self.alias.clone(),
2379                        src: self.raw.to_string(),
2380                    })
2381                }
2382            };
2383
2384            let to = match parts.next() {
2385                Some(value) => match value.parse::<i32>() {
2386                    Ok(num) => num,
2387                    Err(_) => {
2388                        return Err(BifError {
2389                            code: 153,
2390                            msg: "argument is not a number".to_string(),
2391                            name: self.alias.clone(),
2392                            src: self.raw.to_string(),
2393                        })
2394                    }
2395                },
2396                None => {
2397                    return Err(BifError {
2398                        code: 154,
2399                        msg: "arguments not found".to_string(),
2400                        name: self.alias.clone(),
2401                        src: self.raw.to_string(),
2402                    })
2403                }
2404            };
2405
2406            if from > to {
2407                return Err(BifError {
2408                    code: 155,
2409                    msg: "from > to".to_string(),
2410                    name: self.alias.clone(),
2411                    src: self.raw.to_string(),
2412                });
2413            }
2414
2415            self.out = rng.random_range(from..=to).to_string();
2416        }
2417
2418        Ok(())
2419    }
2420
2421    /*
2422        {:redirect; 301 >> /page :}
2423        {:redirect; js:reload:top >> (none) :}
2424    */
2425    fn parse_bif_redirect(&mut self) -> Result<(), BifError> {
2426        if self.mod_filter || self.mod_scope || self.mod_negate {
2427            return Err(BifError {
2428                code: 156,
2429                msg: "modifier not allowed".to_string(),
2430                name: self.alias.clone(),
2431                src: self.raw.to_string(),
2432            });
2433        }
2434
2435        let status_code;
2436        let has_status_params = self.extract_params_code(true);
2437
2438        if self.code.contains(BIF_OPEN) {
2439            self.code = new_child_parse!(self, &self.src, false);
2440        }
2441
2442        if has_status_params {
2443            // When parameters are required or optional in BIF
2444            status_code = match self.params.as_str() {
2445                "301" => {
2446                    if self.code.is_empty() {
2447                        return Err(BifError {
2448                            code: 157,
2449                            msg: "this redirection requires URL".to_string(),
2450                            name: self.alias.clone(),
2451                            src: self.raw.to_string(),
2452                        });
2453                    }
2454
2455                    "301"
2456                }
2457                "302" => {
2458                    if self.code.is_empty() {
2459                        return Err(BifError {
2460                            code: 158,
2461                            msg: "this redirection requires URL".to_string(),
2462                            name: self.alias.clone(),
2463                            src: self.raw.to_string(),
2464                        });
2465                    }
2466
2467                    "302"
2468                }
2469                "303" => {
2470                    if self.code.is_empty() {
2471                        return Err(BifError {
2472                            code: 159,
2473                            msg: "this redirection requires URL".to_string(),
2474                            name: self.alias.clone(),
2475                            src: self.raw.to_string(),
2476                        });
2477                    }
2478
2479                    "303"
2480                }
2481                "307" => {
2482                    if self.code.is_empty() {
2483                        return Err(BifError {
2484                            code: 160,
2485                            msg: "this redirection requires URL".to_string(),
2486                            name: self.alias.clone(),
2487                            src: self.raw.to_string(),
2488                        });
2489                    }
2490
2491                    "307"
2492                }
2493                "308" => {
2494                    if self.code.is_empty() {
2495                        return Err(BifError {
2496                            code: 161,
2497                            msg: "this redirection requires URL".to_string(),
2498                            name: self.alias.clone(),
2499                            src: self.raw.to_string(),
2500                        });
2501                    }
2502
2503                    "308"
2504                }
2505                "js:reload:top" => {
2506                    self.shared.redirect_js = REDIR_JS_RELOAD_TOP.to_string();
2507
2508                    "200"
2509                }
2510                "js:reload:self" => {
2511                    self.shared.redirect_js = REDIR_JS_RELOAD_SELF.to_string();
2512
2513                    "200"
2514                }
2515                "js:redirect:top" => {
2516                    if self.code.is_empty() {
2517                        return Err(BifError {
2518                            code: 162,
2519                            msg: "this redirection requires URL".to_string(),
2520                            name: self.alias.clone(),
2521                            src: self.raw.to_string(),
2522                        });
2523                    }
2524                    // TODO replace(['%2F','%3A','%3F','%3D','%26'], ['/',':','?','=','&'], url);
2525                    self.shared.redirect_js =
2526                        REDIR_JS_REDIRECT_TOP.replace("{}", &self.code).to_string();
2527
2528                    "200"
2529                }
2530                "js:redirect:self" => {
2531                    if self.code.is_empty() {
2532                        return Err(BifError {
2533                            code: 163,
2534                            msg: "this redirection requires URL".to_string(),
2535                            name: self.alias.clone(),
2536                            src: self.raw.to_string(),
2537                        });
2538                    }
2539                    // TODO replace(['%2F','%3A','%3F','%3D','%26'], ['/',':','?','=','&'], url);
2540                    self.shared.redirect_js =
2541                        REDIR_JS_REDIRECT_SELF.replace("{}", &self.code).to_string();
2542
2543                    "200"
2544                }
2545                _ => {
2546                    // Parameters are optional in js:reload:self and js:reload:top
2547                    if !self.code.contains("js:reload:self") || !self.code.contains("js:reload:top")
2548                    {
2549                        return Err(BifError {
2550                            code: 164,
2551                            msg: "status code not allowed".to_string(),
2552                            name: self.alias.clone(),
2553                            src: self.raw.to_string(),
2554                        });
2555                    } else {
2556                        "200"
2557                    }
2558                }
2559            };
2560        } else {
2561            // When parameters are not needed in BIF
2562            status_code = match self.code.as_str() {
2563                "js:reload:top" => {
2564                    self.shared.redirect_js = REDIR_JS_RELOAD_TOP.to_string();
2565
2566                    "200"
2567                }
2568                "js:reload:self" => {
2569                    self.shared.redirect_js = REDIR_JS_RELOAD_SELF.to_string();
2570
2571                    "200"
2572                }
2573                _ => {
2574                    return Err(BifError {
2575                        code: 165,
2576                        msg: "redirect type not allowed".to_string(),
2577                        name: self.alias.clone(),
2578                        src: self.raw.to_string(),
2579                    })
2580                }
2581            };
2582        }
2583
2584        self.shared.status_param = self.code.to_string();
2585        self.shared.status_code = status_code.to_string();
2586
2587        if let Some(text) = STATUS_CODES.get(status_code) {
2588            self.shared.status_text = text.to_string();
2589        } else {
2590            self.shared.status_text = EMPTY_STRING;
2591        }
2592
2593        self.shared.exit = true ^ self.mod_negate;
2594        self.out = EMPTY_STRING;
2595
2596        Ok(())
2597    }
2598
2599    /*
2600        {:replace; /from/to/ >> ... :}
2601        /from/to/, ~from~to~, |from|to|, ...
2602    */
2603    fn parse_bif_replace(&mut self) -> Result<(), BifError> {
2604        if self.mod_filter || self.mod_negate || self.mod_scope {
2605            return Err(BifError {
2606                code: 166,
2607                msg: "modifier not allowed".to_string(),
2608                name: self.alias.clone(),
2609                src: self.raw.to_string(),
2610            });
2611        }
2612
2613        self.extract_params_code(false);
2614
2615        let delim;
2616        if let Some(first_char) = self.params.chars().next() {
2617            delim = first_char;
2618        } else {
2619            return Err(BifError {
2620                code: 167,
2621                msg: "missing arguments".to_string(),
2622                name: self.alias.clone(),
2623                src: self.raw.to_string(),
2624            });
2625        }
2626
2627        let mut parts = self.params.split(delim);
2628
2629        // discard the first
2630        parts.next();
2631
2632        let mut from = match parts.next() {
2633            Some(value) => value.to_string(),
2634            None => {
2635                return Err(BifError {
2636                    code: 168,
2637                    msg: "arguments not found".to_string(),
2638                    name: self.alias.clone(),
2639                    src: self.raw.to_string(),
2640                })
2641            }
2642        };
2643
2644        let mut to = match parts.next() {
2645            Some(value) => value.to_string(),
2646            None => {
2647                return Err(BifError {
2648                    code: 169,
2649                    msg: "arguments not found".to_string(),
2650                    name: self.alias.clone(),
2651                    src: self.raw.to_string(),
2652                })
2653            }
2654        };
2655
2656        if to.contains(BIF_OPEN) {
2657            to = new_child_parse!(self, &to, false);
2658        }
2659
2660        if from.contains(BIF_OPEN) {
2661            from = new_child_parse!(self, &from, false);
2662        }
2663
2664        if self.code.contains(BIF_OPEN) {
2665            self.code = new_child_parse!(self, &self.code, self.mod_scope);
2666        }
2667
2668        self.out = self.code.replace(&from, &to);
2669
2670        Ok(())
2671    }
2672
2673    /*
2674        {:same; /a/b/ >> ... :}
2675    */
2676    fn parse_bif_same(&mut self) -> Result<(), BifError> {
2677        if self.mod_filter {
2678            return Err(BifError {
2679                code: 120,
2680                msg: "modifier not allowed".to_string(),
2681                name: self.alias.clone(),
2682                src: self.raw.to_string(),
2683            });
2684        }
2685
2686        self.extract_params_code(false);
2687
2688        let delim;
2689        if let Some(first_char) = self.params.chars().next() {
2690            delim = first_char;
2691        } else {
2692            return Err(BifError {
2693                code: 173,
2694                msg: "missing arguments".to_string(),
2695                name: self.alias.clone(),
2696                src: self.raw.to_string(),
2697            });
2698        }
2699
2700        let mut parts = self.params.split(delim);
2701
2702        // discard the first
2703        parts.next();
2704
2705        let mut param1 = match parts.next() {
2706            Some(value) => value.to_string(),
2707            None => {
2708                return Err(BifError {
2709                    code: 174,
2710                    msg: "arguments not found".to_string(),
2711                    name: self.alias.clone(),
2712                    src: self.raw.to_string(),
2713                })
2714            }
2715        };
2716
2717        let mut param2 = match parts.next() {
2718            Some(value) => value.to_string(),
2719            None => {
2720                return Err(BifError {
2721                    code: 175,
2722                    msg: "arguments not found".to_string(),
2723                    name: self.alias.clone(),
2724                    src: self.raw.to_string(),
2725                })
2726            }
2727        };
2728
2729        if param1.contains(BIF_OPEN) {
2730            param1 = new_child_parse!(self, &param1, false);
2731        }
2732
2733        if param2.contains(BIF_OPEN) {
2734            param2 = new_child_parse!(self, &param2, false);
2735        }
2736
2737        if (param1 == param2) ^ self.mod_negate  {
2738            if self.code.contains(BIF_OPEN) {
2739                self.code = new_child_parse!(self, &self.code, self.mod_scope);
2740            }
2741            self.out = self.code.to_string();
2742        } else {
2743            self.out = EMPTY_STRING;
2744        }
2745
2746        Ok(())
2747    }
2748
2749    /*
2750        Play snippet:
2751        {:snippet; snippet-name :}
2752
2753        Set snippet:
2754        {:snippet; snippet-name >>
2755            content to set
2756        :}
2757    */
2758    fn parse_bif_snippet(&mut self) -> Result<(), BifError> {
2759        if self.mod_filter || self.mod_negate || self.mod_scope {
2760            return Err(BifError {
2761                code: 170,
2762                msg: "modifier not allowed".to_string(),
2763                name: self.alias.clone(),
2764                src: self.raw.to_string(),
2765            });
2766        }
2767
2768        self.alias = "snippet".to_string();
2769
2770        let is_set = self.extract_params_code(true);
2771        if is_set {
2772            // Set snippets in snippet files and inside snippets
2773            if self.inherit.current_file.contains(SNIPPETS_FILES) || self.inherit.alias == "snippet"
2774            {
2775                if self.flags.contains("|static|") {
2776                    self.code = new_child_parse!(self, &self.code, self.mod_scope);
2777                } else {
2778                    // required regardless of mod_scope or static
2779                    self.inherit.create_block_schema(self.shared);
2780                }
2781                self.shared.schema["__indir"][&self.inherit.indir]["snippets"][&self.params] =
2782                    json!(&self.code);
2783
2784                // The directory inside the snippet is that of the template that created it.
2785                self.shared.schema["__indir"][&self.inherit.indir]["snippets_set_dir"][&self.params] =
2786                    json!(&self.inherit.current_dir);
2787
2788                self.out = EMPTY_STRING;
2789
2790                Ok(())
2791            } else {
2792                Err(BifError {
2793                    code: 171,
2794                    msg: "snippet cannot be set here".to_string(),
2795                    name: self.alias.clone(),
2796                    src: self.raw.to_string(),
2797                })
2798            }
2799        } else {
2800            // parse snippet name if need
2801            if self.code.contains(BIF_OPEN) {
2802                self.code = new_child_parse!(self, &self.code, false);
2803            }
2804            let snip_name = self.code.clone();
2805
2806            self.code = get_from_key(
2807                &self.shared.schema["__indir"][&self.inherit.indir]["snippets"],&self.code,
2808            );
2809
2810            if self.code.contains(BIF_OPEN) {
2811
2812                // The directory inside the snippet is that of the template that created it.
2813                let set_dir = get_from_key(
2814                    &self.shared.schema["__indir"][&self.inherit.indir]["snippets_set_dir"],&snip_name,
2815                );
2816
2817                if !set_dir.is_empty() {
2818                    self.inherit.current_dir = set_dir;
2819                }
2820
2821                // auto mod_scope in snippets for snippets inside snippets
2822                self.code = new_child_parse!(self, &self.code, self.code.contains("{:snip"));
2823            }
2824
2825            self.out = self.code.to_string();
2826
2827            Ok(())
2828        }
2829    }
2830
2831    /*
2832       {:trans; ... :}
2833    */
2834    fn parse_bif_trans(&mut self) -> Result<(), BifError> {
2835        if self.mod_filter || self.mod_scope {
2836            return Err(BifError {
2837                code: 172,
2838                msg: "modifier not allowed".to_string(),
2839                name: self.alias.clone(),
2840                src: self.raw.to_string(),
2841            });
2842        }
2843
2844        // For performance, we avoid calling BlockParser::new if it is not necessary
2845        if self.src.contains(BIF_OPEN) {
2846            self.src = new_child_parse!(self, &self.src, self.mod_scope);
2847        }
2848
2849        let trans = self.get_trans(&self.src);
2850
2851        // By default the input text
2852        if trans.is_empty() {
2853            if self.mod_negate {
2854                self.out = EMPTY_STRING;
2855            } else {
2856                self.out = self.src.clone();
2857            }
2858        } else {
2859            self.out = trans;
2860        }
2861
2862        Ok(())
2863    }
2864}