diff --git a/README.md b/README.md index 7f6ab52..a6447d4 100644 --- a/README.md +++ b/README.md @@ -14,32 +14,24 @@ This package implements escaping for [GNU Bash][gnu-bash], [Z Shell][z-shell], [z-shell]: https://zsh.sourceforge.io/ [fish]: https://fishshell.com/ -Inspired by the Haskell [shell-escape][] package. - -[shell-escape]: https://github.com/solidsnack/shell-escape - -## Compatibility - -[`Sh`] can serve as a lowest common denominator for Bash, Z Shell, and -`/bin/sh`-like shells like Dash. However, fish's quoting rules are different -enough that you must use [`Fish`] for fish scripts. +It can take as input many different string and byte string types: -## Feature flags +- [`&str`] and [`String`] +- [`&bstr::BStr`][`bstr::BStr`] and [`bstr::BString`] +- [`&[u8]`][`slice`] and [`Vec`] +- [`&OsStr`][`OsStr`] and [`OsString`] (on UNIX) +- [`&Path`][`Path`] and [`PathBuf`] -The following are all enabled by default: +and produce output as (or push into) the following types: -- `bstr`: Support [`bstr::BStr`] and [`bstr::BString`]. -- `bash`: Support [Bash][gnu-bash] and [Z Shell][z-shell]. -- `fish`: Support [fish][]. -- `sh`: Support `/bin/sh`-like shells including [Dash][dash]. +- [`String`] (for shells that support it, i.e. not [`Sh`]/[`Dash`]) +- [`bstr::BString`] +- [`Vec`] +- [`OsString`] (on UNIX) -To limit support to specific shells, you must disable this crate's default -features in `Cargo.toml` and re-enable those you want. For example: +Inspired by the Haskell [shell-escape][] package. -```toml -[dependencies] -shell-quote = { version = "*", default-features = false, features = ["bash"] } -``` +[shell-escape]: https://github.com/solidsnack/shell-escape ## Examples @@ -67,12 +59,12 @@ It's also possible to use the extension trait [`QuoteRefExt`] which provides a ```rust use shell_quote::{Bash, Sh, Fish, QuoteRefExt}; -let quoted: Vec = "foo bar".quoted(Bash); -assert_eq!(quoted, b"$'foo bar'"); +let quoted: String = "foo bar".quoted(Bash); +assert_eq!(quoted, "$'foo bar'"); let quoted: Vec = "foo bar".quoted(Sh); assert_eq!(quoted, b"foo' bar'"); -let quoted: Vec = "foo bar".quoted(Fish); -assert_eq!(quoted, b"foo' bar'"); +let quoted: String = "foo bar".quoted(Fish); +assert_eq!(quoted, "foo' bar'"); ``` Or the extension trait [`QuoteExt`] for pushing quoted strings into a buffer: @@ -85,3 +77,29 @@ script.extend(b" > "); script.push_quoted(Bash, "/path/(to)/[output]"); assert_eq!(script, "echo $'foo bar' > $'/path/(to)/[output]'"); ``` + +## Compatibility + +[`Sh`] can serve as a lowest common denominator for Bash, Z Shell, and +`/bin/sh`-like shells like Dash. However, fish's quoting rules are different +enough that you must use [`Fish`] for fish scripts. + +Note that using [`Sh`] as a lowest common denominator brings with it other +issues; read its documentation carefully to understand the limitations. + +## Feature flags + +The following are all enabled by default: + +- `bstr`: Support [`bstr::BStr`] and [`bstr::BString`]. +- `bash`: Support [Bash][gnu-bash] and [Z Shell][z-shell]. +- `fish`: Support [fish][]. +- `sh`: Support `/bin/sh`-like shells including [Dash][dash]. + +To limit support to specific shells, you must disable this crate's default +features in `Cargo.toml` and re-enable those you want. For example: + +```toml +[dependencies] +shell-quote = { version = "*", default-features = false, features = ["bash"] } +``` diff --git a/src/sh.rs b/src/sh.rs index d04bdbf..3450619 100644 --- a/src/sh.rs +++ b/src/sh.rs @@ -4,6 +4,21 @@ use crate::{ascii::Char, Quotable, QuoteInto}; /// Quote byte strings for use with `/bin/sh`. /// +/// # ⚠️ Warning +/// +/// There is no escape sequence for bytes between 0x80 and 0xFF – these must be +/// reproduced exactly in the quoted output – hence **it is not possible to +/// safely create or quote into an existing [`String`]** with [`Sh`] because +/// these bytes would be misinterpreted as a second or subsequent byte of a +/// [multi-byte UTF-8 code point representation][utf-8-encoding]. +/// +/// [utf-8-encoding]: https://en.wikipedia.org/wiki/UTF-8#Encoding +/// +/// If you're not using bytes between 0x80 and 0xFF, a workaround is to instead +/// quote into a [`Vec`] and convert that into a string using +/// [`String::from_utf8`]. The key difference is that `from_utf8` returns a +/// [`Result`] which the caller must deal with. +/// /// # Compatibility /// /// Quoted/escaped strings produced by [`Sh`] also work in Bash, Dash, and Z