1use std::ffi::{c_char, CString};
2use std::{mem, ptr, slice};
3
4use pkgcraft::pkg::ebuild::{xml, EbuildPackage};
5use pkgcraft::pkg::Pkg;
6use pkgcraft::traits::IntoOwned;
7
8use crate::dep::{DependencySet, DependencySetKind};
9use crate::error::Error;
10use crate::macros::*;
11use crate::panic::ffi_catch_panic;
12use crate::utils::{boxed, obj_to_str, str_to_raw};
13
14pub mod keyword;
15use keyword::Keyword;
16
17#[repr(C)]
19pub struct Maintainer {
20 email: *mut c_char,
21 name: *mut c_char,
22 description: *mut c_char,
23 maint_type: *mut c_char,
24 proxied: *mut c_char,
25}
26
27impl Drop for Maintainer {
28 fn drop(&mut self) {
29 unsafe {
30 drop(CString::from_raw(self.email));
31 char_p_or_null_free!(self.name);
32 char_p_or_null_free!(self.description);
33 drop(CString::from_raw(self.maint_type));
34 drop(CString::from_raw(self.proxied));
35 }
36 }
37}
38
39#[repr(C)]
41pub struct RemoteId {
42 site: *mut c_char,
43 name: *mut c_char,
44}
45
46impl Drop for RemoteId {
47 fn drop(&mut self) {
48 unsafe {
49 drop(CString::from_raw(self.site));
50 drop(CString::from_raw(self.name));
51 }
52 }
53}
54
55#[repr(C)]
57pub struct UpstreamMaintainer {
58 name: *mut c_char,
59 email: *mut c_char,
60 status: *mut c_char,
61}
62
63impl Drop for UpstreamMaintainer {
64 fn drop(&mut self) {
65 unsafe {
66 drop(CString::from_raw(self.name));
67 char_p_or_null_free!(self.email);
68 drop(CString::from_raw(self.status));
69 }
70 }
71}
72
73#[repr(C)]
75pub struct Upstream {
76 remote_ids_len: usize,
77 remote_ids: *mut *mut RemoteId,
78 maintainers_len: usize,
79 maintainers: *mut *mut UpstreamMaintainer,
80 bugs_to: *mut c_char,
81 changelog: *mut c_char,
82 doc: *mut c_char,
83}
84
85impl Drop for Upstream {
86 fn drop(&mut self) {
87 unsafe {
88 let len = self.remote_ids_len;
89 for ptr in Vec::from_raw_parts(self.remote_ids, len, len).into_iter() {
90 drop(Box::from_raw(ptr));
91 }
92 let len = self.maintainers_len;
93 for ptr in Vec::from_raw_parts(self.maintainers, len, len).into_iter() {
94 drop(Box::from_raw(ptr));
95 }
96 char_p_or_null_free!(self.bugs_to);
97 char_p_or_null_free!(self.changelog);
98 char_p_or_null_free!(self.doc);
99 }
100 }
101}
102
103macro_rules! try_pkg_from_ptr {
105 ( $var:expr ) => {{
106 let pkg = $crate::macros::try_ref_from_ptr!($var);
107 match pkg {
108 Pkg::Ebuild(p, _) => p,
109 Pkg::Configured(p, _) => p.into(),
110 _ => panic!("invalid pkg type: {pkg:?}"),
111 }
112 }};
113}
114
115#[no_mangle]
120pub unsafe extern "C" fn pkgcraft_pkg_ebuild_path(p: *mut Pkg) -> *mut c_char {
121 let pkg = try_pkg_from_ptr!(p);
122 try_ptr_from_str!(pkg.path().as_str())
123}
124
125#[no_mangle]
132pub unsafe extern "C" fn pkgcraft_pkg_ebuild_ebuild(p: *mut Pkg) -> *mut c_char {
133 ffi_catch_panic! {
134 let pkg = try_pkg_from_ptr!(p);
135 let s = unwrap_or_panic!(pkg.ebuild());
136 try_ptr_from_str!(s)
137 }
138}
139
140#[no_mangle]
145pub unsafe extern "C" fn pkgcraft_pkg_ebuild_deprecated(p: *mut Pkg) -> bool {
146 let pkg = try_pkg_from_ptr!(p);
147 pkg.deprecated()
148}
149
150#[no_mangle]
155pub unsafe extern "C" fn pkgcraft_pkg_ebuild_live(p: *mut Pkg) -> bool {
156 let pkg = try_pkg_from_ptr!(p);
157 pkg.live()
158}
159
160#[no_mangle]
165pub unsafe extern "C" fn pkgcraft_pkg_ebuild_masked(p: *mut Pkg) -> bool {
166 let pkg = try_pkg_from_ptr!(p);
167 pkg.masked()
168}
169
170#[no_mangle]
175pub unsafe extern "C" fn pkgcraft_pkg_ebuild_description(p: *mut Pkg) -> *mut c_char {
176 let pkg = try_pkg_from_ptr!(p);
177 try_ptr_from_str!(pkg.description())
178}
179
180#[no_mangle]
185pub unsafe extern "C" fn pkgcraft_pkg_ebuild_slot(p: *mut Pkg) -> *mut c_char {
186 let pkg = try_pkg_from_ptr!(p);
187 try_ptr_from_str!(pkg.slot())
188}
189
190#[no_mangle]
195pub unsafe extern "C" fn pkgcraft_pkg_ebuild_subslot(p: *mut Pkg) -> *mut c_char {
196 let pkg = try_pkg_from_ptr!(p);
197 try_ptr_from_str!(pkg.subslot())
198}
199
200#[no_mangle]
207pub unsafe extern "C" fn pkgcraft_pkg_ebuild_dependencies(
208 p: *mut Pkg,
209 keys: *mut *mut c_char,
210 len: usize,
211) -> *mut DependencySet {
212 ffi_catch_panic! {
213 let pkg = try_pkg_from_ptr!(p);
214 let keys = unsafe { slice::from_raw_parts(keys, len) };
215 let mut dep_keys = vec![];
216 for s in keys {
217 let s = try_str_from_ptr!(s);
218 let key = unwrap_or_panic!(
219 s.to_uppercase().parse().map_err(|_| Error::new(format!("invalid dep key: {s}")))
220 );
221 dep_keys.push(key);
222 }
223
224 let deps = pkg.dependencies(&dep_keys).into_owned();
225 Box::into_raw(Box::new(DependencySet::new_dep(deps)))
226 }
227}
228
229#[no_mangle]
234pub unsafe extern "C" fn pkgcraft_pkg_ebuild_depend(p: *mut Pkg) -> *mut DependencySet {
235 let pkg = try_pkg_from_ptr!(p);
236 let set = DependencySet::new_dep(pkg.depend().clone());
237 Box::into_raw(Box::new(set))
238}
239
240#[no_mangle]
245pub unsafe extern "C" fn pkgcraft_pkg_ebuild_bdepend(p: *mut Pkg) -> *mut DependencySet {
246 let pkg = try_pkg_from_ptr!(p);
247 let set = DependencySet::new_dep(pkg.bdepend().clone());
248 Box::into_raw(Box::new(set))
249}
250
251#[no_mangle]
256pub unsafe extern "C" fn pkgcraft_pkg_ebuild_idepend(p: *mut Pkg) -> *mut DependencySet {
257 let pkg = try_pkg_from_ptr!(p);
258 let set = DependencySet::new_dep(pkg.idepend().clone());
259 Box::into_raw(Box::new(set))
260}
261
262#[no_mangle]
267pub unsafe extern "C" fn pkgcraft_pkg_ebuild_pdepend(p: *mut Pkg) -> *mut DependencySet {
268 let pkg = try_pkg_from_ptr!(p);
269 let set = DependencySet::new_dep(pkg.pdepend().clone());
270 Box::into_raw(Box::new(set))
271}
272
273#[no_mangle]
278pub unsafe extern "C" fn pkgcraft_pkg_ebuild_rdepend(p: *mut Pkg) -> *mut DependencySet {
279 let pkg = try_pkg_from_ptr!(p);
280 let set = DependencySet::new_dep(pkg.rdepend().clone());
281 Box::into_raw(Box::new(set))
282}
283
284#[no_mangle]
289pub unsafe extern "C" fn pkgcraft_pkg_ebuild_license(p: *mut Pkg) -> *mut DependencySet {
290 let pkg = try_pkg_from_ptr!(p);
291 let set = DependencySet::new_string(pkg.license().clone(), DependencySetKind::License);
292 Box::into_raw(Box::new(set))
293}
294
295#[no_mangle]
300pub unsafe extern "C" fn pkgcraft_pkg_ebuild_properties(p: *mut Pkg) -> *mut DependencySet {
301 let pkg = try_pkg_from_ptr!(p);
302 let set = DependencySet::new_string(pkg.properties().clone(), DependencySetKind::Properties);
303 Box::into_raw(Box::new(set))
304}
305
306#[no_mangle]
311pub unsafe extern "C" fn pkgcraft_pkg_ebuild_required_use(p: *mut Pkg) -> *mut DependencySet {
312 let pkg = try_pkg_from_ptr!(p);
313 let set = DependencySet::new_string(pkg.required_use().clone(), DependencySetKind::RequiredUse);
314 Box::into_raw(Box::new(set))
315}
316
317#[no_mangle]
322pub unsafe extern "C" fn pkgcraft_pkg_ebuild_restrict(p: *mut Pkg) -> *mut DependencySet {
323 let pkg = try_pkg_from_ptr!(p);
324 let set = DependencySet::new_string(pkg.restrict().clone(), DependencySetKind::Restrict);
325 Box::into_raw(Box::new(set))
326}
327
328#[no_mangle]
333pub unsafe extern "C" fn pkgcraft_pkg_ebuild_src_uri(p: *mut Pkg) -> *mut DependencySet {
334 let pkg = try_pkg_from_ptr!(p);
335 let set = DependencySet::new_uri(pkg.src_uri().clone());
336 Box::into_raw(Box::new(set))
337}
338
339#[no_mangle]
344pub unsafe extern "C" fn pkgcraft_pkg_ebuild_homepage(
345 p: *mut Pkg,
346 len: *mut usize,
347) -> *mut *mut c_char {
348 let pkg = try_pkg_from_ptr!(p);
349 iter_to_array!(pkg.homepage().iter(), len, str_to_raw)
350}
351
352#[no_mangle]
357pub unsafe extern "C" fn pkgcraft_pkg_ebuild_defined_phases(
358 p: *mut Pkg,
359 len: *mut usize,
360) -> *mut *mut c_char {
361 let pkg = try_pkg_from_ptr!(p);
362 iter_to_array!(pkg.defined_phases().iter(), len, str_to_raw)
363}
364
365#[no_mangle]
370pub unsafe extern "C" fn pkgcraft_pkg_ebuild_keywords(
371 p: *mut Pkg,
372 len: *mut usize,
373) -> *mut *mut Keyword {
374 let pkg = try_pkg_from_ptr!(p);
375 iter_to_array!(pkg.keywords().iter(), len, |x| boxed(x.clone().into()))
376}
377
378#[no_mangle]
383pub unsafe extern "C" fn pkgcraft_pkg_ebuild_keywords_str(
384 p: *mut Pkg,
385 len: *mut usize,
386) -> *mut *mut c_char {
387 let pkg = try_pkg_from_ptr!(p);
388 iter_to_array!(pkg.keywords().iter(), len, obj_to_str)
389}
390
391#[no_mangle]
396pub unsafe extern "C" fn pkgcraft_pkg_ebuild_iuse(
397 p: *mut Pkg,
398 len: *mut usize,
399) -> *mut *mut c_char {
400 let pkg = try_pkg_from_ptr!(p);
401 iter_to_array!(pkg.iuse().iter(), len, obj_to_str)
402}
403
404#[no_mangle]
409pub unsafe extern "C" fn pkgcraft_pkg_ebuild_inherit(
410 p: *mut Pkg,
411 len: *mut usize,
412) -> *mut *mut c_char {
413 let pkg = try_pkg_from_ptr!(p);
414 iter_to_array!(pkg.inherit().iter().map(|e| e.name()), len, str_to_raw)
415}
416
417#[no_mangle]
422pub unsafe extern "C" fn pkgcraft_pkg_ebuild_inherited(
423 p: *mut Pkg,
424 len: *mut usize,
425) -> *mut *mut c_char {
426 let pkg = try_pkg_from_ptr!(p);
427 iter_to_array!(pkg.inherited().iter().map(|e| e.name()), len, str_to_raw)
428}
429
430#[no_mangle]
437pub unsafe extern "C" fn pkgcraft_pkg_ebuild_long_description(p: *mut Pkg) -> *mut c_char {
438 let pkg = try_pkg_from_ptr!(p);
439 match pkg.long_description() {
440 Some(s) => try_ptr_from_str!(s),
441 None => ptr::null_mut(),
442 }
443}
444
445#[no_mangle]
450pub unsafe extern "C" fn pkgcraft_pkg_ebuild_maintainers(
451 p: *mut Pkg,
452 len: *mut usize,
453) -> *mut *mut Maintainer {
454 let pkg = try_pkg_from_ptr!(p);
455 let mut ptrs: Vec<_> = pkg
456 .maintainers()
457 .iter()
458 .map(|m| {
459 let maintainer = Maintainer {
460 email: try_ptr_from_str!(m.email()),
461 name: char_p_or_null!(m.name()),
462 description: char_p_or_null!(m.description()),
463 maint_type: try_ptr_from_str!(m.maint_type().as_ref()),
464 proxied: try_ptr_from_str!(m.proxied().as_ref()),
465 };
466 Box::into_raw(Box::new(maintainer))
467 })
468 .collect();
469 ptrs.shrink_to_fit();
470 unsafe { *len = ptrs.len() };
471 let p = ptrs.as_mut_ptr();
472 mem::forget(ptrs);
473 p
474}
475
476#[no_mangle]
482pub unsafe extern "C" fn pkgcraft_pkg_ebuild_maintainers_free(
483 maintainers: *mut *mut Maintainer,
484 len: usize,
485) {
486 if !maintainers.is_null() {
487 unsafe {
488 for ptr in Vec::from_raw_parts(maintainers, len, len).into_iter() {
489 drop(Box::from_raw(ptr));
490 }
491 }
492 }
493}
494
495#[no_mangle]
502pub unsafe extern "C" fn pkgcraft_pkg_ebuild_upstream(p: *mut Pkg) -> *mut Upstream {
503 let pkg = try_pkg_from_ptr!(p);
504 match pkg.upstream() {
505 Some(u) => {
506 let mut remote_ids_len: usize = 0;
508 let convert = |r: &xml::RemoteId| {
509 let obj = RemoteId {
510 site: try_ptr_from_str!(r.site()),
511 name: try_ptr_from_str!(r.name()),
512 };
513 Box::into_raw(Box::new(obj))
514 };
515 let remote_ids =
516 iter_to_array!(u.remote_ids().iter(), &mut remote_ids_len as *mut _, convert);
517
518 let mut maintainers_len: usize = 0;
520 let convert = |m: &xml::UpstreamMaintainer| {
521 let obj = UpstreamMaintainer {
522 name: try_ptr_from_str!(m.name()),
523 email: char_p_or_null!(m.email()),
524 status: try_ptr_from_str!(m.status().to_string()),
525 };
526 Box::into_raw(Box::new(obj))
527 };
528 let maintainers =
529 iter_to_array!(u.maintainers().iter(), &mut maintainers_len as *mut _, convert);
530
531 let upstream = Upstream {
532 remote_ids_len,
533 remote_ids,
534 maintainers_len,
535 maintainers,
536 bugs_to: char_p_or_null!(u.bugs_to()),
537 changelog: char_p_or_null!(u.changelog()),
538 doc: char_p_or_null!(u.doc()),
539 };
540
541 Box::into_raw(Box::new(upstream))
542 }
543 None => ptr::null_mut(),
544 }
545}
546
547#[no_mangle]
552pub unsafe extern "C" fn pkgcraft_pkg_ebuild_upstream_free(u: *mut Upstream) {
553 if !u.is_null() {
554 unsafe { drop(Box::from_raw(u)) };
555 }
556}