From: Colin Watson Date: Fri, 17 Oct 2003 01:49:53 +0000 (+0000) Subject: Add Vivek's ctlseq script verbatim. X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~cjwatson/git?a=commitdiff_plain;ds=sidebyside;h=62d6ec4026ad55db412c9acd60f56089950ed213;p=bin.git Add Vivek's ctlseq script verbatim. --- diff --git a/ctlseq b/ctlseq new file mode 100755 index 0000000..267f794 --- /dev/null +++ b/ctlseq @@ -0,0 +1,334 @@ +#!/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 rhp: 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 "$@"; +