Skip to content

Commit c23e1db

Browse files
committed
Use the last, not first, two digits as the year
1 parent 6dfa1f8 commit c23e1db

File tree

2 files changed

+32
-13
lines changed

2 files changed

+32
-13
lines changed

src/uu/touch/src/touch.rs

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -141,19 +141,22 @@ fn all_digits(s: &str) -> bool {
141141
}
142142

143143
/// Convert a two-digit year string to the corresponding number.
144+
///
145+
/// `s` must be of length two or more. The last two bytes of `s` are
146+
/// assumed to be the two digits of the year.
144147
fn get_year(s: &str) -> u8 {
145-
// Pre-condition: s.len() >= 2
146148
let bytes = s.as_bytes();
147-
let y1 = bytes[0] - b'0';
148-
let y2 = bytes[1] - b'0';
149+
let n = bytes.len();
150+
let y1 = bytes[n - 2] - b'0';
151+
let y2 = bytes[n - 1] - b'0';
149152
10 * y1 + y2
150153
}
151154

152155
/// Whether the first filename should be interpreted as a timestamp.
153156
fn is_first_filename_timestamp(
154157
reference: Option<&OsString>,
155158
date: Option<&str>,
156-
timestamp: Option<&String>,
159+
timestamp: &Option<String>,
157160
files: &[&String],
158161
) -> bool {
159162
match std::env::var("_POSIX2_VERSION") {
@@ -180,6 +183,18 @@ fn is_first_filename_timestamp(
180183
}
181184
}
182185

186+
/// Cycle the last two characters to the beginning of the string.
187+
///
188+
/// `s` must have length at least two.
189+
fn shr2(s: &str) -> String {
190+
let n = s.len();
191+
let (a, b) = s.split_at(n - 2);
192+
let mut result = String::with_capacity(n);
193+
result.push_str(b);
194+
result.push_str(a);
195+
result
196+
}
197+
183198
#[uucore::main]
184199
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
185200
let matches = uu_app().try_get_matches_from(args)?;
@@ -204,19 +219,23 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
204219
.get_one::<String>(options::sources::DATE)
205220
.map(|date| date.to_owned());
206221

207-
let mut timestamp = matches.get_one::<String>(options::sources::TIMESTAMP);
222+
let mut timestamp = matches
223+
.get_one::<String>(options::sources::TIMESTAMP)
224+
.map(|t| t.to_owned());
208225

209-
if is_first_filename_timestamp(reference, date.as_deref(), timestamp, &filenames) {
210-
let head = filenames[0];
211-
let tail = &filenames[1..];
212-
timestamp = Some(head);
213-
filenames = tail.to_vec();
226+
if is_first_filename_timestamp(reference, date.as_deref(), &timestamp, &filenames) {
227+
timestamp = if filenames[0].len() == 10 {
228+
Some(shr2(filenames[0]))
229+
} else {
230+
Some(filenames[0].to_string())
231+
};
232+
filenames = filenames[1..].to_vec();
214233
}
215234

216235
let source = if let Some(reference) = reference {
217236
Source::Reference(PathBuf::from(reference))
218237
} else if let Some(ts) = timestamp {
219-
Source::Timestamp(parse_timestamp(ts)?)
238+
Source::Timestamp(parse_timestamp(&ts)?)
220239
} else {
221240
Source::Now
222241
};

tests/by-util/test_touch.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -935,9 +935,9 @@ fn test_obsolete_posix_format_with_year() {
935935
let (at, mut ucmd) = at_and_ucmd!();
936936
ucmd.env("_POSIX2_VERSION", "199209")
937937
.env("POSIXLY_CORRECT", "1")
938-
.args(&["9001010000", "11111111"])
938+
.args(&["0101000090", "11111111"])
939939
.succeeds()
940940
.no_output();
941941
assert!(at.file_exists("11111111"));
942-
assert!(!at.file_exists("01010000"));
942+
assert!(!at.file_exists("0101000090"));
943943
}

0 commit comments

Comments
 (0)