55
66// spell-checker:ignore (paths) GPGHome findxs
77
8- use clap:: { Arg , ArgAction , ArgMatches , Command , builder:: ValueParser } ;
8+ use clap:: builder:: { TypedValueParser , ValueParserFactory } ;
9+ use clap:: { Arg , ArgAction , ArgMatches , Command } ;
910use uucore:: display:: { Quotable , println_verbatim} ;
1011use uucore:: error:: { FromIo , UError , UResult , UUsageError } ;
1112use uucore:: format_usage;
@@ -110,9 +111,18 @@ pub struct Options {
110111impl Options {
111112 fn from ( matches : & ArgMatches ) -> Self {
112113 let tmpdir = matches
113- . get_one :: < PathBuf > ( OPT_TMPDIR )
114- . or_else ( || matches. get_one :: < PathBuf > ( OPT_P ) )
115- . cloned ( ) ;
114+ . get_one :: < Option < PathBuf > > ( OPT_TMPDIR )
115+ . or_else ( || matches. get_one :: < Option < PathBuf > > ( OPT_P ) )
116+ . map ( |dir| match dir {
117+ // If the argument of -p/--tmpdir is non-empty, use it as the
118+ // tmpdir.
119+ Some ( d) => d. clone ( ) ,
120+ // Otherwise use $TMPDIR if set, else use the system's default
121+ // temporary directory.
122+ None => env:: var ( TMPDIR_ENV_VAR )
123+ . ok ( )
124+ . map_or_else ( env:: temp_dir, PathBuf :: from) ,
125+ } ) ;
116126 let ( tmpdir, template) = match matches. get_one :: < String > ( ARG_TEMPLATE ) {
117127 // If no template argument is given, `--tmpdir` is implied.
118128 None => {
@@ -274,6 +284,49 @@ impl Params {
274284 }
275285}
276286
287+ /// Custom parser that converts empty string to `None`, and non-empty string to
288+ /// `Some(PathBuf)`.
289+ ///
290+ /// This parser is used for the `-p` and `--tmpdir` options where an empty string
291+ /// argument should be treated as "not provided", causing mktemp to fall back to
292+ /// using the `$TMPDIR` environment variable or the system's default temporary
293+ /// directory.
294+ ///
295+ /// # Examples
296+ ///
297+ /// - Empty string `""` -> `None`
298+ /// - Non-empty string `"/tmp"` -> `Some(PathBuf::from("/tmp"))`
299+ ///
300+ /// This handles the special case where users can pass an empty directory name
301+ /// to explicitly request fallback behavior.
302+ #[ derive( Clone , Debug ) ]
303+ struct OptionalPathBufParser ;
304+
305+ impl TypedValueParser for OptionalPathBufParser {
306+ type Value = Option < PathBuf > ;
307+
308+ fn parse_ref (
309+ & self ,
310+ _cmd : & Command ,
311+ _arg : Option < & Arg > ,
312+ value : & OsStr ,
313+ ) -> Result < Self :: Value , clap:: Error > {
314+ if value. is_empty ( ) {
315+ Ok ( None )
316+ } else {
317+ Ok ( Some ( PathBuf :: from ( value) ) )
318+ }
319+ }
320+ }
321+
322+ impl ValueParserFactory for OptionalPathBufParser {
323+ type Parser = Self ;
324+
325+ fn value_parser ( ) -> Self :: Parser {
326+ Self
327+ }
328+ }
329+
277330#[ uucore:: main]
278331pub fn uumain ( args : impl uucore:: Args ) -> UResult < ( ) > {
279332 let args: Vec < _ > = args. collect ( ) ;
@@ -376,7 +429,7 @@ pub fn uu_app() -> Command {
376429 . help ( translate ! ( "mktemp-help-p" ) )
377430 . value_name ( "DIR" )
378431 . num_args ( 1 )
379- . value_parser ( ValueParser :: path_buf ( ) )
432+ . value_parser ( OptionalPathBufParser )
380433 . value_hint ( clap:: ValueHint :: DirPath ) ,
381434 )
382435 . arg (
@@ -390,7 +443,7 @@ pub fn uu_app() -> Command {
390443 // Require an equals to avoid ambiguity if no tmpdir is supplied
391444 . require_equals ( true )
392445 . overrides_with ( OPT_P )
393- . value_parser ( ValueParser :: path_buf ( ) )
446+ . value_parser ( OptionalPathBufParser )
394447 . value_hint ( clap:: ValueHint :: DirPath ) ,
395448 )
396449 . arg (
0 commit comments