mirror of https://git.meli.delivery/meli/meli
melib/utils: add fnmatch(3) interface
Meant for use with mailbox path globbing. Signed-off-by: Manos Pitsidianakis <manos@pitsidianak.is>pull/492/head
parent
7f0157a966
commit
be3b3ef89b
@ -0,0 +1,77 @@
|
|||||||
|
//
|
||||||
|
// meli
|
||||||
|
//
|
||||||
|
// Copyright 2024 Emmanouil Pitsidianakis <manos@pitsidianak.is>
|
||||||
|
//
|
||||||
|
// This file is part of meli.
|
||||||
|
//
|
||||||
|
// meli is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// meli is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with meli. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: EUPL-1.2 OR GPL-3.0-or-later
|
||||||
|
|
||||||
|
//! Interface for `libc`'s `fnmatch(3)`.
|
||||||
|
|
||||||
|
use std::ffi::CString;
|
||||||
|
|
||||||
|
mod ffi {
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
use std::os::raw::{c_char, c_int};
|
||||||
|
|
||||||
|
use cfg_if::cfg_if;
|
||||||
|
|
||||||
|
pub(super) const FNM_PERIOD: c_int = 1 << 2;
|
||||||
|
pub(super) const FNM_CASEFOLD: c_int = 1 << 4;
|
||||||
|
pub(super) const FNM_NOMATCH: c_int = 1;
|
||||||
|
|
||||||
|
cfg_if! {
|
||||||
|
if #[cfg(any(
|
||||||
|
target_os = "macos",
|
||||||
|
target_os = "freebsd",
|
||||||
|
target_os = "android",
|
||||||
|
))] {
|
||||||
|
pub(super) const FNM_PATHNAME: c_int = 1 << 1;
|
||||||
|
pub(super) const FNM_NOESCAPE: c_int = 1 << 0;
|
||||||
|
} else {
|
||||||
|
pub(super) const FNM_PATHNAME: c_int = 1 << 0;
|
||||||
|
pub(super) const FNM_NOESCAPE: c_int = 1 << 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
pub(super) fn fnmatch(pattern: *const c_char, name: *const c_char, flags: c_int) -> c_int;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See `fnmatch(3)`.
|
||||||
|
pub trait Fnmatch {
|
||||||
|
/// Returns `true` if glob pattern argument matches `self`.
|
||||||
|
fn fnmatches(&self, pattern: &str) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Fnmatch for str {
|
||||||
|
fn fnmatches(&self, pattern: &str) -> bool {
|
||||||
|
let (Ok(name_c), Ok(pattern_c)) = (CString::new(self), CString::new(pattern)) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
// SAFETY: both `pattern_c` and `name_c` are valid and NULL-terminated.
|
||||||
|
unsafe {
|
||||||
|
ffi::fnmatch(
|
||||||
|
pattern_c.as_c_str().as_ptr(),
|
||||||
|
name_c.as_c_str().as_ptr(),
|
||||||
|
ffi::FNM_PERIOD,
|
||||||
|
) == 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue