ftp_cmd_list_parse/entry/
msdos.rs1use std::convert::TryFrom;
2
3use ::regex::Regex;
4
5use super::*;
6
7lazy_static! {
8 static ref RELIST: Regex = Regex::new(
9 r"(?x)
10 ^(?P<month>\d{2})(?:\-|/)
11 (?P<date>\d{2})(?:\-|/)
12 (?P<year>\d{2,4})\s+
13 (?P<hour>\d{2}):(?P<minute>\d{2})\s{0,1}(?P<ampm>[AaMmPp]{1,2})\s+
14 (?:(?P<size>\d+)|(?P<isdir><DIR>))\s+
15 (?P<name>.+)$
16 "
17 )
18 .unwrap();
19}
20
21#[derive(Debug)]
23pub struct FtpEntryMsdos {
24 kind: FtpEntryKind,
25 name: String,
26 size: usize,
27 date_str: String,
29}
30
31impl FtpEntryMsdos {
32 pub fn new(string: &str) -> Option<Self> {
34 FtpEntryMsdos::try_from(string).ok()
35 }
36}
37
38impl FtpEntryInfo for FtpEntryMsdos {
39 fn kind(&self) -> super::FtpEntryKind {
40 self.kind
41 }
42
43 fn name(&self) -> &str {
44 &self.name
45 }
46
47 fn size(&self) -> usize {
48 self.size
49 }
50
51 fn date_str(&self) -> &str {
56 &self.date_str
57 }
58}
59
60impl TryFrom<&str> for FtpEntryMsdos {
61 type Error = ();
62
63 fn try_from(value: &str) -> Result<Self, Self::Error> {
64 if let Some(caps) = RELIST.captures(&value) {
65 let as_str = |s| caps.name(s).unwrap().as_str();
66
67 let name = as_str("name");
68 let kind = caps
69 .name("isdir")
70 .map_or(FtpEntryKind::File, |_| FtpEntryKind::Directory);
71 let size = caps
72 .name("size")
73 .map(|s| s.as_str().parse::<usize>())
74 .map_or(0, |r| r.map_or(0, |size| size));
75
76 let date_str = {
77 let month: u8 = as_str("month").parse().unwrap();
78 let date: u8 = as_str("date").parse().unwrap();
79 let year: u32 = match (as_str("year").len(), as_str("year").parse::<u32>().unwrap())
80 {
81 (len, year) if len < 4 => year + if year < 70 { 2000 } else { 1900 },
82 (_, year) => year,
83 };
84 let mut hour: u8 = as_str("hour").parse().unwrap();
85 let minute: u8 = as_str("minute").parse().unwrap();
86 if hour < 12
87 && as_str("ampm")
88 .bytes()
89 .next()
90 .unwrap()
91 .eq_ignore_ascii_case(&b'p')
92 {
93 hour += 12;
94 } else if hour == 12
95 && as_str("ampm")
96 .bytes()
97 .next()
98 .unwrap()
99 .eq_ignore_ascii_case(&b'a')
100 {
101 hour = 0;
102 }
103
104 format!(
105 "{}-{:02}-{:02}T{:02}:{:02}",
106 year, month, date, hour, minute
107 )
108 };
109
110 return Ok(Self {
111 name: name.to_owned(),
112 kind,
113 size,
114 date_str,
115 });
116 }
117
118 Err(())
119 }
120}