]> git.lizzy.rs Git - rust.git/blob - src/test/run-pass/variadic-ffi.rs
cleanup: s/impl Copy/#[derive(Copy)]/g
[rust.git] / src / test / run-pass / variadic-ffi.rs
1 // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 extern crate libc;
12
13 use std::ffi::{self, CString};
14 use libc::{c_char, c_int};
15
16 // ignore-fast doesn't like extern crate
17
18 extern {
19     fn sprintf(s: *mut c_char, format: *const c_char, ...) -> c_int;
20 }
21
22 unsafe fn check<T, F>(expected: &str, f: F) where F: FnOnce(*mut c_char) -> T {
23     let mut x = [0 as c_char; 50];
24     f(&mut x[0] as *mut c_char);
25     assert_eq!(expected.as_bytes(), ffi::c_str_to_bytes(&x.as_ptr()));
26 }
27
28 pub fn main() {
29
30     unsafe {
31         // Call with just the named parameter
32         let c = CString::from_slice(b"Hello World\n");
33         check("Hello World\n", |s| sprintf(s, c.as_ptr()));
34
35         // Call with variable number of arguments
36         let c = CString::from_slice(b"%d %f %c %s\n");
37         check("42 42.500000 a %d %f %c %s\n\n", |s| {
38             sprintf(s, c.as_ptr(), 42i, 42.5f64, 'a' as c_int, c.as_ptr());
39         });
40
41         // Make a function pointer
42         let x: unsafe extern fn(*mut c_char, *const c_char, ...) -> c_int = sprintf;
43
44         // A function that takes a function pointer
45         unsafe fn call(p: unsafe extern fn(*mut c_char, *const c_char, ...) -> c_int) {
46             // Call with just the named parameter
47             let c = CString::from_slice(b"Hello World\n");
48             check("Hello World\n", |s| sprintf(s, c.as_ptr()));
49
50             // Call with variable number of arguments
51             let c = CString::from_slice(b"%d %f %c %s\n");
52             check("42 42.500000 a %d %f %c %s\n\n", |s| {
53                 sprintf(s, c.as_ptr(), 42i, 42.5f64, 'a' as c_int, c.as_ptr());
54             });
55         }
56
57         // Pass sprintf directly
58         call(sprintf);
59
60         // Pass sprintf indirectly
61         call(x);
62     }
63
64 }