├── README.md ├── examples ├── example1 ├── example2 └── example3 ├── sourcedialog └── tutorial ├── tut1 ├── tut2 ├── tut3 └── tut4 /README.md: -------------------------------------------------------------------------------- 1 | # SourceDialog 2 | 3 | SourceDialog is a script you can source from your own scripts to easily 4 | create TUI forms using only pure Bash. 5 | 6 | ![example of dialog](https://repository-images.githubusercontent.com/966361037/940581b7-edfc-48ca-a55a-5dc95aa3de30 "Source Dialog") 7 | 8 | I'm *not* the author of this tool but have used it a few times. As I can no longer 9 | find it anywhere online anymore, I decided to make a repo for it on GitHub. 10 | 11 | ## License 12 | 13 | Public Domain 14 | 15 | ## History / Credits 16 | 17 | Antonio Macchi introduced the tool with the following message entitled `bash - dialog boxes in mixed 18 | form` in comp.os.linux.development.apps on 2008-11-07 19 | 20 | ``` 21 | Hi, 22 | I have written a software that permits to put some objects (like 23 | buttons, inputboxes and lists) freely around the screen, and interact 24 | with it in a simple manner 25 | 26 | 27 | It consists in a 20K-file, included in a bash-script using 'source' builtin 28 | So I have called it 'SourceDialog' 29 | Using this approach, became possible to interact with user-defined 30 | variables and functions 31 | 32 | 33 | If someone wants to take-a-look... 34 | www.webalice.it/antonio_macchi/SourceDialog.tar.bz2 35 | 36 | Every feedback, suggestion, bug and insult are welcome. 37 | 38 | Thanks for your attention 39 | bye 40 | ``` 41 | -------------------------------------------------------------------------------- /examples/example1: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | . ../sourcedialog 4 | 5 | array=( "Linux The Great Unix Clone for 386/486" \ 6 | "NetBSD Another free Unix Clone for 386/486" \ 7 | "OS/2 IBM OS/2" \ 8 | "WIN NT Microsoft Windows NT" \ 9 | "PCDOS IBM PC DOS" \ 10 | "MSDOS Microsoft DOS" ) 11 | comment= 12 | 13 | 14 | sd_load_canvas name=cvmain x=13 y=4 width=51 height=16 15 | sd_load_textbox name=tbtext x=15 y=5 text="Choose the OS you like" 16 | sd_load_frame name=cvos x=15 y=6 width=47 height=6 17 | sd_load_menubox name=mbos x=17 y=7 width=43 height=4 arrayname=array 18 | sd_load_textbox name=tbwhy x=15 y=13 text="Your comment here..." 19 | sd_load_frame name=frcomm x=15 y=14 width=47 height=3 20 | sd_load_inputbox name=ibcomm x=16 y=15 width=45 varname=comment 21 | sd_load_pushbutton name=pbok x=27 y=18 caption=" OK " 22 | sd_load_pushbutton name=pbcancel x=42 y=18 caption="Cancel" 23 | 24 | sd_pbok_push () { index=$sd_mbos_ilight; return 0; } 25 | sd_pbcancel_push () { return 1; } 26 | 27 | 28 | sd_start; retval=$? 29 | clear 30 | case $retval in 31 | 27) echo "ESC pressed." ;; 32 | 1) echo "Cancel pressed." ;; 33 | 0) 34 | echo "${array[$index]} chosen." 35 | echo 36 | echo "comment: $comment" 37 | ;; 38 | esac 39 | 40 | -------------------------------------------------------------------------------- /examples/example2: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | . ../sourcedialog 4 | 5 | firstname= 6 | lastname= 7 | street= 8 | city= 9 | state= 10 | zip= 11 | country= 12 | phone1= 13 | phone2= 14 | phone3= 15 | ext= 16 | mail= 17 | 18 | 19 | sd_load_canvas name=cvmain x=4 y=1 width=70 height=21 20 | sd_load_textbox name=tbtop x=28 y=2 text="Tell us about yourself" 21 | sd_load_textbox name=tbfirst x=6 y=4 text="First Name:" 22 | sd_load_inputbox name=ibfirst x=18 y=4 width=54 varname=firstname 23 | sd_load_textbox name=tblast x=6 y=6 text="Last Name:" 24 | sd_load_inputbox name=iblast x=17 y=6 width=55 varname=lastname 25 | sd_load_textbox name=tbstreet x=6 y=8 text="Street address:" 26 | sd_load_inputbox name=ibstreet x=22 y=8 width=50 varname=street 27 | sd_load_textbox name=tbcity x=6 y=10 text="City:" 28 | sd_load_inputbox name=ibcity x=12 y=10 width=60 varname=city 29 | sd_load_textbox name=tbstate x=6 y=12 text="State Province:" 30 | sd_load_inputbox name=ibstate x=22 y=12 width=15 varname=state 31 | sd_load_textbox name=tbzip x=39 y=12 text="ZIP / Postal code:" 32 | sd_load_inputbox name=ibzip x=58 y=12 width=14 varname=zip 33 | sd_load_textbox name=tbcountry x=6 y=14 text="Country:" 34 | sd_load_inputbox name=ibcountry x=15 y=14 width=57 varname=country 35 | sd_load_textbox name=tbphone x=6 y=16 text="Telephone number:" 36 | sd_load_inputbox name=ibphone1 x=24 y=16 width=10 varname=phone1 37 | sd_load_textbox name=tbdash1 x=35 y=16 text="-" 38 | sd_load_inputbox name=ibphone2 x=37 y=16 width=10 varname=phone2 39 | sd_load_textbox name=tbdash2 x=48 y=16 text="-" 40 | sd_load_inputbox name=ibphone3 x=50 y=16 width=10 varname=phone3 41 | sd_load_textbox name=tbext x=61 y=16 text="ext.:" 42 | sd_load_inputbox name=ibext x=67 y=16 width=5 varname=ext 43 | sd_load_textbox name=tbmail x=6 y=18 text="Email address:" 44 | sd_load_inputbox name=ibmail x=21 y=18 width=51 varname=mail 45 | sd_load_pushbutton name=pbregister x=34 y=20 caption=" Register " 46 | 47 | sd_pbregister_push () { return 0; } 48 | 49 | 50 | sd_start; retval=$? 51 | clear 52 | if test $retval = 27; then 53 | echo ESC pressed. 54 | else 55 | echo "First name: $firstname" 56 | echo "Last name: $lastname" 57 | echo "Street address: $street" 58 | echo "City: $city" 59 | echo "State: $state" 60 | echo "ZIP: $zip" 61 | echo "Country: $country" 62 | echo "Phone: ${phone1}-${phone2}-${phone3} ext.:$ext" 63 | echo "Email: $mail" 64 | fi 65 | 66 | -------------------------------------------------------------------------------- /examples/example3: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | . ../sourcedialog 4 | 5 | array_loc=( --- \ 6 | Afghanistan \ 7 | Albania \ 8 | Algeria \ 9 | "American Samoa" \ 10 | Andorra \ 11 | Angola \ 12 | Anguilla \ 13 | Antarctica \ 14 | "Atigua and Barbuda" \ 15 | Argentina \ 16 | Armenia \ 17 | Aruba \ 18 | Australia \ 19 | Austria \ 20 | Azerbijan \ 21 | Zambia \ 22 | Zimbabwe ) 23 | 24 | array_month=( --- \ 25 | January \ 26 | February \ 27 | March \ 28 | April \ 29 | May \ 30 | June \ 31 | July \ 32 | August \ 33 | September \ 34 | October \ 35 | November \ 36 | December ) 37 | 38 | array_day=( -- 0{1..9} {10..31} ) 39 | eval array_year=( --- {1901..`date +%Y`} ) 40 | array_gender=( Male Female ) 41 | array_opts=( "Let others find my channel if they have my email address" \ 42 | "I agree to the Terms of Use and Privacy Policy." ) 43 | index_opts[0]=${array_opts[0]} 44 | password= 45 | repassword= 46 | 47 | 48 | sd_load_canvas name=cvmain x=4 y=1 width=70 height=21 \ 49 | caption=" CREATE YOUR ACCOUNT " 50 | sd_load_textbox name=tbmail x=9 y=3 text="Email Address: " 51 | sd_load_inputbox name=ibmail x=24 y=3 width=45 varname=mail 52 | sd_load_textbox name=tbpassword x=14 y=4 text="Password: " 53 | sd_load_passwordbox name=pbpassword x=24 y=4 width=45 varname=password 54 | sd_load_textbox name=tbrepassword x=6 y=5 text="Re-type Password: " 55 | sd_load_passwordbox name=pbrepassword x=24 y=5 width=45 varname=repassword 56 | sd_load_textbox name=tbuser x=14 y=6 text="Username: " 57 | sd_load_inputbox name=ibuser x=24 y=6 width=45 varname=username 58 | sd_load_textbox name=tblocation x=13 y=8 text="Location: " 59 | sd_load_frame name=frlocation x=24 y=7 width=45 height=3 60 | sd_load_menubox name=mblocation x=25 y=8 width=43 arrayname=array_loc 61 | sd_load_textbox name=tbdate x=8 y=11 text="Date of Birth: " 62 | sd_load_frame name=frmonth x=24 y=10 width=11 height=3 63 | sd_load_menubox name=mbmonth x=25 y=11 width=9 arrayname=array_month 64 | sd_load_frame name=frday x=35 y=10 width=4 height=3 65 | sd_load_menubox name=mbday x=36 y=11 width=2 arrayname=array_day 66 | sd_load_frame name=fryear x=39 y=10 width=6 height=3 67 | sd_load_menubox name=mbyear x=40 y=11 width=4 arrayname=array_year 68 | sd_load_textbox name=tbgender x=15 y=13 text="Gender: " 69 | sd_load_radiolist name=rlgender x=24 y=13 width=10 height=2 \ 70 | arrayname=array_gender indexname=index_gender 71 | sd_load_checklist name=clopts x=8 y=16 width=65 height=2 \ 72 | arrayname=array_opts indexname=index_opts 73 | sd_load_pushbutton name=pbcreate x=30 y=20 caption="Create my account" 74 | 75 | 76 | sd_pbcreate_push () { 77 | ilocation=$sd_mblocation_ilight 78 | imonth=$sd_mbmonth_ilight 79 | iday=$sd_mbday_ilight 80 | iyear=$sd_mbday_ilight 81 | return 0; 82 | } 83 | 84 | 85 | sd_start; retval=$? 86 | clear 87 | if test $retval = 27; then 88 | echo ESC pressed. 89 | else 90 | echo Email: $mail 91 | echo Password: $password - $repassword 92 | echo Usernane: $username 93 | echo Location: ${array_loc[$ilocation]} 94 | echo Date: ${array_month[$imonth]}-${array_day[$iday]}-${array_year[$iyear]} 95 | echo Gender: ${index_gender[*]} 96 | for opt in "${index_opts[@]}"; do echo $opt; done 97 | fi 98 | -------------------------------------------------------------------------------- /sourcedialog: -------------------------------------------------------------------------------- 1 | #!/no/bash # only for colours 2 | 3 | # 4 | # author : Antonio Macchi 5 | # license : Public Domain 6 | # mail : antonio_macchi@alice.it 7 | # 8 | 9 | 10 | 11 | ###################################################################### 12 | # terminal escape sequences hardcoded 13 | # 14 | # comment out this if-construct to use original tput command 15 | # anyhow, this should works fine for nearly every terminal 16 | # moreover, original tput on some terminals fails 17 | # 18 | # for example, on an Eterm, this command doesn't work 19 | # $ printf "smacs\nacsc\nrmacs" | tput -S 20 | # while (on an Eterm again) this command works fine 21 | # $ printf "smacs\nacsc\nrmacs" | tput -S -T xterm 22 | # 23 | # assumption: 24 | # every non-linux terminal seems works fine using xterm sequences 25 | ###################################################################### 26 | 27 | if test "$TERM" == linux; then 28 | tput () { 29 | case $1 in 30 | acsc) echo -n +$'\020'\,$'\021'-$'\030'.$'\031'0$'\333'\`$'\004'a$'\261'f$'\370'g$'\361'h$'\260'i$'\316'j$'\331'k$'\277'l$'\332'm$'\300'n$'\305'o~p$'\304'q$'\304'r$'\304's_t$'\303'u$'\264'v$'\301'w$'\302'x$'\263'y$'\363'z$'\362'\{$'\343'\|$'\330'\}$'\234'~$'\376' ;; # $ printf "%q" `tput acsc -T linux` 31 | bold) echo -en "\e[1m" ;; 32 | civis) echo -en "\e[?25l\e[?1c" ;; 33 | cnorm) echo -en "\e[?25h\e[?0c" ;; 34 | cup) echo -en "\e[$(($2 + 1));$(($3 + 1))H" ;; 35 | ht) echo -en "\0011" ;; 36 | kbs) echo -en "\0177" ;; 37 | kcbt) echo -en "\e[Z" ;; 38 | kcub1) echo -en "\e[D" ;; 39 | kcud1) echo -en "\e[B" ;; 40 | kcuf1) echo -en "\e[C" ;; 41 | kcuu1) echo -en "\e[A" ;; 42 | kend) echo -en "\e[4~" ;; 43 | khome) echo -en "\e[1~" ;; 44 | knp) echo -en "\e[6~" ;; 45 | kpp) echo -en "\e[5~" ;; 46 | rmacs) echo -en "\e[10m" ;; 47 | rmkx) echo -en "" ;; 48 | setab) echo -en "\e[4$2m" ;; 49 | setaf) echo -en "\e[3$2m" ;; 50 | sgr0) echo -en "\e[0;10m" ;; 51 | smacs) echo -en "\e[11m" ;; 52 | smkx) echo -en "" ;; 53 | esac 54 | } 55 | else 56 | tput () { 57 | case $1 in 58 | acsc) echo -en "``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~" ;; 59 | bold) echo -en "\e[1m" ;; 60 | civis) echo -en "\e[?25l" ;; 61 | cnorm) echo -en "\e[?12l\e[?25h" ;; 62 | cup) echo -en "\e[$(($2 + 1));$(( $3 + 1))H" ;; 63 | ht) echo -en "\0011" ;; 64 | kbs) echo -en "\0177" ;; 65 | kcbt) echo -en "\e[Z" ;; 66 | kcub1) echo -en "\eOD" ;; 67 | kcud1) echo -en "\eOB" ;; 68 | kcuf1) echo -en "\eOC" ;; 69 | kcuu1) echo -en "\eOA" ;; 70 | kend) echo -en "\e[OF" ;; 71 | khome) echo -en "\e[OH" ;; 72 | knp) echo -en "\e[6~" ;; 73 | kpp) echo -en "\e[5~" ;; 74 | rmacs) echo -en "\e(B" ;; 75 | rmkx) echo -en "\e[?1l\e>" ;; 76 | setab) echo -en "\e[4$2m" ;; 77 | setaf) echo -en "\e[3$2m" ;; 78 | sgr0) echo -en "\e[m\e(B" ;; 79 | smacs) echo -en "\e(0" ;; 80 | smkx) echo -en "\e[?1h\e=" ;; 81 | esac 82 | } 83 | fi 84 | 85 | 86 | ###################################################################### 87 | 88 | 89 | # 90 | # global variable 91 | # 92 | 93 | unset sd_names 94 | 95 | 96 | # 97 | # Primary functions 98 | # 99 | 100 | 101 | sd_start () { 102 | # unfortunately, local variables in bash are not completely local as in C 103 | # so, to be safe, I'll use sd_ prefix for local variables too. 104 | local sd_retval= 105 | 106 | sd_init 107 | sd_draw 108 | sd_read; sd_retval=$? 109 | sd_reset 110 | return $sd_retval 111 | } 112 | 113 | 114 | sd_init () { 115 | stty -echo 116 | tput civis 117 | tput smkx # makes keybord escape sequences consistent for xterm too 118 | IFS=$'\n' 119 | } 120 | 121 | 122 | sd_reset () { 123 | IFS=$' \t\n' 124 | tput rmkx 125 | tput cnorm 126 | tput sgr0 127 | stty echo 128 | } 129 | 130 | 131 | sd_draw () { 132 | local sd_name= sd_type= 133 | 134 | tput setab 4 135 | clear 136 | 137 | for sd_name in ${sd_names[*]}; do 138 | eval sd_type=\$sd_${sd_name}_type 139 | eval sd_${sd_type}_draw $sd_name 140 | done 141 | } 142 | 143 | 144 | sd_read () { 145 | local sd_i=0 sd_max=${#sd_names[*]} 146 | local sd_direction=1 147 | local sd_name= sd_type= sd_retval= 148 | 149 | while true; do 150 | sd_name=${sd_names[$sd_i]} 151 | eval sd_type=\$sd_${sd_name}_type 152 | 153 | eval sd_${sd_type}_read $sd_name 2>/dev/null 154 | sd_retval=$? 155 | case $sd_retval in 156 | 127) : ;; 157 | 254) sd_direction=-1 ;; 158 | 255) sd_direction=1 ;; 159 | *) break ;; 160 | esac 161 | 162 | ((sd_i += sd_direction)) 163 | test $sd_i -lt 0 && sd_i=$((sd_max - 1)) 164 | test $sd_i -gt $sd_max && sd_i=0 165 | done 166 | return $sd_retval 167 | } 168 | 169 | 170 | sd_load () { 171 | # name, type, x, y 172 | # 173 | # canvas : width, height, caption, shadow, frame 174 | # textbox : width, height, text 175 | # inputbox : width, varname [password] 176 | # pushbutton: caption 177 | # listbox : width, height, arrayname, indexname, mark, multi, ilight, ifirst 178 | 179 | local sd_props=( "$@" ) 180 | local sd_name= sd_prop= sd_propname= sd_propvalue= 181 | 182 | until test ${1%=*} = name; do shift; done 183 | 184 | sd_name=${1#*=} 185 | sd_names[${#sd_names[*]}]=$sd_name 186 | 187 | for sd_prop in "${sd_props[@]}"; do 188 | sd_propname=${sd_prop%=*} 189 | sd_propvalue="${sd_prop#*=}" 190 | if test $sd_propname != name; then 191 | eval sd_${sd_name}_${sd_propname}=\"\$sd_propvalue\" 192 | fi 193 | done 194 | } 195 | 196 | sd_load_canvas () { sd_load "$@" type=canvas; } 197 | sd_load_frame () { sd_load "$@" type=canvas shadow=no frame=concave; } 198 | sd_load_textbox () { sd_load "$@" type=textbox; } 199 | sd_load_pushbutton () { sd_load "$@" type=pushbutton; } 200 | sd_load_inputbox () { sd_load "$@" type=inputbox; } 201 | sd_load_passwordbox () { sd_load "$@" type=inputbox password=yes; } 202 | sd_load_menubox () { sd_load "$@" type=listbox; } 203 | sd_load_checklist () { sd_load "$@" type=listbox mark=check multi=yes; } 204 | sd_load_radiolist () { sd_load "$@" type=listbox mark=radio multi=no; } 205 | 206 | 207 | # 208 | # sd_..._draw and sd_..._read functions 209 | # 210 | 211 | 212 | sd_canvas_read () { 213 | return 127 214 | } 215 | 216 | sd_canvas_draw () { # $1=name 217 | local sd_x= sd_y= sd_width= sd_height= sd_caption= 218 | local sd_shadow= sd_frame= 219 | local sd_x2= sd_y2= sd_xbefore= sd_xafter= 220 | local sd_color= sd_colorf1= sd_colorf2= 221 | local sd_jklmqx=( `sd_get_acsc_jklmqx` ) 222 | local sd_black="`tput sgr0; tput setab 0`" 223 | 224 | eval sd_x=\${sd_${1}_x:-0} 225 | eval sd_y=\${sd_${1}_y:-0} 226 | eval sd_width=\${sd_${1}_width:-2}; test $sd_width -lt 2 && sd_width=2 227 | eval sd_height=\${sd_${1}_height:-0} 228 | eval sd_caption=\"\$sd_${1}_caption\" 229 | eval sd_shadow=\${sd_${1}_shadow:-yes} 230 | eval sd_frame=\${sd_${1}_frame:-convex} 231 | 232 | sd_x2=$((sd_width - 2)) 233 | sd_caption="${sd_caption:0:${sd_x2}}" 234 | sd_xbefore=$(( (sd_x2 - ${#sd_caption}) / 2 )) 235 | sd_xafter=$(( sd_x2 - (sd_xbefore + ${#sd_caption}) )) 236 | 237 | sd_color=`tput sgr0; tput setaf 4; tput bold; tput setab 7` 238 | sd_colorf1=`tput sgr0; tput setaf 7; tput bold; tput setab 7; tput smacs` 239 | sd_colorf2=`tput sgr0; tput setaf 0; tput setab 7; tput smacs` 240 | test $sd_frame = concave && sd_swap sd_colorf1 sd_colorf2 241 | 242 | for (( sd_y2=0; sd_y2 < sd_height; sd_y2++ )); do 243 | tput cup $(( sd_y + sd_y2 )) $sd_x 244 | 245 | case $sd_y2 in 246 | 0) 247 | echo -n $sd_colorf1 248 | echo -n ${sd_jklmqx[2]} 249 | sd_repeat $sd_xbefore ${sd_jklmqx[4]} 250 | echo -n $sd_color 251 | echo -n "$sd_caption" 252 | echo -n $sd_colorf1 253 | sd_repeat $sd_xafter ${sd_jklmqx[4]} 254 | echo -n $sd_colorf2 255 | echo -n ${sd_jklmqx[1]} 256 | ;; 257 | 258 | $((sd_height-1))) 259 | echo -n $sd_colorf1 260 | echo -n ${sd_jklmqx[3]} 261 | echo -n $sd_colorf2 262 | sd_repeat $sd_x2 ${sd_jklmqx[4]} 263 | echo -n ${sd_jklmqx[0]} 264 | ;; 265 | 266 | *) 267 | echo -n $sd_colorf1 268 | echo -n ${sd_jklmqx[5]} 269 | echo -n $sd_color 270 | printf "%${sd_x2}s" 271 | echo -n $sd_colorf2 272 | echo -n ${sd_jklmqx[5]} 273 | ;; 274 | esac 275 | 276 | if test $sd_shadow = yes -a $sd_y2 -gt 0; then 277 | echo -n "$sd_black" 278 | echo -n " " 279 | fi 280 | done 281 | if test $sd_shadow = yes; then 282 | echo -n "$sd_black" 283 | tput cup $(($sd_y + $sd_height)) $(($sd_x + 2)) 284 | printf "%${sd_width}s" 285 | fi 286 | } 287 | 288 | 289 | sd_textbox_read () { 290 | return 127 291 | } 292 | 293 | 294 | # 295 | # '\n' = new line 296 | # more than one space will be collapsed in one 297 | # words larger than width will be partially lost 298 | # 299 | sd_textbox_draw () { # $1=name 300 | local sd_x= sd_y= sd_width= sd_height= 301 | local sd_text= 302 | local sd_y2= sd_x2= sd_word= 303 | 304 | eval sd_x=\${sd_${1}_x:-0} 305 | eval sd_y=\${sd_${1}_y:-0} 306 | eval sd_text=\"\$sd_${1}_text\" 307 | eval sd_width=\${sd_${1}_width:-${#sd_text}} 308 | eval sd_height=\${sd_${1}_height:-1} 309 | 310 | tput sgr0; tput setaf 0; tput setab 7 311 | 312 | while test $1; do shift; done 313 | if test "${sd_text// /}"; then 314 | sd_text="${sd_text//\\n/ $'\x01' }" 315 | set -- ${sd_text// /$'\n'} 316 | fi 317 | 318 | sd_nextraw () { 319 | printf "%$((sd_width - sd_x2))s" 320 | ((sd_x2=0, sd_y2++)) 321 | test $sd_y2 -ge $sd_height && return 1 322 | tput cup $((sd_y + sd_y2)) $((sd_x + sd_x2)) 323 | return 0 324 | } 325 | 326 | tput cup $sd_y $sd_x 327 | sd_y2=0; sd_x2=0 328 | while test $1; do 329 | sd_word=${1:0:$sd_width} 330 | if test $sd_word = $'\x01'; then 331 | sd_nextraw || break 332 | shift 333 | continue 334 | fi 335 | test $((${#sd_word} + sd_x2)) -gt $sd_width && ! sd_nextraw && break 336 | echo -n "$sd_word" 337 | sd_x2=$((sd_x2+${#sd_word})) 338 | if test $sd_x2 -lt $sd_width; then 339 | echo -n " " 340 | ((sd_x2++)) 341 | fi 342 | shift 343 | done 344 | test $sd_y2 -lt $sd_height && while sd_nextraw; do : ; done 345 | unset sd_nextraw 346 | } 347 | 348 | 349 | # 350 | # arrow keys, tab, backs etc. will became fixed sequence (\edel, \ehome...) 351 | # 352 | sd_pushbutton_read () { # $1=name 353 | local sd_c= sd_retval= 354 | 355 | sd_pushbutton_draw $1 selection 356 | while true; do 357 | tput cnorm; read -sn1 sd_c; tput civis 358 | sd_c="`sd_escape_parse \"$sd_c\"`" 359 | 360 | if test -z $sd_c; then 361 | eval sd_${1}_push 2>/dev/null 362 | sd_retval=$? 363 | case $sd_retval in 364 | 127 | 254 | 255) : ;; 365 | *) break ;; 366 | esac 367 | fi 368 | 369 | case "$sd_c" in 370 | $'\e') sd_retval=27; break ;; # escape 371 | $'\ekcuf1') sd_retval=255; break ;; # key cursor forward 372 | $'\ekcub1') sd_retval=254; break ;; # key cursor backward 373 | $'\eht') sd_retval=255; break ;; # horizontal tab 374 | $'\ekcbt') sd_retval=254; break ;; # back tab 375 | esac 376 | done 377 | sd_pushbutton_draw $1 378 | return $sd_retval 379 | } 380 | 381 | 382 | sd_pushbutton_draw () { # $1=name [$2=selection] 383 | local sd_x= sd_y= sd_caption= sd_capt2= 384 | local sd_color= sd_colorl= sd_colorb= 385 | 386 | if test "$2" = selection; then 387 | sd_color=`tput sgr0; tput setaf 3; tput bold; tput setab 4` 388 | sd_colorl=`tput sgr0; tput setaf 7; tput bold; tput setab 4` 389 | sd_colorb=` tput sgr0; tput setaf 7; tput bold; tput setab 4` 390 | else 391 | sd_color=`tput sgr0; tput setaf 0; tput bold; tput setab 7` 392 | sd_colorl=`tput sgr0; tput setaf 1; tput setab 7` 393 | sd_colorb=`tput sgr0; tput setaf 0; tput setab 7` 394 | fi 395 | 396 | eval sd_x=\${sd_${1}_x:-0} 397 | eval sd_y=\${sd_${1}_y:-0} 398 | eval sd_caption=\"\$sd_${1}_caption\" 399 | sd_capt2="${sd_caption//[^[:alnum:]]/}" 400 | 401 | tput cup $sd_y $sd_x 402 | echo -en "$sd_colorb" 403 | echo -n "<" 404 | echo -n "$sd_color" 405 | echo -n "${sd_caption%%[[:alnum:]]*}" 406 | echo -n "$sd_colorl" 407 | echo -n "${sd_capt2:0:1}" 408 | echo -n "$sd_color" 409 | echo -n "${sd_caption#*[[:alnum:]]}" 410 | echo -n "$sd_colorb" 411 | echo -n ">" 412 | tput cup $sd_y $((sd_x + 1)) 413 | echo -n "$sd_color" 414 | echo -n "${sd_caption%%[[:alnum:]]*}" 415 | } 416 | 417 | 418 | sd_inputbox_read () { # $1=name 419 | local sd_varname= sd_maxwidth= sd_c= sd_retval= 420 | 421 | eval sd_varname=\$sd_${1}_varname 422 | eval sd_maxwidth=\$sd_${1}_width 423 | ((sd_maxwidth--)) 424 | 425 | while true; do 426 | sd_inputbox_draw $1 selection 427 | tput cnorm; read -sn1 sd_c; tput civis 428 | sd_c="`sd_escape_parse \"$sd_c\"`" 429 | 430 | case "$sd_c" in 431 | $'\e') sd_retval=27; break ;; 432 | $'\ekcuf1') sd_retval=255; break ;; 433 | $'\ekcub1') sd_retval=254; break ;; 434 | $'\eht') sd_retval=255; break ;; 435 | $'\ekcbt') sd_retval=254; break ;; 436 | $'\ekbs') 437 | eval "$sd_varname=\"\${${sd_varname}%\${${sd_varname}: -1}}\"" 438 | ;; 439 | $'\e'*) : ;; 440 | *) eval test \${#$sd_varname} -lt $sd_maxwidth && eval "$sd_varname+=\"\$sd_c\"" ;; 441 | esac 442 | done 443 | sd_inputbox_draw $1 444 | return $sd_retval 445 | } 446 | 447 | 448 | sd_inputbox_draw () { # $1=name, [$2=selection] 449 | local sd_x= sd_y= sd_width= sd_varname= 450 | local sd_varin= sd_varout= 451 | local sd_password= 452 | 453 | eval sd_x=\${sd_${1}_x:-0} 454 | eval sd_y=\${sd_${1}_y:-0} 455 | eval sd_width=\${sd_${1}_width:-0} 456 | eval sd_varname=\${sd_${1}_varname:-sd_novarname} 457 | eval sd_password=\${sd_${1}_password:-no} 458 | 459 | if test "$2" = selection; then 460 | tput sgr0; tput setaf 7; tput setab 4; 461 | else 462 | tput sgr0; tput setaf 0; tput setab 7; 463 | fi 464 | 465 | eval sd_varin=\${#${sd_varname}} 466 | eval sd_varout=$(( sd_width - sd_varin )) 467 | tput cup $sd_y $sd_x 468 | if test $sd_password = yes; then 469 | sd_repeat ${sd_varin} "*" 470 | else 471 | eval echo -n \$$sd_varname 472 | fi 473 | printf "%${sd_varout}s" 474 | eval tput cup $sd_y \$\(\(sd_x+\${#$sd_varname}\)\) 475 | } 476 | 477 | 478 | sd_listbox_read () { # $1=name 479 | local sd_arrayname= sd_indexname= 480 | local sd_maxindex= sd_ilight= sd_ifirst= sd_height= sd_multi= 481 | local sd_exilight= sd_c= sd_retval= sd_text= sd_i= 482 | 483 | eval sd_arrayname=\${sd_${1}_arrayname:-sd_noarray} 484 | eval sd_indexname=\${sd_${1}_indexname:-sd_noindex} 485 | eval sd_maxindex=\${#$sd_arrayname[@]} 486 | eval sd_height=\${sd_${1}_height:-1} 487 | eval sd_multi=\${sd_${1}_multi:-no} 488 | eval sd_ilight=\${sd_${1}_ilight:-0} 489 | eval sd_ifirst=\${sd_${1}_ifirst:-0} 490 | eval sd_exilight=-1 491 | 492 | while true; do 493 | if test $sd_ilight != $sd_exilight; then 494 | sd_exilight=$sd_ilight 495 | sd_listbox_draw $1 496 | fi 497 | 498 | tput cnorm; read -sn1 sd_c; tput civis 499 | sd_c="`sd_escape_parse \"$sd_c\"`" 500 | 501 | case "$sd_c" in 502 | $'\e') sd_retval=27; break ;; 503 | $'\ekcuf1') sd_retval=255; break ;; 504 | $'\ekcub1') sd_retval=254; break ;; 505 | $'\eht') sd_retval=255; break ;; 506 | $'\ekcbt') sd_retval=254; break ;; 507 | $'\ekcuu1') ((sd_ilight--)) ;; 508 | $'\ekcud1') ((sd_ilight++)) ;; 509 | $'\ekpp') test $sd_ilight = $sd_ifirst && \ 510 | sd_ilight=$((sd_ilight - sd_height)) || \ 511 | sd_ilight=$sd_ifirst ;; 512 | $'\eknp') test $sd_ilight = $((sd_ifirst + sd_height - 1)) && \ 513 | sd_ilight=$((sd_ilight + sd_height)) || \ 514 | sd_ilight=$((sd_ifirst + sd_height - 1)) ;; 515 | $'\ekhome') sd_ilight=0 ;; 516 | $'\ekend') sd_ilight=$((sd_maxindex - 1)) ;; 517 | " ") if test $sd_multi = no; then 518 | for ((sd_i=0; sd_i < sd_maxindex; sd_i++)); do 519 | eval unset $sd_indexname[$sd_i] 520 | done 521 | eval $sd_indexname[$sd_ilight]=\"\${$sd_arrayname[$sd_ilight]}\" 522 | else 523 | eval sd_text=\${$sd_indexname[$sd_ilight]+set} 524 | eval unset $sd_indexname[$sd_ilight] 525 | test "$sd_text" = "set" || \ 526 | eval $sd_indexname[$sd_ilight]=\"\${$sd_arrayname[$sd_ilight]}\" 527 | fi 528 | sd_exilight=-1 ;; 529 | *) shopt -s nocasematch 530 | sd_i=$((sd_ilight + 1)) 531 | while test $sd_i != $sd_ilight; do 532 | eval [[ \"\${$sd_arrayname[$sd_i]::1}\" = "$sd_c" ]] && break 533 | ((sd_i++)) 534 | test $sd_i -ge $sd_maxindex && sd_i=0 535 | done 536 | sd_ilight=$sd_i 537 | shopt -u nocasematch ;; 538 | esac 539 | test $sd_ilight -lt 0 && sd_ilight=0 540 | test $sd_ilight -ge $sd_maxindex && sd_ilight=$((sd_maxindex - 1)) 541 | test $sd_ilight -lt $sd_ifirst && sd_ifirst=$sd_ilight 542 | test $sd_ilight -ge $((sd_ifirst + sd_height)) && sd_ifirst=$((sd_ilight - sd_height + 1)) 543 | 544 | eval sd_${1}_ilight=$sd_ilight 545 | eval sd_${1}_ifirst=$sd_ifirst 546 | done 547 | return $sd_retval 548 | } 549 | 550 | 551 | # 552 | # unset indexname[n] means not-selected 553 | # any other strings ("" too) means selected 554 | # 555 | # with mark=no you can get selection from "ilight" 556 | # 557 | sd_listbox_draw () { # $1=name [$2=selection] 558 | local sd_x= sd_y= sd_width= sd_height= 559 | local sd_arrayname= sd_indexname= 560 | local sd_mark= sd_multi= sd_ilight= sd_ifirst= 561 | local sd_xrest= sd_y2= sd_taby2= sd_text= sd_text2= sd_maxindex= 562 | local sd_color= sd_colorl= sd_colorb= sd_scolor= sd_scolorl= sd_scolorb= 563 | 564 | sd_color=`tput sgr0; tput setaf 4; tput bold; tput setab 7` 565 | sd_colorl=`tput sgr0; tput setaf 1; tput setab 7` 566 | sd_colorb=`tput sgr0; tput setaf 0; tput setab 7` 567 | sd_scolor=`tput sgr0; tput setaf 3; tput bold; tput setab 4` 568 | sd_scolorl=`tput sgr0; tput setaf 1; tput bold; tput setab 4` 569 | sd_scolorb=`tput sgr0; tput setaf 7; tput bold; tput setab 4` 570 | 571 | eval sd_x=\${sd_${1}_x:0} 572 | eval sd_y=\${sd_${1}_y:0} 573 | eval sd_width=\${sd_${1}_width:-4} 574 | eval sd_height=\${sd_${1}_height:-1} 575 | eval sd_mark=\${sd_${1}_mark:-no} 576 | eval sd_ilight=\${sd_${1}_ilight:-0} 577 | eval sd_ifirst=\${sd_${1}_ifirst:-0} 578 | eval sd_arrayname=\${sd_${1}_arrayname:-sd_noarray} 579 | eval sd_indexname=\${sd_${1}_indexname:-sd_noindex} 580 | 581 | if test $sd_mark != no; then 582 | test $sd_width -lt 4 && sd_width=0 || ((sd_width -= 4)) 583 | fi 584 | eval sd_maxindex=\${#$sd_arrayname[@]} 585 | for ((sd_y2=0, sd_taby2=sd_ifirst; \ 586 | sd_y2 < sd_height & sd_taby2 < sd_maxindex; \ 587 | sd_y2++, sd_taby2++)); do 588 | 589 | tput cup $(( sd_y + sd_y2)) $sd_x 590 | 591 | if test $sd_mark != no; then 592 | test $sd_ilight = $sd_taby2 && echo -n "$sd_scolorb" || echo -n "$sd_colorb" 593 | test $sd_mark = radio && echo -n "(" || echo -n "[" 594 | eval test \"\${$sd_indexname[$sd_taby2]+set}\" = set && echo -n "*" || echo -n " " 595 | test $sd_mark = radio && echo -n ")" || echo -n "]" 596 | echo -n "$sd_color" 597 | echo -n " " 598 | fi 599 | 600 | eval sd_text=\"\${$sd_arrayname[$sd_taby2]}\" 601 | sd_text="${sd_text::$sd_width}" 602 | sd_xrest=$(( sd_width - ${#sd_text} )) 603 | test $sd_ilight = $sd_taby2 && echo -n "$sd_scolorl" || echo -n "$sd_colorl" 604 | echo -n ${sd_text::1} 605 | test $sd_ilight = $sd_taby2 && echo -n "$sd_scolor" || echo -n "$sd_color" 606 | echo -n ${sd_text:1} 607 | echo -n "$sd_color" 608 | printf "%-${sd_xrest}s" 609 | done 610 | test $sd_mark = no || ((sd_x += 4)) 611 | test $((sd_ilight - sd_ifirst)) -lt $sd_height && \ 612 | tput cup $((sd_y + sd_ilight - sd_ifirst)) $((sd_x)) 613 | } 614 | 615 | 616 | # 617 | # secondary functions 618 | # 619 | 620 | 621 | sd_swap () { # $1=varname1 $2=varname2 622 | local sd_temp= 623 | 624 | eval sd_temp=\"\$$1\" 625 | eval $1=\"\$$2\" 626 | eval $2=\"\$sd_temp\" 627 | } 628 | 629 | 630 | sd_repeat () { # $1=times $2=char 631 | local sd_i= 632 | for (( sd_i=0; sd_i < $1; sd_i++ )); do echo -n "$2"; done 633 | return 0 634 | } 635 | 636 | 637 | # 638 | # cuu, cud, cur, cul, tab, back, del... 639 | # every special keys will start with \e 640 | # 641 | sd_escape_parse () { # $1=char 642 | local sd_escseq=( "`tput kcuu1`" \ 643 | "`tput kcud1`" \ 644 | "`tput kcuf1`" \ 645 | "`tput kcub1`" \ 646 | "`tput ht`" \ 647 | "`tput kcbt`" \ 648 | "`tput kbs`" \ 649 | "`tput kpp`" \ 650 | "`tput knp`" \ 651 | "`tput khome`" \ 652 | "`tput kend`" ) 653 | 654 | local sd_outseq=( $'\ekcuu1' \ 655 | $'\ekcud1' \ 656 | $'\ekcuf1' \ 657 | $'\ekcub1' \ 658 | $'\eht' \ 659 | $'\ekcbt' \ 660 | $'\ekbs' \ 661 | $'\ekpp' \ 662 | $'\eknp' \ 663 | $'\ekhome' \ 664 | $'\ekend' ) 665 | 666 | local sd_i=0 sd_i2=1 sd_seq="$1" sd_c2= 667 | 668 | while test $sd_i -lt "${#sd_escseq[@]}"; do 669 | if test "$sd_seq" = "${sd_escseq[$sd_i]::$sd_i2}"; then 670 | test ${#sd_escseq[$sd_i]} = $sd_i2 && { echo -n "${sd_outseq[$sd_i]}"; return; } 671 | read -sn1 -t1 sd_c2 || break 672 | sd_seq+="$sd_c2" 673 | ((sd_i=0, sd_i2++)) 674 | else 675 | ((sd_i++)) 676 | fi 677 | done 678 | echo -n "${sd_seq: -1}" 679 | } 680 | 681 | 682 | sd_get_acsc_jklmqx () { 683 | local sd_jklmqx= sd_acsc= sd_i= 684 | 685 | sd_acsc="`tput acsc`" 686 | test "$sd_acsc" || { echo "',,'-|"; return; } 687 | 688 | for (( sd_i=0; sd_i < ${#sd_acsc}; sd_i+=2 )); do 689 | case ${sd_acsc:$sd_i:1} in 690 | j|k|l|m|q|x) sd_jklmqx+="${sd_acsc:$((sd_i+1)):1}"$'\n' ;; 691 | esac 692 | done 693 | echo "$sd_jklmqx" 694 | } 695 | 696 | -------------------------------------------------------------------------------- /tutorial/tut1: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # First of all, you have to include 'sourcedialog' in your script. 4 | # You can include it using 'source ' bash builtin. 5 | 6 | source ../sourcedialog 7 | 8 | 9 | # Next, you have to load your objects 10 | # 11 | # For every object you have to set his name (name=) and his properties 12 | # 13 | # Properties for canvas : x, y, width, height, caption 14 | # Properties for frame : x, y, width, height 15 | # Properties for textbox : x, y, width, height, text 16 | # Properties for pushbutton : x, y, caption 17 | # Properties for inputbox : x, y, width, varname 18 | # Properties for menubox : x, y, width, height, arrayname, [ilight, ifirst] 19 | # Properties for checklist : x, y, width, height, arrayname, indexname 20 | # Properties for radiolist : x, y, width, height, arrayname, indexname 21 | 22 | sd_load_canvas name=mycanvas x=20 y=5 width=40 height=10 caption="EXAMPLE 1" 23 | sd_load_frame name=myframe x=23 y=7 width=34 height=5 24 | sd_load_textbox name=mytext x=25 y=8 width=30 height=3 text="Once a man has tasted freedom he will never be content to be a slave." 25 | sd_load_pushbutton name=mybutton1 x=30 y=13 caption=" OK " 26 | sd_load_pushbutton name=mybutton2 x=42 y=13 caption="Cancel" 27 | 28 | 29 | # Detect the "push event" of your pushbuttons and return a value 30 | # The value must be in the range 0-26, and will be the return value of sd_start 31 | 32 | sd_mybutton1_push () { return 0; } 33 | sd_mybutton2_push () { return 1; } 34 | 35 | 36 | # Finally, simply call sd_start, and save his return value 37 | # 38 | # Walk through objects using right-left arrows and tab key 39 | # When finished press Enter in a pushbutton 40 | 41 | sd_start; retval=$? 42 | 43 | 44 | # 27 is the return value of Esc key 45 | # The other values are those returned from sd__push functions 46 | 47 | clear 48 | case $retval in 49 | 27) echo "Esc pressed." ;; 50 | 0) echo "OK pressed." ;; 51 | 1) echo "Cancel pressed." ;; 52 | esac 53 | 54 | -------------------------------------------------------------------------------- /tutorial/tut2: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | source ../sourcedialog 5 | 6 | 7 | sd_load_canvas name=canvas1 x=3 y=3 width=73 height=18 caption="EXAMPLE 2" 8 | 9 | sd_load_frame name=frame1 x=4 y=5 width=17 height=12 10 | sd_load_textbox name=textbox1 x=5 y=6 width=15 height=10 \ 11 | text="This text is automatically wrapped" 12 | 13 | sd_load_frame name=frame2 x=22 y=5 width=17 height=12 14 | sd_load_textbox name=textbox2 x=23 y=6 width=15 height=10 \ 15 | text="This\ntext\nis\nforced\nto\nwrap\nevery\nword" 16 | 17 | sd_load_frame name=frame3 x=40 y=5 width=17 height=12 18 | sd_load_textbox name=textbox3 x=41 y=6 width=15 height=10 \ 19 | text="Be careful in veryverylongwords because words greather than width will be truncated" 20 | 21 | sd_load_frame name=frame4 x=58 y=5 width=17 height=12 22 | sd_load_textbox name=textbox4 x=59 y=6 width=15 height=10 \ 23 | text="You have to define a rectangle large enaugh to fill every word you think to write, because if your rectangle is too small, your text will be truncated" 24 | 25 | sd_load_pushbutton name=button1 x=35 y=19 caption=" OK " 26 | sd_button1_push () { return 0; } 27 | 28 | 29 | sd_start; retval=$? 30 | clear 31 | case $retval in 32 | 27) echo "Esc pressed." ;; 33 | 0) echo "OK pressed." ;; 34 | esac 35 | 36 | -------------------------------------------------------------------------------- /tutorial/tut3: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | . ../sourcedialog 4 | 5 | sd_load_canvas name=canvas1 x=14 y=6 width=50 height=12 caption="EXAMPLE 4" 6 | sd_load_textbox name=textbox1 x=18 y=9 width=5 text="Name:" 7 | sd_load_textbox name=textbox2 x=18 y=11 width=8 text="Surname:" 8 | sd_load_textbox name=textbox3 x=18 y=13 width=9 text="Password:" 9 | 10 | 11 | # "varname" inputbox property sets the 'name' of the user-variable 12 | # This variable will be automatically managed by sourcedialog 13 | # Pre-put something in this variable to start with a default value 14 | # 15 | # passwordbox works like inputbox, but hiding text with * 16 | 17 | name="Richard" 18 | sd_load_inputbox name=ibname x=28 y=9 width=20 varname=name 19 | 20 | surname="Stallman" 21 | sd_load_inputbox name=ibsurname x=28 y=11 width=20 varname=surname 22 | 23 | password="freebeer" 24 | sd_load_passwordbox name=ibpassword x=28 y=13 width=20 varname=password 25 | 26 | 27 | sd_load_pushbutton name=button1 x=35 y=16 caption=" OK " 28 | sd_button1_push () { return 0; } 29 | 30 | 31 | sd_start; retval=$? 32 | clear 33 | case $retval in 34 | 27) echo "Esc pressed." ;; 35 | 0) 36 | echo 37 | echo "The name is: $name" 38 | echo "The surname is: $surname" 39 | echo "The password is: $password" 40 | ;; 41 | esac 42 | 43 | -------------------------------------------------------------------------------- /tutorial/tut4: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | . ../sourcedialog 4 | 5 | array_best=( "Linus Torvalds" \ 6 | "Richard Stallman" \ 7 | "Mahatma Gandhi" \ 8 | "John Lennon" \ 9 | "Jesus Christ" ) 10 | index_best[0]=${array_best[0]} 11 | index_best[1]=${array_best[1]} 12 | index_best[4]=${array_best[4]} 13 | 14 | 15 | array_worst=( "Adolf Hitler" \ 16 | "Iosif Stalin" \ 17 | "Augusto Pinochet" \ 18 | "Silvio Berlusconi" \ 19 | "Saddam Hussein" ) 20 | index_worst[3]=${array_worst[3]} 21 | 22 | 23 | array_quote=( "The best is the enemy of the good" \ 24 | "To hold a pen is to be at war" \ 25 | "Love truth but pardon error" \ 26 | "A witty saying proves nothing" \ 27 | "Business is the salt of life" ) 28 | 29 | 30 | sd_load_canvas name=cv1 x=17 y=1 width=40 height=21 caption="EXAMPLE 4" 31 | sd_load_textbox name=tbb x=19 y=2 width=36 text="Choose the best" 32 | sd_load_textbox name=tbw x=19 y=8 width=36 text="Choose the worst" 33 | sd_load_textbox name=tbq x=19 y=14 width=36 text="Choose your quote" 34 | 35 | 36 | # "arrayname" sets the 'name' of the array filled with the elements of the list 37 | # 38 | # "indexname" sets the 'name' of the array filled with the elements selected 39 | # unset-element means not-selected, any string ("" too) means selected 40 | # sourcedialog will fill this array unsetting non-selected elements 41 | # and setting every selected element with the same string found in "arrayname" 42 | 43 | sd_load_checklist name=listbest x=19 y=4 width=36 height=3 \ 44 | arrayname=array_best indexname=index_best 45 | sd_load_radiolist name=listworst x=19 y=10 width=36 height=3 \ 46 | arrayname=array_worst indexname=index_worst 47 | 48 | 49 | # "ilight" sets the first element highlighted (default 0) 50 | # "ifirst" sets the first element showed (default 0) 51 | # in this way you can change the starting point of the list 52 | 53 | sd_load_menubox name=menuquote x=19 y=16 width=36 height=3 \ 54 | arrayname=array_quote ifirst=1 ilight=2 55 | 56 | 57 | sd_load_pushbutton name=button1 x=33 y=20 caption=" OK " 58 | 59 | 60 | # you can read "ilight" property to get the last selection in menuboxes 61 | 62 | sd_button1_push () { lastsel=$sd_menuquote_ilight; return 0; } 63 | 64 | 65 | sd_start; retval=$? 66 | clear 67 | case $retval in 68 | 27) echo "ESC pressed." ;; 69 | 0) 70 | echo "BEST SELECTION" 71 | echo "--------------" 72 | for name in "${index_best[@]}"; do echo "$name"; done 73 | 74 | echo 75 | echo "YOUR QUOTE IS: ${array_quote[$lastsel]}" 76 | ;; 77 | esac 78 | 79 | --------------------------------------------------------------------------------