date_cli/
parse.rs

1/*
2 * Copyright 2024 Stanislav Mikhailov (xavetar)
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a copy
11 * of this software and associated documentation files (the "Software"), to deal
12 * in the Software without restriction, including without limitation the rights
13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the Software is
15 * furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 * THE SOFTWARE.
27 */
28
29use PHASEXave::{
30    CalendarView,
31    Date, Week,
32    Zone, Sign,
33    RataDie, Xavetar, Sakamoto
34};
35
36fn print_help() {
37    println!(
38        "Usage: {bin_name} [options]\n\nOptions:
39
40        -z, --zone [ZONE]              Set the time_zone:[+/-][hours:minutes:seconds]: local zone (default)
41                                                                                       [+/-][255-1:255-1:255-1] (max)
42
43        -m, --method [METHOD]          Determining the day of week method: 1 - Xavetar - High Precision - Fast
44                                                                           2 - Rata Die - High Precision - Fast (default)
45                                                                           3 - Sakamoto - High Precision - Fast
46
47        -v, --view [VIEW]              Set the calendar view: 1 - Julian
48                                                              2 - Gregorian (default)
49                                                              3 - Solar
50
51        ", bin_name = std::path::Path::new::<String>(
52            &std::env::args().nth(0)
53                .expect("[ERROR]: Binary path is unknown (print_help)!"))
54            .file_name().expect("[ERROR]: Can't unwrap filename (print_help)!")
55            .to_str().expect("[ERROR]: Can't convert OsStr to &str filename (print_help)!")
56    );
57}
58
59pub fn parse_args(time_zone: &mut Zone, method: &mut fn(CalendarView, u64, u8, u8) -> Week, view: &mut CalendarView) {
60    let mut args: std::iter::Skip<std::env::Args> = std::env::args().skip(1);
61
62    while let Some(arg) = args.next() {
63        match arg.as_str() {
64            "-h" | "--help" => {
65                print_help();
66                std::process::exit(0);
67            }
68            "-z" | "--zone" => {
69                if let Some(zone_str) = args.next() {
70                    let sign: Sign;
71
72                    if zone_str.starts_with("-") {
73                        sign = Sign::Signed
74                    } else if zone_str.starts_with("+") {
75                        sign = Sign::Unsigned
76                    } else {
77                        panic!("[ERROR] Invalid sign in time zone: {char:?}", char = zone_str.chars().nth(0));
78                    }
79
80                    let zone_values: Vec<u8> = zone_str[1..]
81                        .split(':')
82                        .map(|x| x.parse::<u8>())
83                        .collect::<Result<Vec<u8>, std::num::ParseIntError>>()
84                        .expect("[ERROR]: One of value or more is not a unsigned integer or overflow type!");
85
86                    if zone_values.len() < 3 {
87                        println!("[ERROR]: Invalid argument format: -z, --zone [+/-][hours:minutes:seconds]");
88                        std::process::exit(0);
89                    } else if zone_values.len() > 3 {
90                        println!("[ERROR]: Invalid argument format: -z, --zone [+/-][hours:minutes:seconds]");
91                        std::process::exit(0);
92                    } else {
93                        (time_zone.sign, time_zone.hours, time_zone.minutes, time_zone.seconds)
94                        =
95                        (sign, zone_values[0], zone_values[1], zone_values[2]);
96                    }
97                } else {
98                    println!("[ERROR]: Value not provided: -z, --margins");
99                    std::process::exit(0);
100                }
101            }
102            "-m" | "--method" => {
103                if let Some(method_str) = args.next() {
104                    if let Ok(parsed_method) = method_str.parse::<u8>() {
105                        match parsed_method {
106                            1 => *method = <Date as Xavetar>::from,
107                            2 => *method = <Date as RataDie>::from,
108                            3 => *method = <Date as Sakamoto>::from,
109                            _ => {
110                                println!("[ERROR]: Invalid method type: -m, --method");
111                                std::process::exit(0);
112                            }
113                        }
114                    } else {
115                        println!("[ERROR]: Value is not a unsigned integer or overflow type: -m, --method [METHOD]");
116                        std::process::exit(0);
117                    }
118                } else {
119                    println!("[ERROR]: Value not provided: -m, --method");
120                    std::process::exit(0);
121                }
122            }
123            "-v" | "--view" => {
124                if let Some(view_str) = args.next() {
125                    if let Ok(parsed_view) = view_str.parse::<u8>() {
126                        match parsed_view {
127                            1 => *view = CalendarView::Julian,
128                            2 => *view = CalendarView::Gregorian,
129                            3 => *view = CalendarView::Solar,
130                            _ => {
131                                println!("[ERROR]: Invalid view type: -v, --view");
132                                std::process::exit(0);
133                            }
134                        }
135                    } else {
136                        println!("[ERROR]: Value is not a unsigned integer or overflow type: -v, --view [VIEW]");
137                        std::process::exit(0);
138                    }
139                } else {
140                    println!("[ERROR]: Value not provided: -v, --view");
141                    std::process::exit(0);
142                }
143            }
144            _ => {
145                println!("[ERROR]: Unknown option: {}", arg);
146                std::process::exit(0);
147            }
148        }
149    }
150}