#!/bin/sh # Last modified: Fri 2003-03-28 15:25:04 +0000 # Copyright (C) 2003, Vivek Dasmohapatra declare paridx=0; declare -a OPT_p; # convert "^X" to a control char (A-_ supported): _ctrl () { local char="${1:1:1}"; #echo _ctrl "$char"; case $char in A) asc=$'\x01' ;; B) asc=$'\x02' ;; C) asc=$'\x03' ;; D) asc=$'\x04' ;; E) asc=$'\x05' ;; F) asc=$'\x06' ;; G) asc=$'\x07' ;; H) asc=$'\x08' ;; I) asc=$'\x09' ;; J) asc=$'\x0a' ;; K) asc=$'\x0b' ;; L) asc=$'\x0c' ;; M) asc=$'\x0d' ;; N) asc=$'\x0e' ;; O) asc=$'\x0f' ;; P) asc=$'\x10' ;; Q) asc=$'\x11' ;; R) asc=$'\x12' ;; S) asc=$'\x13' ;; T) asc=$'\x14' ;; U) asc=$'\x15' ;; V) asc=$'\x16' ;; W) asc=$'\x17' ;; X) asc=$'\x18' ;; Y) asc=$'\x19' ;; Z) asc=$'\x1a' ;; [) asc=$'\x1b' ;; \\) asc=$'\x1c' ;; ]) asc=$'\x1d' ;; ^) asc=$'\x1e' ;; _) asc=$'\x1f' ;; *) asc="" ;; esac; } # decode a symbol, or just return unaltered if no match found: _decode () { local \ asc="" \ symbol="" \ ctlbuf="" ; ctlstr=""; #echo _decode "'$*'" 1>&2; for symbol in "$@"; do case "$symbol" in S7C1T) symbol="ESC SP F" ;; # 7 bit controls S8C1T) symbol="ESC SP G" ;; # 8 bit controls DECDHLU)symbol="ESC # 3" ;; # double height, upper half DECDHLL)symbol="ESC # 4" ;; # double height, lower half DECSWL) symbol="ESC # 5" ;; # single width DECDWL) symbol="ESC # 6" ;; # double width DECALN) symbol="ESC # 8" ;; # alignment test DECSC) symbol="ESC 7" ;; # save cursor DECRC) symbol="ESC 8" ;; # restore cursor DECPAM) symbol="ESC =" ;; # app keypad DECPNM) symbol="ESC >" ;; # normal keypad RIS) symbol="ESC c" ;; # full reset ESC) symbol="^[" ;; # esc IND) symbol="ESC D" ;; # index NEL) symbol="ESC E" ;; # next line HTS) symbol="ESC H" ;; # set tab stop RI) symbol="ESC M" ;; # Reverse Index SS2) symbol="ESC N" ;; # Single Shift G2 charset next char only SS3) symbol="ESC O" ;; # Single Shift G3 charset next char only DCS) symbol="ESC P" ;; # Device Control String SPA) symbol="ESC V" ;; # Start Protected Area EPA) symbol="ESC W" ;; # End Protected Area SOS) symbol="ESC X" ;; # Start Of String DECID) symbol="ESC Z" ;; # terminal id (obs, use CSI Ps c) CSI) symbol="ESC [" ;; # Control Sequence Introduction ST) symbol="ESC \\" ;;# String Terminator (new, was BEL) OSC) symbol="ESC ]" ;; # Operating System Command PM) symbol="ESC ^" ;; # Privacy Message APC) symbol="ESC _" ;; # Application Program Command BEL) symbol="^G" ;; # beep BS) symbol="^H" ;; # backspace CR) symbol="^M" ;; # Carriage Return (beginning of line) ENQ) symbol="^E" ;; # terminal stats. usu responds "xterm" FF) symbol="^L" ;; # Form Feed (clear/redraw screen) LF) symbol="^J" ;; # Line Feed SO) symbol="^N" ;; # Shift Out : G1 character set TAB) symbol="^I" ;; # Tab VT) symbol="^K" ;; # same as LF SI) symbol="^O" ;; # Shift In : G0 (default) character set ^?) _ctrl "$symbol"; symbol="$asc" ;; # ^X ctrl notation SET_WTITLE) symbol="OSC 2 ; %p ST" ;; SET_ITITLE) symbol="OSC 1 ; %p ST" ;; SET_TITLES) symbol="OSC 0 ; %p ST" ;; SET_XPROP) symbol="OSC 3 ; %p ST" ;; GET_WTITLE) symbol="CSI 2 1 t" ;; GET_ITITLE) symbol="CSI 2 0 t" ;; esac; ctlbuf="${ctlbuf}${ctlbuf:+ }${symbol}"; done; ctlstr="${ctlbuf}"; } usage () { cat < This tool translates a sequence of symbols and strings into a corresponding terminal escape sequence, which it then prints on stdout. If the -r flag is supplied, then it sends the escape sequence to the tty ( via '/dev/tty' ), reads the terminal's response, trims some leading and trailing marker characters, and prints the result on stdout instead (unless -R was specified, in which case you get the raw response sequence). Note that the raw response generally begins with a control string that renders it invisible when printed, so it's a good idea to capture it with a RSP=\$($0 -r -R SEQUENCE) type construct. The sequence will have all the spaces stripped out of it, except those explicitly passed as the 'SP' symbol. $0 knows about the following symbols: S7C1T 7 bit control sequences S8C1T 8 bit control sequences DECDHLU double height line, upper half DECDHLL double height line, lower half DECSWL single width DECDWL double width DECALN alignment test DECSC save cursor DECRC restore cursor DECPAM app keypad DECPNM normal keypad RIS full reset ESC esc IND index NEL next line HTS set tab stop RI Reverse Index SS2 Single Shift G2 charset: next char only SS3 Single Shift G3 charset: next char only DCS Device Control String SPA Start Protected Area EPA End Protected Area SOS Start Of String DECID terminal id (obsolete: use CSI Ps c) CSI Control Sequence Introduction ST String Terminator OSC Operating System Command PM Privacy Message APC Application Program Command BEL beep BS backspace CR Carriage Return (beginning of line) ENQ terminal status FF Form Feed (clear/redraw screen) LF Line Feed SO Shift Out : G1 character set SP space TAB Tab VT same as LF SI Shift In : G0 (default) character set ^A ... ^_ control characters 0x01 through 0x1f The following high-level sequences have been defined for convenience: GET_WTITLE fetch the window title GET_ITITLE fetch the icon title Additionally, we support parametrised symbolic sequences: Each '%p' in a sequence will be replaced with successive values of the -p flag. The following parametrised sequences are built in: SET_WTITLE (1 arg) Set the window title SET_ITITLE (1 arg) Set the icon title SET_TITLES (1 arg) Set both the above SET_XPROP (1 arg) Set (prop=value) or zap (prop) an X property The escape sequences are detailed here: http://rtfm.etla.org/xterm/ctlseq.html Example: # sets the title bar to "Xterm Title" $0 OSC 0 \; Xterm SP Title ST # or: $0 -p "Xterm SP Title" SET_WTITLE # stores the (sanitised) title response in \$TSTR TSTR=\$($0 CSI 2 1 t) # or: TSTR=\$($0 GET_WTITLE) EOF } _param () { local curidx=0; while [ 1 -eq 1 ]; do if [ $paridx -eq $curidx ]; then par=${OPT_p[$curidx]}; paridx=$(($paridx + 1)); #echo "retrieving p[$curidx] = $par"; break; else curidx=$(($curidx + 1)); fi; done; } decode () { local\ ctlstr="" \ sym="" \ seqbuf="" ; for sym in "$@"; do while [ "1" = "1" ]; do _decode $sym; if [ "X$ctlstr" = "X$sym" ]; then break; else sym="$ctlstr"; fi; done; sequence="${sequence}${sequence:+ }${sym}"; #echo -n sequence= 1>&2; #echo "$sequence" | sed -e 's@[^A-Z0-9_]@.@g' 1>&2; done; for sym in $sequence; do if [ "X$sym" = "XSP" ]; then sym=" "; fi; if [ "X$sym" = "X%p" ]; then _param ; sym="$par"; fi; seqbuf="${seqbuf}${sym}"; done; sequence="$seqbuf"; } ctl_read () { local \ old="" \ cseq="$*" \ response="" \ sequence="" ; exec /dev/tty; # feed the control sequence to the tty IFS='' read -r response; # read the response stty "$old"; # reset th tty to its saved state if [ -z "$OPT_R" ] && [ -n "$response" ]; then local \ OSC="" \ CSI="" \ rlen=${#response} \ start=${response:0:2} ; decode "OSC"; OSC="$sequence"; decode "CSI"; CSI="$sequence"; if [ "$start" = "$OSC" ]; then response=${response:3:$(($rlen-5))}; elif [ "$start" = "$CSI" ]; then response=${response:3:$(($rlen-4))}; fi; fi; echo -n "$response"; # echo the response string } main () { local \ name="" \ setarg="" ; while getopts rRhp: n; do case $n in p) OPT_p[$paridx]="${OPTARG:-$paridx}"; paridx=$(($paridx + 1)); ;; *) setarg="OPT_${n}=\"\${OPT_${n}}\${OPT_$n:+ }${OPTARG:-1}\""; #echo $setarg 1>&2; eval $setarg; ;; esac; done; paridx=0; shift $(($OPTIND-1)); #echo "\$OPT_p='$OPT_p'"; if [ $# -eq 0 ] || [ -n "$OPT_h" ]; then usage; exit 0; fi; decode "$@"; if [ -n "$OPT_r" ]; then ctl_read $sequence; else echo -n $sequence; fi; } main "$@";