@@ -22485,6 +22485,7 @@ const ARGP_HELP_POST_DOC: c_uint = 0x20;
2248522485const ARGP_HELP_BUG_ADDR: c_uint = 0x40;
2248622486const ARGP_HELP_EXIT_ERR: c_uint = 0x100;
2248722487const ARGP_HELP_EXIT_OK: c_uint = 0x200;
22488+ const ARGP_NO_EXIT: c_uint = 0x20;
2248822489const ARGP_TEXT_SCAN_LIMIT: usize = 16 * 1024;
2248922490const ARGP_HELP_STATE_NON_RENDERING_FLAGS: c_uint =
2249022491 ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR | ARGP_HELP_EXIT_OK;
@@ -22646,18 +22647,56 @@ unsafe fn argp_write_diagnostic(state: *mut c_void, message: &[u8], errnum: c_in
2264622647 unsafe { argp_write_bytes(stream, &line) }
2264722648}
2264822649
22650+ #[inline]
22651+ unsafe fn argp_exit_unless_suppressed(state: &ArgpStateHeader, status: c_int) {
22652+ if state.flags & ARGP_NO_EXIT == 0 {
22653+ unsafe { crate::stdlib_abi::exit(status) };
22654+ }
22655+ }
22656+
22657+ unsafe fn argp_write_version(stream: *mut libc::FILE, state: *mut c_void) -> bool {
22658+ let hook = unsafe { crate::glibc_internal_abi::argp_program_version_hook };
22659+ if !hook.is_null() {
22660+ type ArgpVersionHook = unsafe extern "C" fn(*mut libc::FILE, *mut c_void);
22661+ // SAFETY: `argp_program_version_hook` is the public GNU argp callback
22662+ // slot. A non-null value is required by that ABI to be a function with
22663+ // this exact signature.
22664+ let hook = unsafe { core::mem::transmute::<*mut c_void, ArgpVersionHook>(hook) };
22665+ unsafe { hook(stream, state) };
22666+ return true;
22667+ }
22668+
22669+ let version = unsafe { crate::glibc_internal_abi::argp_program_version };
22670+ let Some(version) = (unsafe { argp_read_text(version) }) else {
22671+ return false;
22672+ };
22673+ unsafe { argp_write_text_line(stream, &version) }
22674+ }
22675+
22676+ unsafe fn argp_parse_version_requested(argc: c_int, argv: *mut *mut c_char) -> bool {
22677+ for index in 1..argc as usize {
22678+ let arg = unsafe { *argv.add(index) };
22679+ if let Some(arg) = unsafe { argp_read_text(arg.cast_const()) }
22680+ && arg == b"--version"
22681+ {
22682+ return true;
22683+ }
22684+ }
22685+ false
22686+ }
22687+
2264922688/// `argp_parse` — parse arguments using argp framework.
2265022689///
2265122690/// Native phase-1 support handles the common zeroed `struct argp` case as a
22652- /// successful no-op parse, matching glibc's behavior for empty parsers .
22691+ /// successful no-op parse and its GNU `--version` built-in .
2265322692#[cfg_attr(not(debug_assertions), unsafe(no_mangle))]
2265422693pub unsafe extern "C" fn argp_parse(
2265522694 argp: *const c_void,
2265622695 argc: c_int,
2265722696 argv: *mut *mut c_char,
22658- _flags : libc::c_uint,
22697+ flags : libc::c_uint,
2265922698 arg_index: *mut c_int,
22660- _input : *mut c_void,
22699+ input : *mut c_void,
2266122700) -> c_int {
2266222701 if argp.is_null() || argc < 0 || (argc > 0 && argv.is_null()) {
2266322702 unsafe { set_abi_errno(libc::EINVAL) };
@@ -22666,6 +22705,22 @@ pub unsafe extern "C" fn argp_parse(
2266622705
2266722706 let header = unsafe { &*(argp as *const ArgpHeader) };
2266822707 if header.is_empty() {
22708+ let version = unsafe { crate::glibc_internal_abi::argp_program_version };
22709+ let version_hook = unsafe { crate::glibc_internal_abi::argp_program_version_hook };
22710+ let version_available = !version.is_null() || !version_hook.is_null();
22711+ if version_available && unsafe { argp_parse_version_requested(argc, argv) } {
22712+ let stream = unsafe { crate::stdio_abi::stdout }.cast::<libc::FILE>();
22713+ if !unsafe { argp_write_version(stream, input) } {
22714+ unsafe { set_abi_errno(libc::EIO) };
22715+ }
22716+ if !arg_index.is_null() {
22717+ unsafe { *arg_index = argc };
22718+ }
22719+ if flags & ARGP_NO_EXIT == 0 {
22720+ unsafe { crate::stdlib_abi::exit(0) };
22721+ }
22722+ return 0;
22723+ }
2266922724 if !arg_index.is_null() {
2267022725 unsafe { *arg_index = argc.min(1) };
2267122726 }
@@ -22715,7 +22770,7 @@ pub unsafe extern "C" fn argp_usage(state: *mut c_void) {
2271522770 unsafe { argp_state_help(state, core::ptr::null_mut(), ARGP_HELP_STD_USAGE_PHASE1) };
2271622771}
2271722772
22718- /// `argp_error` — report a bounded formatted parsing diagnostic to state error stream .
22773+ /// `argp_error` — report a bounded formatted parsing diagnostic and exit unless suppressed .
2271922774#[cfg_attr(not(debug_assertions), unsafe(no_mangle))]
2272022775pub unsafe extern "C" fn argp_error(state: *mut c_void, fmt: *const c_char, mut args: ...) {
2272122776 if unsafe { argp_diagnostic_stream(state) }.is_null() {
@@ -22734,13 +22789,16 @@ pub unsafe extern "C" fn argp_error(state: *mut c_void, fmt: *const c_char, mut
2273422789 if !unsafe { argp_write_diagnostic(state, &rendered, 0) } {
2273522790 unsafe { set_abi_errno(libc::EIO) };
2273622791 }
22792+ let state = unsafe { &*(state as *const ArgpStateHeader) };
22793+ let status = unsafe { crate::glibc_internal_abi::argp_err_exit_status };
22794+ unsafe { argp_exit_unless_suppressed(state, status) };
2273722795}
2273822796
22739- /// `argp_failure` — report a bounded formatted parsing failure diagnostic.
22797+ /// `argp_failure` — report a bounded formatted parsing failure diagnostic and exit when requested .
2274022798#[cfg_attr(not(debug_assertions), unsafe(no_mangle))]
2274122799pub unsafe extern "C" fn argp_failure(
2274222800 state: *mut c_void,
22743- _status : c_int,
22801+ status : c_int,
2274422802 errnum: c_int,
2274522803 fmt: *const c_char,
2274622804 mut args: ...
@@ -22761,6 +22819,10 @@ pub unsafe extern "C" fn argp_failure(
2276122819 if !unsafe { argp_write_diagnostic(state, &rendered, errnum) } {
2276222820 unsafe { set_abi_errno(libc::EIO) };
2276322821 }
22822+ if status != 0 {
22823+ let state = unsafe { &*(state as *const ArgpStateHeader) };
22824+ unsafe { argp_exit_unless_suppressed(state, status) };
22825+ }
2276422826}
2276522827
2276622828/// `argp_state_help` — print bounded phase-1 help from state.
0 commit comments