Migrate truncate_at_nul to common and write some tests

This encapsulates a common pattern of truncating a wstr at its first NUL
character.
This commit is contained in:
ridiculousfish 2024-01-07 13:43:31 -08:00
parent 29bd6eebd0
commit 9aa5a97530
5 changed files with 27 additions and 18 deletions

View file

@ -370,14 +370,6 @@ impl Named for BuiltinData {
} }
} }
/// Helper function to convert Vec<WString> to Vec<&wstr>, truncating on NUL.
/// We truncate on NUL for backwards-compatibility reasons.
/// This used to be passed as c-strings (`wchar_t *`),
/// and so we act like it for now.
pub fn truncate_at_nul(s: &wstr) -> &wstr {
&s[..s.chars().position(|c| c == '\x00').unwrap_or(s.len())]
}
fn builtin_lookup(name: &wstr) -> Option<&'static BuiltinData> { fn builtin_lookup(name: &wstr) -> Option<&'static BuiltinData> {
get_by_sorted_name(name, BUILTIN_DATAS) get_by_sorted_name(name, BUILTIN_DATAS)
} }

View file

@ -1162,6 +1162,15 @@ pub fn str2wcstring(inp: &[u8]) -> WString {
result result
} }
/// Given an input string, return a prefix of the string up to the first NUL character,
/// or the entire string if there is no NUL character.
pub fn truncate_at_nul(input: &wstr) -> &wstr {
match input.chars().position(|c| c == '\0') {
Some(nul_pos) => &input[..nul_pos],
None => input,
}
}
pub fn cstr2wcstring(input: &[u8]) -> WString { pub fn cstr2wcstring(input: &[u8]) -> WString {
let strlen = input.iter().position(|c| *c == b'\0').unwrap(); let strlen = input.iter().position(|c| *c == b'\0').unwrap();
str2wcstring(&input[0..strlen]) str2wcstring(&input[0..strlen])

View file

@ -4,12 +4,12 @@
// performed have been massive. // performed have been massive.
use crate::builtins::shared::{ use crate::builtins::shared::{
builtin_run, truncate_at_nul, STATUS_CMD_ERROR, STATUS_CMD_OK, STATUS_CMD_UNKNOWN, builtin_run, STATUS_CMD_ERROR, STATUS_CMD_OK, STATUS_CMD_UNKNOWN, STATUS_NOT_EXECUTABLE,
STATUS_NOT_EXECUTABLE, STATUS_READ_TOO_MUCH, STATUS_READ_TOO_MUCH,
}; };
use crate::common::{ use crate::common::{
exit_without_destructors, scoped_push_replacer, str2wcstring, wcs2string, wcs2zstring, exit_without_destructors, scoped_push_replacer, str2wcstring, truncate_at_nul, wcs2string,
write_loop, ScopeGuard, wcs2zstring, write_loop, ScopeGuard,
}; };
use crate::env::{EnvMode, EnvStack, Environment, Statuses, READ_BYTE_LIMIT}; use crate::env::{EnvMode, EnvStack, Environment, Statuses, READ_BYTE_LIMIT};
use crate::env_dispatch::use_posix_spawn; use crate::env_dispatch::use_posix_spawn;

View file

@ -5,13 +5,13 @@ use crate::ast::{
}; };
use crate::builtins; use crate::builtins;
use crate::builtins::shared::{ use crate::builtins::shared::{
builtin_exists, truncate_at_nul, BUILTIN_ERR_VARNAME, STATUS_CMD_ERROR, STATUS_CMD_OK, builtin_exists, BUILTIN_ERR_VARNAME, STATUS_CMD_ERROR, STATUS_CMD_OK, STATUS_CMD_UNKNOWN,
STATUS_CMD_UNKNOWN, STATUS_EXPAND_ERROR, STATUS_ILLEGAL_CMD, STATUS_INVALID_ARGS, STATUS_EXPAND_ERROR, STATUS_ILLEGAL_CMD, STATUS_INVALID_ARGS, STATUS_NOT_EXECUTABLE,
STATUS_NOT_EXECUTABLE, STATUS_UNMATCHED_WILDCARD, STATUS_UNMATCHED_WILDCARD,
}; };
use crate::common::{ use crate::common::{
escape, scoped_push_replacer, should_suppress_stderr_for_tests, valid_var_name, ScopeGuard, escape, scoped_push_replacer, should_suppress_stderr_for_tests, truncate_at_nul,
ScopeGuarding, valid_var_name, ScopeGuard, ScopeGuarding,
}; };
use crate::complete::CompletionList; use crate::complete::CompletionList;
use crate::env::{EnvMode, EnvStackSetResult, EnvVar, EnvVarFlags, Environment, Statuses}; use crate::env::{EnvMode, EnvStackSetResult, EnvVar, EnvVarFlags, Environment, Statuses};

View file

@ -1,5 +1,6 @@
use crate::common::{ use crate::common::{
cstr2wcstring, format_llong_safe, format_size_safe, scoped_push, ScopeGuard, ScopeGuarding, cstr2wcstring, format_llong_safe, format_size_safe, scoped_push, truncate_at_nul, ScopeGuard,
ScopeGuarding,
}; };
use crate::wchar::prelude::*; use crate::wchar::prelude::*;
@ -132,3 +133,10 @@ fn test_format() {
unsafe { libc::snprintf(buff2.as_mut_ptr().cast(), 128, "%ld\0".as_ptr().cast(), q) }; unsafe { libc::snprintf(buff2.as_mut_ptr().cast(), 128, "%ld\0".as_ptr().cast(), q) };
assert_eq!(cstr2wcstring(&buff1), cstr2wcstring(&buff2)); assert_eq!(cstr2wcstring(&buff1), cstr2wcstring(&buff2));
} }
#[test]
fn test_truncate_at_nul() {
assert_eq!(truncate_at_nul(L!("abc\0def")), L!("abc"));
assert_eq!(truncate_at_nul(L!("abc")), L!("abc"));
assert_eq!(truncate_at_nul(L!("\0abc")), L!(""));
}