hexchat_unsafe_plugin/word.rs
1// This file is part of Hexchat Plugin API Bindings for Rust
2// Copyright (C) 2018, 2021, 2022 Soni L.
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as
6// published by the Free Software Foundation, either version 3 of the
7// License, or (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <https://www.gnu.org/licenses/>.
16
17use std::ffi::CStr;
18use std::ops::Deref;
19
20/// Arguments passed to a hook, until the next argument.
21///
22/// # Examples
23///
24/// ```no_run
25/// use hexchat_unsafe_plugin::{PluginHandle, Word, WordEol, Eat};
26///
27/// fn cmd_foo(ph: &mut PluginHandle, arg: Word, arg_eol: WordEol) -> Eat {
28/// if arg.len() < 3 {
29/// ph.print("Not enough arguments");
30/// } else {
31/// ph.print(&format!("{} {} {}", arg[0], arg[1], arg[2]));
32/// }
33/// hexchat_unsafe_plugin::EAT_ALL
34/// }
35///
36/// fn on_privmsg(ph: &mut PluginHandle, word: Word, word_eol: WordEol) -> Eat {
37/// if word.len() > 0 && word[0].starts_with('@') {
38/// ph.print("We have message tags!?");
39/// }
40/// hexchat_unsafe_plugin::EAT_NONE
41/// }
42/// ```
43pub struct Word<'a> {
44 word: Vec<&'a str>
45}
46
47/// Arguments passed to a hook, until the end of the line.
48///
49/// # Examples
50///
51/// ```no_run
52/// use hexchat_unsafe_plugin::{PluginHandle, Word, WordEol, Eat};
53///
54/// fn cmd_foo(ph: &mut PluginHandle, arg: Word, arg_eol: WordEol) -> Eat {
55/// if arg.len() < 3 {
56/// ph.print("Not enough arguments");
57/// } else {
58/// ph.print(&format!("{} {} {}", arg[0], arg[1], arg_eol[2]));
59/// }
60/// hexchat_unsafe_plugin::EAT_ALL
61/// }
62///
63/// fn on_privmsg(ph: &mut PluginHandle, word: Word, word_eol: WordEol) -> Eat {
64/// if word_eol.len() > 0 && word[0].starts_with('@') {
65/// ph.print("We have message tags!?");
66/// }
67/// hexchat_unsafe_plugin::EAT_NONE
68/// }
69/// ```
70pub struct WordEol<'a> {
71 word_eol: Vec<&'a str>
72}
73
74impl<'a> Word<'a> {
75 /// Creates a new Word.
76 ///
77 /// # Safety
78 ///
79 /// Uses raw pointers.
80 pub(crate) unsafe fn new(word: *const *const libc::c_char) -> Word<'a> {
81 let mut vec = vec![];
82 for i in 1..32 {
83 let w = *word.offset(i);
84 if !w.is_null() {
85 vec.push(CStr::from_ptr(w).to_str().expect("non-utf8 word - broken hexchat"))
86 }
87 }
88 while let Some(&"") = vec.last() {
89 vec.pop();
90 }
91 Word { word: vec }
92 }
93}
94
95/// Provides access to the contents of the Word.
96impl<'a> Deref for Word<'a> {
97 type Target = [&'a str];
98 fn deref(&self) -> &[&'a str] {
99 &self.word
100 }
101}
102
103impl<'a> WordEol<'a> {
104 /// Creates a new WordEol.
105 ///
106 /// # Safety
107 ///
108 /// Uses raw pointers.
109 pub(crate) unsafe fn new(word_eol: *const *const libc::c_char) -> WordEol<'a> {
110 let mut vec = vec![];
111 for i in 1..32 {
112 let w = *word_eol.offset(i);
113 if !w.is_null() {
114 vec.push(CStr::from_ptr(w).to_str().expect("non-utf8 word_eol - broken hexchat"))
115 }
116 }
117 while let Some(&"") = vec.last() {
118 vec.pop();
119 }
120 WordEol { word_eol: vec }
121 }
122}
123
124/// Provides access to the contents of the WordEol.
125impl<'a> Deref for WordEol<'a> {
126 type Target = [&'a str];
127 fn deref(&self) -> &[&'a str] {
128 &self.word_eol
129 }
130}