// This file is part of Hexchat Plugin API Bindings for Rust // Copyright (C) 2018, 2021, 2022 Soni L. // // This program 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. // // This program 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 this program. If not, see . use crate::EMPTY_CSTRING_DATA; use crate::cstr; use std::mem; use std::ffi::CString; /// Holds name, desc, vers // This is kinda naughty - we modify these values after returning from hexchat_plugin_init, during // the deinitialization. // However, if my reading of the HexChat code is correct, this is "ok". #[derive(Copy, Clone)] pub struct PluginInfo { pub name: *mut *const libc::c_char, pub desc: *mut *const libc::c_char, pub vers: *mut *const libc::c_char, } impl PluginInfo { /// Creates a PluginInfo. /// /// # Safety /// /// This function is unsafe, as it can't guarantee the validity of its /// arguments. It does more checking than `new_unchecked` however. /// /// See `new_unchecked` for the full requirements. /// /// # Panics /// /// This function explicitly doesn't panic. Call unwrap() on the result instead. pub unsafe fn new( name: *mut *const libc::c_char, desc: *mut *const libc::c_char, vers: *mut *const libc::c_char, ) -> Option { if name.is_null() || desc.is_null() || vers.is_null() || name == desc || desc == vers || name == vers { None } else { Some(PluginInfo::new_unchecked(name, desc, vers)) } } /// Creates a PluginInfo without checking the arguments. /// /// # Safety /// /// This function is unsafe, as it doesn't check the validity of the /// arguments. You're expected to only pass in non-aliased non-null valid /// pointers. Use `new` if unsure. pub unsafe fn new_unchecked( name: *mut *const libc::c_char, desc: *mut *const libc::c_char, vers: *mut *const libc::c_char, ) -> PluginInfo { PluginInfo { name, desc, vers } } /// Drop relevant CStrings. /// /// # Safety /// /// This function is unsafe because calling it may trigger Undefined Behaviour. See also /// [CString::from_raw]. /// /// [from_raw]: https://doc.rust-lang.org/std/ffi/struct.CString.html#method.from_raw pub unsafe fn drop_info(&mut self) { if !(*self.name).is_null() { mem::drop(CString::from_raw(*self.name as *mut _)); *self.name = cstr(EMPTY_CSTRING_DATA); } if !(*self.desc).is_null() { mem::drop(CString::from_raw(*self.desc as *mut _)); *self.desc = cstr(EMPTY_CSTRING_DATA); } if !(*self.vers).is_null() { mem::drop(CString::from_raw(*self.vers as *mut _)); *self.vers = cstr(EMPTY_CSTRING_DATA); } } /// Returns whether this `PluginInfo` has been registered. /// /// # Safety /// /// We cannot currently guarantee the validity of the pointers contained in /// here. pub unsafe fn is_registered(&self) -> bool { ![ self.name, self.desc, self.vers, ].into_iter().any(|meta| unsafe { *meta }.is_null()) } }