1#! /usr/bin/env modernish 2#! use safe -k 3#! use var/loop 4 5# Test and demonstration program for shellquote(). 6# See README.md under "Low-level shell utilities" -> "shellquote" for more info. 7# 8# This program includes an -N option for trying the current shell's builtin 9# quoting algorithm. Its output is not always portable, and it's generally 10# *much* worse at minimising exponential growth when quoting multiple times. 11 12PATH=$DEFPATH # use standard utilities, esp. 'tput' 13 14showusage() { 15 putln "usage: ${ME##*/} [ -n DEPTHLEVEL ] [ -f ] [ -P | -N ] [ STRING ]" 16} 17 18# Parse options. 19force='' method='' level=6 20while getopts n:fPN opt; do 21 case $opt in 22 ( n ) level=$OPTARG ;; # Number of times to quote 23 ( f ) force='-f' ;; # Force quoting shell-safe strings 24 ( P ) method='-P' ;; # Portable POSIX quoting (no $CC*) 25 ( N ) method=native ;; # Use shell's native algorithm 26 ( * ) exit -u 1 ;; # 'exit -u' calls showusage() 27 esac 28done 29shift $((OPTIND-1)) 30str isint $level || exit -u 1 "bad number: $level" 31 32# Set the string to quote. 33if let "$#"; then 34 # "$*" separates all arguments with the first character of IFS. 35 # But in the safe mode, IFS is emptied to disable global field 36 # splitting, so there would be no separator. 37 push IFS; IFS=' '; quotestring="$*"; pop IFS 38else 39 quotestring='Let`s \see hôw modernish shellquote() 40 "handles" '\''quoting'\'' $of '${CCv}'`weird` multi#line \$strings\\. 41 (To try another string, specify one on the command line.)\' 42fi 43quotestring_orig=$quotestring 44 45# Quoted strings can get large, so make them easier to tell apart. 46if is onterminal 1; then 47 emphasis=$(tput md; tput setaf 1 2>/dev/null || tput rev) # bold & either red or reverse 48 reset=$(tput sgr0) 49else 50 emphasis='' reset='' 51fi 52 53# Quote the specified number of levels with specified options. 54LOOP for i=1 to level; DO 55 case $method in 56 ( native ) 57 # Set a dummy alias in a subshell and ask the shell to print 58 # it, quoting the value with its internal algorithm. 59 quotestring=$(alias Q=$quotestring; alias Q) 60 quotestring=${quotestring#*Q=} ;; 61 ( * ) 62 # Modernish shellquoting. 63 # (Due to the shell's empty removal mechanism, $force 64 # and $method below are skipped entirely if empty.) 65 shellquote $force $method quotestring ;; 66 esac 67 putln "${emphasis}q$i: [${#quotestring}]$reset $quotestring" "" 68DONE 69 70# Roll back the quoting and verify the results. 71LOOP for i=level-1 to 0; DO 72 eval quotestring=$quotestring || exit 73 putln "${emphasis}u$i: [${#quotestring}]$reset $quotestring" "" 74DONE 75str eq $quotestring $quotestring_orig && putln ok 76