rustexits 0.1.1

Rust bindings to sysexits.h
/* 
 * Copyright (c) 2024 Emma Tebibyte <emma@tebibyte.media>
 * SPDX-License-Identifier: LGPL-3.0-or-later
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Lesser 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 Lesser General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program. If not, see https://www.gnu.org/licenses/.
 *
 * This file incorporates work covered by the following copyright and permission
 * notice:
 *
 *     Copyright (c) 2024 Emma Tebibyte <emma@tebibyte.media>
 *     SPDX-License-Identifier: FSFAP
 *
 *     Copying and distribution of this file, with or without modification, are
 *     permitted in any medium without royalty provided the copyright notice and
 *     this notice are preserved.  This file is offered as-is, without any
 *     warranty.
 */ 

use std::{
	io::{ Error, Write },
	process::{ Command, Stdio },
	path::PathBuf,
};

use bindgen::{ Builder, CargoCallbacks, MacroTypeVariation };

fn main() -> Result<(), Error> {
	let mut header = String::new();

	/* Locate sysexits.h using cpp(1) */
	let mut process = Command::new("cpp")
		.arg("-M")
		.stdin(Stdio::piped())
		.stdout(Stdio::piped())
		.spawn()?;

	if let Some(mut child_stdin) = process.stdin.take() {
		child_stdin.write_all("#include <sysexits.h>\n".as_bytes())?;
	}

	let output = process.wait_with_output()?.stdout;

	let headers = String::from_utf8(output).map_err(|e| {
		Error::other(e.to_string())
	})?;

	/* Split headers by spaces because cpp(1) returns more than one */
	for h in headers.split(' ') {
		if h.contains("sysexits.h") {
			header = h.trim().to_string();
		/* If sysexits.h cannot be located, then use the dummy sysexits.h */
		} else { header = "src/sysexits.h".to_string() }
	}

	/* Make sysexits bindings depend only on core and use signed integers for
	 * compatibility with Rust’s exit() implementation */
	let bindings = Builder::default()
		.use_core()
		.default_macro_constant_type(MacroTypeVariation::Signed)
		.header(header)
		.parse_callbacks(Box::new(CargoCallbacks::new()))
		.generate()
		.map_err(|e| Error::other(e.to_string()))?;

	bindings.write_to_file(PathBuf::from("src/").join("lib.rs"))?;

	Ok(())
}