umpl/
cli.rs

1use std::process::exit;
2
3use crate::error;
4pub static mut EASY_MODE: bool = false;
5pub static mut TOGGLE_CASE: i32 = 0;
6#[derive(PartialEq, Eq, Debug)]
7pub struct ParsedArgs {
8    pub repl: bool,   // inerative mode
9    pub file: String, // file to read/write
10    pub force: bool,  // if true, overwrites file
11    pub log: bool,    // if true, logs to file
12}
13
14impl ParsedArgs {
15    const fn new(repl: bool, file: String) -> Self {
16        Self {
17            repl,
18            file,
19            force: false,
20            log: false,
21        }
22    }
23}
24
25pub fn get_string_args(args: &[String]) -> (usize, ParsedArgs) {
26    let mut to_return: ParsedArgs = ParsedArgs::new(false, String::new());
27    let mut index: usize = 1; // start at 1 because index  0 is the program name
28    if args.len() < 2 {
29        // if there are no arguments run in repl mode with no file
30        return (0, ParsedArgs::new(true, String::new()));
31    } else if args[1].ends_with(".umpl") {
32        // make sure it's a .umpl file
33        to_return.file = args[1].to_string(); // if it is, then set file to the file name
34        to_return.repl = false; // and set repl to false
35        index += 1; // and increment index
36        let file_len = to_return.file.strip_suffix(".umpl").unwrap().len(); // get the length of the file name without the .umpl
37        if args.len() > 2 && args[2] == format!("{file_len}") {
38            unsafe {
39                EASY_MODE = true;
40            }
41            index += 1; // and increment index
42        } else if args.len() > 2 && args[2] == "show_length" {
43            println!("{file_len}"); // print the length of the file name without the .umpl
44            exit(1);
45        }
46    } else {
47        to_return.repl = true; // if it's not a .umpl file, then set repl to true
48        for (arg_index, arg) in args[index..].iter().enumerate() {
49            if arg.starts_with('-') {
50                // if it starts with a dash
51                index += arg_index; // then add the args index to the current index
52                break; // and break
53            }
54            usage(); // if not a flag, then its not one of the args we want so print usage and exit
55        }
56    };
57    (index, to_return)
58}
59#[allow(clippy::cast_possible_wrap)]
60pub fn get_dash_args(args: &[String], start_index: usize, args_struct: &mut ParsedArgs) {
61    args[start_index..].iter().for_each(|arg| {
62        // for each arg after the start index
63        if arg.starts_with('-') {
64            // if it starts with a dash check if its a correct flag and set the appropriate field if not print usage and exit
65            for char_part_arg in arg.chars().skip(1) {
66                if ['r', 'i'].contains(&char_part_arg) {
67                    args_struct.repl = true;
68                } else if ['f'].contains(&char_part_arg) {
69                    args_struct.force = true;
70                } else if ['l'].contains(&char_part_arg) {
71                    args_struct.log = true;
72                } else if char_part_arg == 'e' {
73                    unsafe {
74                        EASY_MODE = false;
75                    }
76                    let num = match &args_struct.file {
77                        // TODO: use rand
78                        file if file.is_empty() => 0,
79                        file => file.len(),
80                    };
81                    unsafe { TOGGLE_CASE = num as i32 };
82                } else if char_part_arg == 't' {
83                    let number: i32 = arg.split_once('=').map_or_else(
84                        || error::error(0, "option t requires an =number"),
85                        |n| match n.1.parse() {
86                            Ok(value) => value,
87                            Err(error) => error::error(0, error),
88                        },
89                    );
90                    unsafe {
91                        TOGGLE_CASE = number;
92                    }
93                    break;
94                } else {
95                    usage();
96                }
97            }
98        } else {
99            usage();
100        }
101    });
102}
103
104fn usage() {
105    unsafe {
106        if EASY_MODE {
107            println!(
108                "Usage: umpl [File] [OPTIONS]
109        OPTIONS: 
110        -r, -i: interactive mode
111        -h: help
112        -f: force
113        -t=number: toggle case"
114            );
115        } else {
116            eprintln!("Segmentation fault (core dumped)");
117        }
118    }
119    exit(1);
120}