├── README.md ├── getopts_long.sh ├── locvar.sh ├── lsofc ├── mouse.zsh ├── which_interpreter └── wide_strftime.sh /README.md: -------------------------------------------------------------------------------- 1 | misc-scripts 2 | ============ 3 | 4 | mouse.zsh 5 | --------- 6 | 7 | mouse support for the Z-shell (for xterm like terminals or linux console on i386). See the file itself for details on how to use it. 8 | 9 | getopts_long.sh 10 | --------------- 11 | 12 | a getopts that supports long options à la GNU for POSIX shells 13 | 14 | wide_strftime.sh 15 | ---------------- 16 | 17 | Date/time manipulation routines for POSIX shells. 18 | 19 | which_interpreter 20 | ----------------- 21 | 22 | A perl script. Err, no sorry, a ruby script. Or, is it a python one? tcl, expect? Simply a shell script? But, which shell? Ok, that one's definitely nerdish. 23 | 24 | locvar.sh 25 | --------- 26 | 27 | How to implement a local scope (for functions or sourced code or eval blocks...) in a POSIX shell. 28 | 29 | lsofc 30 | ----- 31 | 32 | Wrapper around lsof to add peer information for sockets. 33 | -------------------------------------------------------------------------------- /getopts_long.sh: -------------------------------------------------------------------------------- 1 | #! /bin/echo Usage:. 2 | # 3 | # getopts_long -- POSIX shell getopts with GNU-style long option support 4 | # 5 | # Copyright 2005-2009 Stephane Chazelas 6 | # 7 | # Permission to use, copy, modify, distribute, and sell this software and 8 | # its documentation for any purpose is hereby granted without fee, provided 9 | # that the above copyright notice appear in all copies and that both that 10 | # copyright notice and this permission notice appear in supporting 11 | # documentation. No representations are made about the suitability of this 12 | # software for any purpose. It is provided "as is" without express or 13 | # implied warranty. 14 | 15 | # History: 16 | # 2005 ?? - 1.0 17 | # first version 18 | # 2009-08-12 - 1.1 19 | # thanks to ujqm8360@netwtc.net for helping fix a few bugs: 20 | # - -ab x where -b accepts arguments wasn't handled properly. Also, 21 | # $OPTLIND wasn't set properly (at least not the same way as most 22 | # getopts implementation do). 23 | # - The handling of ambiguous long options was incorrect. 24 | 25 | getopts_long() { 26 | # args: shortopts, var, [name, type]*, "", "$@" 27 | # 28 | # getopts_long parses command line arguments. It works like the 29 | # getopts shell built-in command except that it also recognises long 30 | # options a la GNU. 31 | # 32 | # You must provide getopts_long with the list of supported single 33 | # letter options in the same format as getopts', followed by the 34 | # variable name you want getopts_long to return the current processed 35 | # option in, followed by the list of long option names (without the 36 | # leading "--") and types (0 or no_argument, 1 or required_argument, 37 | # 2 or optional_argument). The end of the long option specification 38 | # is indicated by an empty argument. Then follows the list of 39 | # arguments to be parsed. 40 | # 41 | # The $OPTLIND variable must be set to 1 before the first call of the 42 | # getopts_long function to process a given list of arguments. 43 | # 44 | # getopts_long returns the value of the current option in the variable 45 | # whose name is provided as its second argument (be careful to avoid 46 | # variables that have a special signification to getopts_long or the 47 | # shell or any other tool you may call from your script). If the 48 | # current option is a single letter option, then it is returned 49 | # without the leading "-". If it's a long option (possibly 50 | # abbreviated), then the full name of the option (without the leading 51 | # "--") is returned. If the option has an argument, then it is stored 52 | # in the $OPTLARG variable. If the current option is not recognised, 53 | # or if it is provided with an argument while it is not expecting one 54 | # (as in --opt=value) or if it is not provided with an argument while 55 | # it is expecting one, or if the option is so abbreviated that it is 56 | # impossible to identify the option uniquely, then: 57 | # - if the short option specifications begin with ":", getopts_long 58 | # returns ":" in the output variable and $OPTLARG contains the 59 | # faulty option name (in full except in the case of the ambiguous 60 | # or bad option) and $OPTLERR contains the error message. 61 | # - if not, then getopts_long behaves the same as above except that 62 | # it returns "?" instead of ":", leaves $OPTLARG unset and 63 | # displays the error message on stderr. 64 | # 65 | # The exit status of getopts_long is 0 unless the end of options is 66 | # reached or an error is encountered in the syntax of the getopts_long 67 | # call. 68 | # 69 | # After getopts_long has finished processing the options, $OPTLIND 70 | # contains the index of the first non-option argument or $# + 1 if 71 | # there's no non-option argument. 72 | # 73 | # The "=" character is not allowed in a long option name. Any other 74 | # character is. "-" and ":" are not allowed as short option names. Any 75 | # other character is. If a short option appears more than once in the 76 | # specification, the one with the greatest number of ":"s following it 77 | # is retained. If a long option name is provided more than once, only 78 | # the first one is taken into account. Note that if you have both a -a 79 | # and --a option, there's no way to differentiate them. Beside the 80 | # $OPTLIND, $OPTLARG, and $OPTLERR, getopts_long uses the $OPTLPENDING 81 | # variable to hold the remaining options to be processed for arguments 82 | # with several one-letter options. That variable shouldn't be used 83 | # anywhere else in your script. Those 4 variables are the only ones 84 | # getopts_long may modify. 85 | # 86 | # Dependency: only POSIX utilities are called by that function. They 87 | # are "set", "unset", "shift", "break", "return", "eval", "command", 88 | # ":", "printf" and "[". Those are generally built in the POSIX 89 | # shells. Only "printf" has been known not to be in some old versions 90 | # of bash, zsh or ash based shells. 91 | # 92 | # Differences with the POSIX getopts: 93 | # - if an error is detected during the parsing of command line 94 | # arguments, the error message is stored in the $OPTLERR variable 95 | # and if the first character of optstring is ':', ':' is returned in 96 | # any case. 97 | # - in the single-letter option specification, if a letter is 98 | # followed by 2 colons ("::"), then the option can have an optional 99 | # argument as in GNU getopt(3). In that case, the argument must 100 | # directly follow the option as in -oarg (not -o arg). 101 | # - there must be an empty argument to mark the end of the option 102 | # specification. 103 | # - long options starting with "--" are supported. 104 | # 105 | # Differences with GNU getopt_long(3): 106 | # - getopts_long doesn't allow options to be interspersed with other 107 | # arguments (as if POSIXLY_CORRECT was set for GNU getopt_long(3)) 108 | # - there's no linkage of any sort between the short and long 109 | # options. The caller is responsible of that (see example below). 110 | # 111 | # Compatibility: 112 | # getopts_long code is (hopefully) POSIX.2/SUSv3 compliant. It won't 113 | # work with the Bourne/SystemV shell. Use /usr/xpg4/bin/sh or ksh or 114 | # bash on Solaris. 115 | # It has been tested successfully with: 116 | # - bash 3.0 (patch level 16) on Cygwin 117 | # - zsh 4.2.4 on Solaris 2.7 118 | # - /usr/xpg4/bin/sh (same as /usr/bin/ksh) (ksh88i) on Solaris 2.7 119 | # - /usr/dt/bin/dtksh (ksh93d) on Solaris 2.7 120 | # - /usr/bin/ksh (pdksh 5.2.14) on Linux 121 | # - zsh 3.0.6 on Solaris 2.8 122 | # - bash 2.0.3 on Solaris 2.8 123 | # - dash 0.5.2 on Linux 124 | # - bash 2.05b (patch level 0) on Linux 125 | # - ksh93p and ksh93q on Linux (ksh93t+ crashes) 126 | # 127 | # It is known to fail with those non-POSIX compliant shells: 128 | # - /bin/sh on Solaris 129 | # - /usr/bin/sh on Cygwin 130 | # - bash 1.x 131 | # 132 | # Bugs: 133 | # please report them to 134 | # 135 | # Example: 136 | # 137 | # verbose=false opt_bar=false bar=default_bar foo=default_foo 138 | # opt_s=false opt_long=false 139 | # OPTLIND=1 OPTLPENDING= # or OPTLIND=0 140 | # while getopts_long :sf:b::vh opt \ 141 | # long 0 \ 142 | # foo required_argument \ 143 | # bar 2 \ 144 | # verbose no_argument \ 145 | # help 0 "" "$@" 146 | # do 147 | # case "$opt" in 148 | # s) opt_s=true;; 149 | # long) opt_long=true;; 150 | # v|verbose) verbose=true;; 151 | # h|help) usage; exit 0;; 152 | # f|foo) foo=$OPTLARG;; 153 | # b|bar) bar=${OPTLARG-$bar};; 154 | # :) printf >&2 '%s: %s\n' "${0##*/}" "$OPTLERR" 155 | # usage 156 | # exit 1;; 157 | # esac 158 | # done 159 | # shift "$(($OPTLIND - 1))" 160 | # # process the remaining arguments 161 | 162 | [ -n "${ZSH_VERSION+z}" ] && emulate -L sh 163 | 164 | unset OPTLERR OPTLARG || : 165 | 166 | case "$OPTLIND" in 167 | "" | 0 | *[!0-9]*) 168 | # First time in the loop. Initialise the parameters. 169 | OPTLIND=1 170 | OPTLPENDING= 171 | ;; 172 | esac 173 | 174 | if [ "$#" -lt 2 ]; then 175 | printf >&2 'getopts_long: not enough arguments\n' 176 | return 1 177 | fi 178 | 179 | # validate variable name. Need to fix locale for character ranges. 180 | LC_ALL=C command eval ' 181 | case "$2" in 182 | *[!a-zA-Z_0-9]*|""|[0-9]*) 183 | printf >&2 "getopts_long: invalid variable name: \`%s'\''\n" "$2" 184 | return 1 185 | ;; 186 | esac' 187 | 188 | # validate short option specification 189 | case "$1" in 190 | ::*|*:::*|*-*) 191 | printf >&2 "getopts_long: invalid option specification: \`%s'\n" "$1" 192 | return 1 193 | ;; 194 | esac 195 | 196 | # validate long option specifications 197 | 198 | # POSIX shells only have $1, $2... as local variables, hence the 199 | # extensive use of "set" in that function. 200 | 201 | set 4 "$@" 202 | while :; do 203 | if 204 | [ "$1" -gt "$#" ] || { 205 | eval 'set -- "${'"$1"'}" "$@"' 206 | [ -n "$1" ] || break 207 | [ "$(($2 + 2))" -gt "$#" ] 208 | } 209 | then 210 | printf >&2 "getopts_long: long option specifications must end in an empty argument\n" 211 | return 1 212 | fi 213 | eval 'set -- "${'"$(($2 + 2))"'}" "$@"' 214 | # $1 = type, $2 = name, $3 = $@ 215 | case "$2" in 216 | *=*) 217 | printf >&2 "getopts_long: invalid long option name: \`%s'\n" "$2" 218 | return 1 219 | ;; 220 | esac 221 | case "$1" in 222 | 0 | no_argument) ;; 223 | 1 | required_argument) ;; 224 | 2 | optional_argument) ;; 225 | *) 226 | printf >&2 "getopts_long: invalid long option type: \`%s'\n" "$1" 227 | return 1 228 | ;; 229 | esac 230 | eval "shift 3; set $(($3 + 2))"' "$@"' 231 | done 232 | shift 233 | 234 | eval "shift; set $(($1 + $OPTLIND))"' "$@"' 235 | 236 | # unless there are pending short options to be processed (in 237 | # $OPTLPENDING), the current option is now in ${$1} 238 | 239 | if [ -z "$OPTLPENDING" ]; then 240 | [ "$1" -le "$#" ] || return 1 241 | eval 'set -- "${'"$1"'}" "$@"' 242 | 243 | case "$1" in 244 | --) 245 | OPTLIND=$(($OPTLIND + 1)) 246 | return 1 247 | ;; 248 | --*) 249 | OPTLIND=$(($OPTLIND + 1)) 250 | ;; 251 | -?*) 252 | OPTLPENDING="${1#-}" 253 | shift 254 | ;; 255 | *) 256 | return 1 257 | ;; 258 | esac 259 | fi 260 | 261 | if [ -n "$OPTLPENDING" ]; then 262 | # WA for zsh and bash 2.03 bugs: 263 | OPTLARG=${OPTLPENDING%"${OPTLPENDING#?}"} 264 | set -- "$OPTLARG" "$@" 265 | OPTLPENDING="${OPTLPENDING#?}" 266 | unset OPTLARG 267 | 268 | # $1 = current option = ${$2+1}, $3 = $@ 269 | 270 | [ -n "$OPTLPENDING" ] || 271 | OPTLIND=$(($OPTLIND + 1)) 272 | 273 | case "$1" in 274 | [-:]) 275 | OPTLERR="bad option: \`-$1'" 276 | case "$3" in 277 | :*) 278 | eval "$4=:" 279 | OPTLARG="$1" 280 | ;; 281 | *) 282 | printf >&2 '%s\n' "$OPTLERR" 283 | eval "$4='?'" 284 | ;; 285 | esac 286 | ;; 287 | 288 | *) 289 | case "$3" in 290 | *"$1"::*) # optional argument 291 | eval "$4=\"\$1\"" 292 | if [ -n "$OPTLPENDING" ]; then 293 | # take the argument from $OPTLPENDING if any 294 | OPTLARG="$OPTLPENDING" 295 | OPTLPENDING= 296 | OPTLIND=$(($OPTLIND + 1)) 297 | fi 298 | ;; 299 | 300 | *"$1":*) # required argument 301 | if [ -n "$OPTLPENDING" ]; then 302 | # take the argument from $OPTLPENDING if any 303 | OPTLARG="$OPTLPENDING" 304 | eval "$4=\"\$1\"" 305 | OPTLPENDING= 306 | OPTLIND=$(($OPTLIND + 1)) 307 | else 308 | # take the argument from the next argument 309 | if [ "$(($2 + 2))" -gt "$#" ]; then 310 | OPTLERR="option \`-$1' requires an argument" 311 | case "$3" in 312 | :*) 313 | eval "$4=:" 314 | OPTLARG="$1" 315 | ;; 316 | *) 317 | printf >&2 '%s\n' "$OPTLERR" 318 | eval "$4='?'" 319 | ;; 320 | esac 321 | else 322 | OPTLIND=$(($OPTLIND + 1)) 323 | eval "OPTLARG=\"\${$(($2 + 2))}\"" 324 | eval "$4=\"\$1\"" 325 | fi 326 | fi 327 | ;; 328 | 329 | *"$1"*) # no argument 330 | eval "$4=\"\$1\"" 331 | ;; 332 | *) 333 | OPTLERR="bad option: \`-$1'" 334 | case "$3" in 335 | :*) 336 | eval "$4=:" 337 | OPTLARG="$1" 338 | ;; 339 | *) 340 | printf >&2 '%s\n' "$OPTLERR" 341 | eval "$4='?'" 342 | ;; 343 | esac 344 | ;; 345 | esac 346 | ;; 347 | esac 348 | else # long option 349 | 350 | # remove the leading "--" 351 | OPTLPENDING="$1" 352 | shift 353 | set 6 "${OPTLPENDING#--}" "$@" 354 | OPTLPENDING= 355 | 356 | while 357 | eval 'set -- "${'"$1"'}" "$@"' 358 | [ -n "$1" ] 359 | do 360 | # $1 = option name = ${$2+1}, $3 => given option = ${$4+3}, $5 = $@ 361 | 362 | case "${3%%=*}" in 363 | "$1") 364 | OPTLPENDING=EXACT 365 | break;; 366 | esac 367 | 368 | # try to see if the current option can be seen as an abbreviation. 369 | case "$1" in 370 | "${3%%=*}"*) 371 | if [ -n "$OPTLPENDING" ]; then 372 | [ "$OPTLPENDING" = AMBIGUOUS ] || eval '[ "${'"$(($OPTLPENDING + 1))"'}" = "$1" ]' || 373 | OPTLPENDING=AMBIGUOUS 374 | # there was another different option matching the current 375 | # option. The eval thing is in case one option is provided 376 | # twice in the specifications which is OK as per the 377 | # documentation above 378 | else 379 | OPTLPENDING="$2" 380 | fi 381 | ;; 382 | esac 383 | eval "shift 2; set $(($2 + 2)) "'"$@"' 384 | done 385 | 386 | case "$OPTLPENDING" in 387 | AMBIGUOUS) 388 | OPTLERR="option \`--${3%%=*}' is ambiguous" 389 | case "$5" in 390 | :*) 391 | eval "$6=:" 392 | OPTLARG="${3%%=*}" 393 | ;; 394 | *) 395 | printf >&2 '%s\n' "$OPTLERR" 396 | eval "$6='?'" 397 | ;; 398 | esac 399 | OPTLPENDING= 400 | return 0 401 | ;; 402 | EXACT) 403 | eval 'set "${'"$(($2 + 2))"'}" "$@"' 404 | ;; 405 | "") 406 | OPTLERR="bad option: \`--${3%%=*}'" 407 | case "$5" in 408 | :*) 409 | eval "$6=:" 410 | OPTLARG="${3%%=*}" 411 | ;; 412 | *) 413 | printf >&2 '%s\n' "$OPTLERR" 414 | eval "$6='?'" 415 | ;; 416 | esac 417 | OPTLPENDING= 418 | return 0 419 | ;; 420 | *) 421 | # we've got an abbreviated long option. 422 | shift 423 | eval 'set "${'"$(($OPTLPENDING + 1))"'}" "${'"$OPTLPENDING"'}" "$@"' 424 | ;; 425 | esac 426 | 427 | OPTLPENDING= 428 | 429 | # $1 = option type, $2 = option name, $3 unused, 430 | # $4 = given option = ${$5+4}, $6 = $@ 431 | 432 | case "$4" in 433 | *=*) 434 | case "$1" in 435 | 1 | required_argument | 2 | optional_argument) 436 | eval "$7=\"\$2\"" 437 | OPTLARG="${4#*=}" 438 | ;; 439 | *) 440 | OPTLERR="option \`--$2' doesn't allow an argument" 441 | case "$6" in 442 | :*) 443 | eval "$7=:" 444 | OPTLARG="$2" 445 | ;; 446 | *) 447 | printf >&2 '%s\n' "$OPTLERR" 448 | eval "$7='?'" 449 | ;; 450 | esac 451 | ;; 452 | esac 453 | ;; 454 | 455 | *) 456 | case "$1" in 457 | 1 | required_argument) 458 | if [ "$(($5 + 5))" -gt "$#" ]; then 459 | OPTLERR="option \`--$2' requires an argument" 460 | case "$6" in 461 | :*) 462 | eval "$7=:" 463 | OPTLARG="$2" 464 | ;; 465 | *) 466 | printf >&2 '%s\n' "$OPTLERR" 467 | eval "$7='?'" 468 | ;; 469 | esac 470 | else 471 | OPTLIND=$(($OPTLIND + 1)) 472 | eval "OPTLARG=\"\${$(($5 + 5))}\"" 473 | eval "$7=\"\$2\"" 474 | fi 475 | ;; 476 | *) 477 | # optional argument (but obviously not provided) or no 478 | # argument 479 | eval "$7=\"\$2\"" 480 | ;; 481 | esac 482 | ;; 483 | esac 484 | fi 485 | return 0 486 | } 487 | 488 | # testing code 489 | if [ -n "$test_getopts_long" ]; then 490 | test_getopts_long() { 491 | expected="$1" had= 492 | shift 493 | OPTLIND=1 OPTLPENDING= 494 | 495 | while err="$(set +x;getopts_long "$@" 2>&1 > /dev/null)" 496 | getopts_long "$@" 2> /dev/null; do 497 | eval "opt=\"\$$2\"" 498 | had="$had|$opt@${OPTLARG-unset}@${OPTLIND-unset}@${OPTLERR-unset}@$err" 499 | done 500 | had="$had|${OPTLIND-unset}|$err" 501 | 502 | if [ "$had" = "$expected" ]; then 503 | echo PASS 504 | else 505 | echo FAIL 506 | printf 'Expected: %s\n Got: %s\n' "$expected" "$had" 507 | fi 508 | } 509 | while IFS= read -r c && IFS= read -r e; do 510 | printf '+ %-72s ' "$c" 511 | #set -x 512 | eval "test_getopts_long \"\$e\" $c" 513 | done << \EOF 514 | : a 515 | |1|getopts_long: long option specifications must end in an empty argument 516 | :a opt "" -a 517 | |a@unset@2@unset@|2| 518 | :a opt "" -a b 519 | |a@unset@2@unset@|2| 520 | :a opt "" -a -a 521 | |a@unset@2@unset@|a@unset@3@unset@|3| 522 | :a opt "" -ab 523 | |a@unset@1@unset@|:@b@2@bad option: `-b'@|2| 524 | :a: opt "" -ab 525 | |a@b@2@unset@|2| 526 | :a: opt "" -a b 527 | |a@b@3@unset@|3| 528 | :a: opt "" -a -a 529 | |a@-a@3@unset@|3| 530 | :a: opt "" -a 531 | |:@a@2@option `-a' requires an argument@|2| 532 | :a:: opt "" -a 533 | |a@unset@2@unset@|2| 534 | :a:: opt "" -ab 535 | |a@b@2@unset@|2| 536 | :a:: opt "" -a b 537 | |a@unset@2@unset@|2| 538 | :ab: opt "" -ab c 539 | |a@unset@1@unset@|b@c@3@unset@|3| 540 | :a:: opt "" -a -a 541 | |a@unset@2@unset@|a@unset@3@unset@|3| 542 | :a:: opt "" -:a: 543 | |:@:@1@bad option: `-:'@|a@:@2@unset@|2| 544 | := opt "" 545 | |1| 546 | :: opt "" 547 | |1|getopts_long: invalid option specification: `::' 548 | : opt "" 549 | |1| 550 | :a:a opt "" -a 551 | |:@a@2@option `-a' requires an argument@|2| 552 | :a::a opt "" -a 553 | |a@unset@2@unset@|2| 554 | :ab:c:: opt "" -abc -cba -bac 555 | |a@unset@1@unset@|b@c@2@unset@|c@ba@3@unset@|b@ac@4@unset@|4| 556 | : opt abc 0 "" --abc 557 | |abc@unset@2@unset@|2| 558 | : opt abc no_argument "" --abc 559 | |abc@unset@2@unset@|2| 560 | : opt abc no_argument "" --abc=foo 561 | |:@abc@2@option `--abc' doesn't allow an argument@|2| 562 | : opt abc no_argument "" --abc foo 563 | |abc@unset@2@unset@|2| 564 | : opt abc 1 "" --abc=foo 565 | |abc@foo@2@unset@|2| 566 | : opt abc required_argument "" --abc foo 567 | |abc@foo@3@unset@|3| 568 | : opt abc required_argument "" --abc= 569 | |abc@@2@unset@|2| 570 | : opt abc required_argument "" --abc 571 | |:@abc@2@option `--abc' requires an argument@|2| 572 | : opt abc 2 "" --abc 573 | |abc@unset@2@unset@|2| 574 | : opt abc optional_argument "" --abc= 575 | |abc@@2@unset@|2| 576 | : opt abc optional_argument "" --abc=foo 577 | |abc@foo@2@unset@|2| 578 | : opt abc optional_argument "" --abc --abc 579 | |abc@unset@2@unset@|abc@unset@3@unset@|3| 580 | : opt abc 0 abcd 0 "" --abc 581 | |abc@unset@2@unset@|2| 582 | : opt abc 0 abd 0 "" --ab 583 | |:@ab@2@option `--ab' is ambiguous@|2| 584 | : opt abc 0 abcd 0 "" --ab 585 | |:@ab@2@option `--ab' is ambiguous@|2| 586 | : opt abc 0 abc 1 "" --ab 587 | |abc@unset@2@unset@|2| 588 | : opt abc 0 abc 1 "" --abc 589 | |abc@unset@2@unset@|2| 590 | : opt abc 0 abc 1 "" --ab 591 | |abc@unset@2@unset@|2| 592 | : opt abc 0 acd 0 "" --ab 593 | |abc@unset@2@unset@|2| 594 | :abc:d:e::f:: opt ab 0 ac 1 bc 2 cd 1 cde 2 "" -abcdef -a -f -c --a --a= --b=foo -fg 595 | |a@unset@1@unset@|b@unset@1@unset@|c@def@2@unset@|a@unset@3@unset@|f@unset@4@unset@|c@--a@6@unset@|:@a@7@option `--a' is ambiguous@|bc@foo@8@unset@|f@g@9@unset@|9| 596 | a opt "" -a 597 | |a@unset@2@unset@|2| 598 | a opt "" -a b 599 | |a@unset@2@unset@|2| 600 | a opt "" -a -a 601 | |a@unset@2@unset@|a@unset@3@unset@|3| 602 | a opt "" -ab 603 | |a@unset@1@unset@|?@unset@2@bad option: `-b'@bad option: `-b'|2| 604 | a: opt "" -ab 605 | |a@b@2@unset@|2| 606 | a: opt "" -a b 607 | |a@b@3@unset@|3| 608 | a: opt "" -a -a 609 | |a@-a@3@unset@|3| 610 | a: opt "" -a 611 | |?@unset@2@option `-a' requires an argument@option `-a' requires an argument|2| 612 | a:: opt "" -a 613 | |a@unset@2@unset@|2| 614 | a:: opt "" -ab 615 | |a@b@2@unset@|2| 616 | a:: opt "" -a b 617 | |a@unset@2@unset@|2| 618 | a:: opt "" -a -a 619 | |a@unset@2@unset@|a@unset@3@unset@|3| 620 | a:: opt "" -:a: 621 | |?@unset@1@bad option: `-:'@bad option: `-:'|a@:@2@unset@|2| 622 | = opt "" 623 | |1| 624 | : opt "" 625 | |1| 626 | '' opt "" 627 | |1| 628 | a:a opt "" -a 629 | |?@unset@2@option `-a' requires an argument@option `-a' requires an argument|2| 630 | a::a opt "" -a 631 | |a@unset@2@unset@|2| 632 | ab:c:: opt "" -abc -cba -bac 633 | |a@unset@1@unset@|b@c@2@unset@|c@ba@3@unset@|b@ac@4@unset@|4| 634 | '' opt abc 0 "" --abc 635 | |abc@unset@2@unset@|2| 636 | '' opt abc no_argument "" --abc 637 | |abc@unset@2@unset@|2| 638 | '' opt abc no_argument "" --abc=foo 639 | |?@unset@2@option `--abc' doesn't allow an argument@option `--abc' doesn't allow an argument|2| 640 | '' opt abc no_argument "" --abc foo 641 | |abc@unset@2@unset@|2| 642 | '' opt abc 1 "" --abc=foo 643 | |abc@foo@2@unset@|2| 644 | '' opt abc required_argument "" --abc foo 645 | |abc@foo@3@unset@|3| 646 | '' opt abc required_argument "" --abc= 647 | |abc@@2@unset@|2| 648 | '' opt abc required_argument "" --abc 649 | |?@unset@2@option `--abc' requires an argument@option `--abc' requires an argument|2| 650 | '' opt abc 2 "" --abc 651 | |abc@unset@2@unset@|2| 652 | '' opt abc optional_argument "" --abc= 653 | |abc@@2@unset@|2| 654 | '' opt abc optional_argument "" --abc=foo 655 | |abc@foo@2@unset@|2| 656 | '' opt abc optional_argument "" --abc --abc 657 | |abc@unset@2@unset@|abc@unset@3@unset@|3| 658 | '' opt abc 0 abcd 0 "" --abc 659 | |abc@unset@2@unset@|2| 660 | '' opt abc 0 abd 0 "" --ab 661 | |?@unset@2@option `--ab' is ambiguous@option `--ab' is ambiguous|2| 662 | '' opt abc 0 abcd 0 "" --ab 663 | |?@unset@2@option `--ab' is ambiguous@option `--ab' is ambiguous|2| 664 | '' opt abc 0 abc 1 "" --ab 665 | |abc@unset@2@unset@|2| 666 | '' opt abc 0 abc 1 "" --abc 667 | |abc@unset@2@unset@|2| 668 | '' opt abc 0 abc 1 "" --ab 669 | |abc@unset@2@unset@|2| 670 | '' opt abc 0 acd 0 "" --ab 671 | |abc@unset@2@unset@|2| 672 | abc:d:e::f:: opt ab 0 ac 1 bc 2 cd 1 cde 2 "" -abcdef -a -f -c --a --a= --b=foo -fg 673 | |a@unset@1@unset@|b@unset@1@unset@|c@def@2@unset@|a@unset@3@unset@|f@unset@4@unset@|c@--a@6@unset@|?@unset@7@option `--a' is ambiguous@option `--a' is ambiguous|bc@foo@8@unset@|f@g@9@unset@|9| 674 | : '' '' a 675 | |1|getopts_long: invalid variable name: `' 676 | : 1a '' 677 | |1|getopts_long: invalid variable name: `1a' 678 | - a 679 | |1|getopts_long: invalid option specification: `-' 680 | :a::a:abcd o ab 1 abc 1 abd 1 abe 1 abc 2 '' -aa --ab 1 --abc 681 | |a@a@2@unset@|ab@1@4@unset@|:@abc@5@option `--abc' requires an argument@|5| 682 | : 683 | |1|getopts_long: not enough arguments 684 | '\[$' o -- 0 ' ' 1 '#' required_argument '' '-\\\[$' --\ =a --\#=\$\$ 685 | |\@unset@1@unset@|\@unset@1@unset@|\@unset@1@unset@|[@unset@1@unset@|$@unset@2@unset@| @a@3@unset@|#@$$@4@unset@|4| 686 | : o a 1 b 2 c 687 | |1|getopts_long: long option specifications must end in an empty argument 688 | : o a 1 b 2 689 | |1|getopts_long: long option specifications must end in an empty argument 690 | : o a 1 b 2 c 3 '' --c 691 | |1|getopts_long: invalid long option type: `3' 692 | ": " o " " 1 '' "- " "-- =1" 693 | | @unset@1@unset@| @unset@2@unset@| @1@3@unset@|3| 694 | : o a 1 '' --c 695 | |:@c@2@bad option: `--c'@|2| 696 | : o a 1 '' --c=foo 697 | |:@c@2@bad option: `--c'@|2| 698 | : o ab 1 ac 1 ad 1 a 1 '' --a=1 699 | |a@1@2@unset@|2| 700 | EOF 701 | fi 702 | -------------------------------------------------------------------------------- /locvar.sh: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2008 Stephane Chazelas 3 | # 4 | # Feel free to use that code. 5 | # 6 | PS4='$_l_fstack> ' 7 | # functions that are meant to have a local scope (that use "locvar") should be 8 | # declared as: 9 | # sub funcname; _funcname() { ... 10 | # When called as "funcname", it gets its own name space for variables, 11 | # when called as "_funcname", it uses the one of its caller. 12 | sub() { eval "$1() { call _$1 \"\$@\"; }"; } 2> /dev/null 13 | 14 | # locvar, call, sub and locopt implement a local name space for variables 15 | # and shell options. Variables whose name starts with _l_ are reserved 16 | # for those. 17 | locvar() { 18 | for _l_var do 19 | # push previous variable value onto a stack if not there already 20 | # if the variable is not set, store as an empty value in _l${_l}_$_l_var. 21 | # otherwise, prepend its value with "+" 22 | eval "[ -z \"\${_l${_l}_$_l_var++}\" ] && 23 | _l$_l=\"\${_l$_l} \$_l_var\" && 24 | _l${_l}_$_l_var=\${$_l_var++\$$_l_var}" 25 | done 26 | } 2> /dev/null 27 | 28 | set_last_exit_status() { 29 | return "$1" 30 | } 2> /dev/null 31 | 32 | call() { 33 | # implements a call stack and variable stack. 34 | # _l is the numerical depth of the stack 35 | # _l_fname is the current function name 36 | # _l_fstack is the call stack 37 | # _l$_l is the list of variables pushed onto stack $_l 38 | # _l${_l}_ is variable varname pushed onto stack $l 39 | # _l_option_restore is the list of pushed options. 40 | # 41 | # sets up the current stack at the calling level for "locvar" and "locopt" 42 | # to use, calls the function passed as argument, and then restores the 43 | # stack before returning. 44 | 45 | { 46 | _l_ret=$? 47 | 48 | _l=$((${_l:-0} + 1)) 49 | unset "_l$_l" 50 | 51 | locvar _l_fname _l_fstack _l_option_restore 52 | _l_fname="${1#_}" 53 | _l_fstack="$_l_fstack+$_l_fname" 54 | _l_option_restore= 55 | 56 | case $1 in 57 | (_*) eval "[ -n \"\${_lx$1}\" ] && 58 | locopt -x" 59 | esac 60 | set_last_exit_status "$_l_ret" 61 | } 2> /dev/null 62 | 63 | "$@" 64 | 65 | { 66 | _l_ret=$? 67 | 68 | # restore options 69 | [ -z "$_l_option_restore" ] || 70 | eval "set $_l_option_restore" 71 | 72 | # restore stack 73 | locvar IFS 74 | IFS=" " 75 | eval "_l_var=\${_l$_l}" 76 | for _l_var in $_l_var; do 77 | eval "$_l_var=\${_l${_l}_$_l_var}" 78 | if eval "[ -z \"\${$_l_var}\" ]"; then 79 | unset "$_l_var" 80 | else 81 | eval "$_l_var=\${$_l_var#+}" 82 | fi 83 | unset "_l${_l}_$_l_var" 84 | done 85 | unset "_l$_l" 86 | _l=$(($_l - 1)) 87 | return "$_l_ret" 88 | } 2> /dev/null 89 | } 90 | 91 | locopt() { 92 | for _l_opt do 93 | case $_l_option_restore in 94 | (*"${_l_opt#?}"*) ;; 95 | (*) 96 | case $- in 97 | (*"${_l_opt#?}"*) 98 | _l_option_restore="$_l_option_restore -${_l_opt#?}";; 99 | (*) 100 | _l_option_restore="$_l_option_restore +${_l_opt#?}";; 101 | esac;; 102 | esac 103 | set "$_l_opt" 104 | done 105 | } 2> /dev/null 106 | 107 | trace_fn() { 108 | eval "_lx_$1=1" 109 | } 2> /dev/null 110 | 111 | untrace_fn() { 112 | unset "_lx_$1" 113 | } 2> /dev/null 114 | 115 | # Example: 116 | 117 | var=foo 118 | sub f; _f() { 119 | locvar var 120 | var=$1 121 | echo "$var" 122 | } 123 | 124 | trace_fn f 125 | 126 | f test 127 | echo "$var" 128 | -------------------------------------------------------------------------------- /lsofc: -------------------------------------------------------------------------------- 1 | #! /usr/bin/perl 2 | # wrapper around lsof to add peer information for sockets. 3 | # 4 | # Where the "ss" command can give peer information for Unix domain 5 | # sockets, it uses that and also retrieves information on which 6 | # direction of the socket is shut down (indicated with arrows like <--, 7 | # -->, <->, ---). 8 | # 9 | # Where not (older systems), we get the information from kernel memory 10 | # (/proc/kcore). In that case, superuser privileges are required. 11 | # 12 | # Copyright Stephane Chazelas 2015, public domain. 13 | # 14 | # example without "ss": 15 | # # lsofc -ad14,21,22 -c mysqld 16 | # COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME 17 | # mysqld 1260 mysql 14u unix 0xffff880f48b48680 0t0 47793475 /var/run/mysqld/mysqld.sock -> 0xffff880f48b4aa40[authdaemond,2692] 18 | # mysqld 1260 mysql 21u IPv4 47946785 0t0 TCP localhost:mysql->localhost:44477 (ESTABLISHED) -> [proxymap,40597] 19 | # mysqld 1260 mysql 22u unix 0xffff880fbd6ab0c0 0t0 47953869 /var/run/mysqld/mysqld.sock -> 0xffff880fbd6afb80[postfix-policyd,3455] 20 | # 21 | # Example with "ss": 22 | # # lsofc -aUc packagekit 23 | # COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME 24 | # packageki 26565 root 1u unix 0xffff8800a95081c0 0t0 591416 type=STREAM --> 591417[systemd-journal,233,/run/systemd/journal/stdout] 25 | # packageki 26565 root 2u unix 0xffff8800a95081c0 0t0 591416 type=STREAM --> 591417[systemd-journal,233,/run/systemd/journal/stdout] 26 | # packageki 26565 root 3u unix 0xffff8802168f04c0 0t0 592167 type=DGRAM 27 | # packageki 26565 root 5u unix 0xffff8801bd2f0780 0t0 591426 type=STREAM <-> 592168[dbus-daemon,2268,/var/run/dbus/system_bus_socket] 28 | 29 | use Socket; 30 | 31 | my $usable_ss; 32 | my (%peer, %dir); 33 | 34 | # Try and get unix socket peer information from the ss command. 35 | # While we're at it, we also use -e to get direction (-->, <-->...) 36 | if (open SS, '-|', 'ss', '-nexa') { 37 | while () { 38 | # parse unix domain list. 39 | if (/\s(\d+)\s+\*\s+(\d+) ([<-]-[->])$/) { 40 | # if we find a non-null peer, that means we can probably trust ss 41 | $usable_ss = 1 if $2; 42 | $peer{$1} = $2; 43 | $dir{$1} = $3; 44 | } 45 | } 46 | close SS; 47 | } 48 | 49 | my (%fields, %proc, %net); 50 | 51 | # get an idea of what [command,pid] has any given (unix or tcp) socket 52 | # open. We store the information in the keys of a hash for each socket. 53 | open LSOF, '-|', qw{lsof -nMPFpctidn -U -i@[::1] -i@127.0.0.1}; 54 | while () { 55 | if (/(.)(.*)/) { 56 | $fields{$1} = $2; 57 | if ($1 eq 'n') { 58 | if ($fields{t} eq 'unix') { 59 | $proc{$usable_ss ? $fields{i} : hex $fields{d}}->{"$fields{c},$fields{p}" . 60 | ($fields{n} =~ m{^([@/].*?)( type=\w+)?$} ? ",$1" : "")} = ""; 61 | } else { 62 | # for TCP sockets, We try to identify peers of loopback connections. 63 | # Here we store a: "x:p->y:q" -> ["cmd,pid"...] relationship using 64 | # numerical values for x,y,p,q. 65 | $net{$fields{n}}->{"$fields{c},$fields{p}"} = ""; 66 | } 67 | } 68 | } 69 | } 70 | close LSOF; 71 | 72 | if (!$usable_ss) { 73 | # if we can't use ss, revert to getting peer information from kernel memory. 74 | # That works pretty well even for very old systems but requires superuser 75 | # privileges. 76 | open K, "<", "/proc/kcore" or die "open kcore: $!"; 77 | read K, $h, 8192 # should be more than enough 78 | or die "read kcore: $!"; 79 | 80 | # parse ELF header 81 | my ($t,$o,$n) = unpack("x4Cx[C19L!]L!x[L!C8]S", $h); 82 | $t = $t == 1 ? "L3x4Lx12" : "Lx4QQx8Qx16"; # program header ELF32 or ELF64 83 | my @headers = unpack("x$o($t)$n",$h); 84 | 85 | # helper to read data from kcore at given address (obtaining file offset from 86 | # ELF @headers) 87 | sub readaddr { 88 | my @h = @headers; 89 | my ($addr, $length) = @_; 90 | my $offset; 91 | while (my ($t, $o, $v, $s) = splice @h, 0, 4) { 92 | if ($addr >= $v && $addr < $v + $s) { 93 | $offset = $o + $addr - $v; 94 | if ($addr + $length - $v > $s) { 95 | $length = $s - ($addr - $v); 96 | } 97 | last; 98 | } 99 | } 100 | return undef unless defined($offset); 101 | seek K, $offset, 0 or die "seek kcore: $!"; 102 | my $ret; 103 | read K, $ret, $length or die "read($length) kcore \@$offset: $!"; 104 | return $ret; 105 | } 106 | 107 | # create a dummy socketpair to try and find the offset of the 108 | # peer member in the kernel structure 109 | socketpair(Rdr, Wtr, AF_UNIX, SOCK_STREAM, PF_UNSPEC) 110 | or die "socketpair: $!"; 111 | my $r = readlink("/proc/self/fd/" . fileno(Rdr)) or die "readlink Rdr: $!"; 112 | $r =~ /\[(\d+)/; $r = $1; 113 | my $w = readlink("/proc/self/fd/" . fileno(Wtr)) or die "readlink Wtr: $!"; 114 | $w =~ /\[(\d+)/; $w = $1; 115 | # now $r and $w contain the socket inodes of both ends of the socketpair 116 | die "Can't determine peer offset" unless $r && $w; 117 | 118 | # get the inode->address mapping 119 | my %addr; 120 | open U, "<", "/proc/net/unix" or die "open unix: $!"; 121 | while () { 122 | if (/^([0-9a-f]+):(?:\s+\S+){5}\s+(\d+)/) { 123 | $addr{$2} = hex $1; 124 | } 125 | } 126 | close U; 127 | 128 | die "Can't determine peer offset" unless $addr{$r} && $addr{$w}; 129 | 130 | # read 2048 bytes starting at the address of Rdr and hope to find 131 | # the address of Wtr referenced somewhere in there. 132 | my $around = readaddr $addr{$r}, 2048; 133 | my $offset = 0; 134 | my $ptr_size = length(pack("L!",0)); 135 | my $found; 136 | for (unpack("L!*", $around)) { 137 | if ($_ == $addr{$w}) { 138 | $found = 1; 139 | last; 140 | } 141 | $offset += $ptr_size; 142 | } 143 | die "Can't determine peer offset" unless $found; 144 | 145 | # now retrieve peer for each socket 146 | for my $inode (keys %addr) { 147 | $peer{$addr{$inode}} = unpack("L!", readaddr($addr{$inode}+$offset,$ptr_size)); 148 | } 149 | close K; 150 | } 151 | 152 | # Now to be able to process host and service names, we need to know what 153 | # host name the system uses for the loop back interface addresses 154 | # (things like "localhost", "ip6-localhost"). These should work even for 155 | # very old perls: 156 | my ($l4) = gethostbyaddr(pack("C4",127,0,0,1), AF_INET); 157 | my ($l6) = gethostbyaddr(pack("x15C",1), AF_INET6); 158 | my %name_to_num = ( 159 | $l4 => "127.0.0.1", 160 | $l6 => "[::1]" 161 | ); 162 | # regexp to match localhost as IPv4 or IPv6 (numerical or name): 163 | my $localhost = join "|", map {qr{\Q$_\E}} keys %name_to_num, values %name_to_num; 164 | $localhost = qr{$localhost}; 165 | 166 | # and finally process the lsof output 167 | open LSOF, '-|', 'lsof', @ARGV; 168 | LINE: while () { 169 | chomp; 170 | if ($usable_ss) { 171 | # we use the inode number (decimal, so we rely on it being the 3rd 172 | # field after "unix" 173 | if (/\sunix\s+\S+\s+\S+\s+(\d+)\s/) { 174 | my $peer = $peer{$1}; 175 | if (defined($peer)) { 176 | $_ .= $peer ? 177 | " ${dir{$1}} $peer\[" . (join("|", keys%{$proc{$peer}})||"?") . "]" : 178 | "[LISTENING]"; 179 | next LINE; 180 | } 181 | } 182 | } else { 183 | # we use the unix_sock address as hex number 184 | for my $addr (/0x[0-9a-f]+/g) { 185 | $addr = hex $addr; 186 | my $peer = $peer{$addr}; 187 | if (defined($peer)) { 188 | $_ .= $peer ? 189 | sprintf(" -> 0x%x[", $peer) . join("|", keys%{$proc{$peer}}) . "]" : 190 | "[LISTENING]"; 191 | next LINE; 192 | } 193 | } 194 | } 195 | # Handle TCP connections: 196 | if (/\s($localhost):([\w-]+)->($localhost):([\w-]+)\s/) { 197 | my ($a, $ap, $b, $bp) = ($1, $2, $3, $4); 198 | # convert to numerical form, assume 127.1 and [::1] for 199 | # loopback addresses 200 | $a = $name_to_num{$a} || $a; 201 | $b = $name_to_num{$b} || $b; 202 | (undef, undef, $ap) = getservbyname($ap, "tcp") if $ap =~ /\D/; 203 | (undef, undef, $bp) = getservbyname($bp, "tcp") if $bp =~ /\D/; 204 | my $peer = $net{"$b:$bp->$a:$ap"}; 205 | if (defined($peer)) { 206 | $_ .= " -> [" . join("|", keys(%{$peer})) . "]"; 207 | } 208 | } 209 | } continue { 210 | print "$_\n"; 211 | } 212 | close LSOF or exit(1); 213 | -------------------------------------------------------------------------------- /mouse.zsh: -------------------------------------------------------------------------------- 1 | ########################################################################### 2 | # zsh mouse (and X clipboard) support v1.6 3 | ########################################################################### 4 | # 5 | # Copyright 2004-2011 Stephane Chazelas 6 | # 7 | # Permission to use, copy, modify, distribute, and sell this software and 8 | # its documentation for any purpose is hereby granted without fee, provided 9 | # that the above copyright notice appear in all copies and that both that 10 | # copyright notice and this permission notice appear in supporting 11 | # documentation. No representations are made about the suitability of this 12 | # software for any purpose. It is provided "as is" without express or 13 | # implied warranty. 14 | ########################################################################### 15 | # 16 | # QUICKSTART: jump to "how to use" below. 17 | # 18 | # currently supported: 19 | # - VT200 mouse tracking (at least xterm, gnome-terminal, rxvt) 20 | # - GPM on Linux little-endian systems such as i386 (at least) 21 | # - X clipboard handling if xsel(1) or xclip(1) is available (see 22 | # note below). 23 | # 24 | # addionnaly, if you are using xterm and don't want to use the mouse 25 | # tracking system, you can map some button click events so that they 26 | # send \E[M^X[ where is the character 0x20 + (0, 1, 2) 27 | # , are the coordinate of the mouse pointer. This is usually done 28 | # by adding those lines to your resource file for XTerm (~/.Xdefaults 29 | # for example): 30 | # 31 | # XTerm.VT100.translations: #override\ 32 | # Mod4 : ignore()\n\ 33 | # Mod4 : ignore()\n\ 34 | # Mod4 : ignore()\n\ 35 | # Mod4 : string(0x1b) string("[M ") dired-button()\n\ 36 | # Mod4 : string(0x1b) string("[M!") dired-button()\n\ 37 | # Mod4 : string(0x1b) string("[M") string(0x22) dired-button()\n\ 38 | # Mod4 ,: string(0x10)\n\ 39 | # Mod4 ,: string(0xe) 40 | # 41 | # That maps the button click events with the modifier 4 (when you hold 42 | # the Key [possibly Windows keys] under recent versions of 43 | # XFree86). The last two lines are for an easy support of the mouse 44 | # wheel (map the mouse wheel events to ^N and ^P) 45 | # 46 | # Remember that even if you use the mouse tracking, you can still have 47 | # access to the normal xterm selection mechanism by holding the 48 | # key. 49 | # 50 | # Note about X selection. 51 | # By default, xterm uses the PRIMARY selection instead of CLIPBOARD 52 | # for copy-paste. You may prefer changing that if you want 53 | # to insert the CLIPBOARD and a better communication 54 | # between xterm and clipboard based applications like mozilla. 55 | # A way to do that is to add those resources: 56 | # XTerm.VT100.translations: #override\ 57 | # Shift ~Ctrl Insert:insert-selection(\ 58 | # CLIPBOARD, CUT_BUFFER0, PRIMARY) \n\ 59 | # Shift Ctrl Insert:insert-selection(\ 60 | # PRIMARY, CUT_BUFFER0, CLIPBOARD) \n\ 61 | # ~Ctrl ~Meta: select-end(PRIMARY,CUT_BUFFER0,CLIPBOARD) 62 | # 63 | # and to run a clipboard manager application such as xclipboard 64 | # (whose invocation you may want to put in your X session startup 65 | # file). ( inserts the PRIMARY selection as does 66 | # the middle mouse button). (without xclipboard, the clipboard 67 | # content is lost whenever the text is no more selected). 68 | # 69 | # How to use: 70 | # 71 | # add to your ~/.zshrc: 72 | # . /path/to/this-file 73 | # zle-toggle-mouse 74 | # 75 | # and if you want to be able to toggle on/off the mouse support: 76 | # bindkey -M emacs '\em' zle-toggle-mouse 77 | # # m to toggle the mouse in emacs mode 78 | # bindkey -M vicmd M zle-toggle-mouse 79 | # # M for vi (cmd) mode 80 | # 81 | # clicking on the button 1: 82 | # moves the cursor to the pointed location 83 | # clicking on the button 2: 84 | # inserts zsh cutbuffer at pointed location. If $DISPLAY is set and 85 | # either the xsel(1) or xclip(1) command is available, then it's the 86 | # content of the X clipboard instead that is pasted (and stored into 87 | # zsh cutbuffer). 88 | # clicking on the button 3: 89 | # stores the text between the cursor and the pointed localion 90 | # into zsh cutbuffer. Additionaly, if $DISPLAY is set and either the 91 | # xclip(1) or xsel(1) command is available, that text is put on the 92 | # clipboard. 93 | # 94 | # If xsel or xlip is available, and $DISPLAY is set (and you're in a 95 | # xterm-like terminal (even though that feature is terminal 96 | # independant)), all the keys (actually widgets) that deal with zsh 97 | # cut buffer have been modified so that the X CLIPBOARD selection is 98 | # used. So , ... will put the killed region on the X 99 | # clipboard. vi mode "p" or emacs "" will paste the X CLIPBOARD 100 | # selection. Only the keys that delete one character are not affected 101 | # (, , ). Additionnaly, the primary selection (what 102 | # is mouse highlighted and that you paste with the middle button) is put 103 | # on the clipboard (and so made available to zsh) when you press 104 | # or or X (emacs mode) or X (vicmd 105 | # mode). (note that your terminal may already do that by default, also 106 | # note that your terminal may paste the primary selection and not the 107 | # clipboard on , you may change that if you find it 108 | # confusing (see above)) 109 | # 110 | # for GPM, you may change the list of modifiers (Shift, Alt...) that 111 | # need to be on for the event to be accepted (see below). 112 | # 113 | # kterm: same as for xterm, but replace XTerm with KTerm in the resource 114 | # customization 115 | # hanterm: same as for xterm, but replace XTerm with Hanterm in the 116 | # resource customization. 117 | # Eterm: the paste(clipboard) actions don't seem to work, future 118 | # versions of mouse.zsh may include support for X cutbuffers or revert 119 | # back to PRIMARY selection to provide a better support for Eterm. 120 | # gnome-terminal: you may want to bind some keys to Edit->{copy,paste} 121 | # multi-gnome-terminal: selection looks mostly bogus to me 122 | # rxvt,aterm,[ckgt]aterm,mlterm,pterm: no support for clipboard. 123 | # GNUstep terminal: no mouse support but support for clipboard via menu 124 | # KDE x-terminal-emulator: works OK except mouse button3 that is mapped 125 | # to the context menu. Use Ctrl-Insert to put the selection on the 126 | # clipboard. 127 | # dtterm: no mouse support but the selection works OK. 128 | # 129 | # bugs: 130 | # - the GPM support was not much tested (was tested with gpm 1.19.6 on 131 | # a linux 2.6.9, AMD Athlon) 132 | # - mouse positionning doesn't work properly in "vared" if a prompt 133 | # was provided (vared -p ) 134 | # 135 | # Todo: 136 | # - write proper documentation 137 | # - customization through zstyles. 138 | # 139 | # Author: 140 | # Stephane Chazelas 141 | # 142 | # Changes: 143 | # v1.6 2011-09-15: added Copyright and License notice, no code change 144 | # v1.5 2005-03-12: bug fixes (GPM now works again), xclip prefered over 145 | # xsel as xsel is bogus. 146 | # v1.4 2005-03-01: puts both words on the cut buffer 147 | # support for CUT_BUFFER0 via xprop. 148 | # v1.3 2005-02-28: support for more X terminals, tidy-up, separate 149 | # mouse support from clipboard support 150 | # v1.2 2005-02-24: support for vi-mode. X clipboard mirroring zsh cut buffer 151 | # when possible. Bug fixes. 152 | # v1.1 2005-02-20: support for X selection through xsel or xclip 153 | # v1.0 2004-11-18: initial release 154 | 155 | # UTILITY FUNCTIONS 156 | 157 | zle-error() { 158 | local IFS=" " 159 | if [[ -n $WIDGET ]]; then 160 | # error message if zle active 161 | zle -M -- "$*" 162 | else 163 | # on stderr otherwise 164 | print -ru2 -- "$*" 165 | fi 166 | } 167 | 168 | # SELECTION/CLIPBOARD FUNCTIONS 169 | 170 | set-x-clipboard() { return 0; } 171 | get-x-clipboard() { return 1; } 172 | 173 | # find a command to read from/write to the X selections 174 | if whence xclip > /dev/null 2>&1; then 175 | x_selection_tool="xclip -sel p" 176 | x_clipboard_tool="xclip -sel c" 177 | elif whence xsel > /dev/null 2>&1; then 178 | x_selection_tool="xsel -p" 179 | x_clipboard_tool="xsel -b" 180 | else 181 | x_clipboard_tool= 182 | x_selection_tool= 183 | fi 184 | if [[ -n $x_clipboard_tool && $ZSH_X_COPY_PASTING -gt 0 ]]; then 185 | eval ' 186 | get-x-clipboard() { 187 | (( $+DISPLAY )) || return 1 188 | local r 189 | r=$('$x_clipboard_tool' -o < /dev/null 2> /dev/null && print .) 190 | r=${r%.} 191 | if [[ -n $r && $r != $CUTBUFFER ]]; then 192 | killring=("$CUTBUFFER" "${(@)killring[1,-2]}") 193 | CUTBUFFER=$r 194 | fi 195 | } 196 | set-x-clipboard() { 197 | (( ! $+DISPLAY )) || 198 | print -rn -- "$1" | '$x_clipboard_tool' -i 2> /dev/null 199 | } 200 | push-x-cut_buffer0() { 201 | # retrieve the CUT_BUFFER0 property via xprop and store it on the 202 | # CLIPBOARD selection 203 | (( $+DISPLAY )) || return 1 204 | local r 205 | r=$(xprop -root -notype 8s \$0 CUT_BUFFER0 2> /dev/null) || return 1 206 | r=${r#CUT_BUFFER0\"} 207 | r=${r%\"} 208 | r=${r//\'\''/\\\'\''} 209 | eval print -rn -- \$\'\''$r\'\'' | '$x_clipboard_tool' -i 2> /dev/null 210 | } 211 | push-x-selection() { 212 | # puts the PRIMARY selection onto the CLIPBOARD 213 | # failing that call push-x-cut_buffer0 214 | (( $+DISPLAY )) || return 1 215 | local r 216 | if r=$('$x_selection_tool' -o < /dev/null 2> /dev/null && print .) && 217 | r=${r%?} && 218 | [[ -n $r ]]; then 219 | print -rn -- $r | '$x_clipboard_tool' -i 2> /dev/null 220 | else 221 | push-x-cut_buffer0 222 | fi 223 | } 224 | ' 225 | # redefine the copying widgets so that they update the clipboard. 226 | for w in copy-region-as-kill vi-delete vi-yank vi-change vi-change-whole-line vi-change-eol; do 227 | eval ' 228 | '$w'() { 229 | zle .'$w' 230 | set-x-clipboard $CUTBUFFER 231 | } 232 | zle -N '$w 233 | done 234 | 235 | # that's a bit more complicated for those ones as we have to 236 | # re-implement the special behavior that does that if you call several 237 | # of those widgets in sequence, the text on the clipboard is the 238 | # whole text cut, not just the text cut by the latest widget. 239 | for w in ${widgets[(I).*kill-*]}; do 240 | if [[ $w = *backward* ]]; then 241 | e='$CUTBUFFER$scb' 242 | else 243 | e='$scb$CUTBUFFER' 244 | fi 245 | eval ' 246 | '${w#.}'() { 247 | local scb=$CUTBUFFER 248 | local slw=$LASTWIDGET 249 | local sbl=${#BUFFER} 250 | 251 | zle '$w' 252 | (( $sbl == $#BUFFER )) && return 253 | if [[ $slw = (.|)(backward-|)kill-* ]]; then 254 | killring=("${(@)killring[2,-1]}") 255 | CUTBUFFER='$e' 256 | fi 257 | set-x-clipboard $CUTBUFFER 258 | } 259 | zle -N '${w#.} 260 | done 261 | 262 | zle -N push-x-selection 263 | zle -N push-x-cut_buffer0 264 | 265 | # put the current selection on the clipboard upon 266 | # X or X: 267 | if (( $+terminfo[kSI] )); then 268 | bindkey -M emacs "$terminfo[kSI]" push-x-selection 269 | bindkey -M viins "$terminfo[kSI]" push-x-selection 270 | bindkey -M vicmd "$terminfo[kSI]" push-x-selection 271 | fi 272 | if (( $+terminfo[kich1] )); then 273 | # according to terminfo 274 | bindkey -M emacs "\e$terminfo[kich1]" push-x-selection 275 | bindkey -M viins "\e$terminfo[kich1]" push-x-selection 276 | bindkey -M vicmd "\e$terminfo[kich1]" push-x-selection 277 | fi 278 | # hardcode ^[[2;3~ which is sent by on xterm 279 | bindkey -M emacs '\e[2;3~' push-x-selection 280 | bindkey -M viins '\e[2;3~' push-x-selection 281 | bindkey -M vicmd '\e[2;3~' push-x-selection 282 | # hardcode ^[^[[2;5~ which is sent by on some terminals 283 | bindkey -M emacs '\e\e[2~' push-x-selection 284 | bindkey -M viins '\e\e[2~' push-x-selection 285 | bindkey -M vicmd '\e\e[2~' push-x-selection 286 | 287 | # hardcode ^[[2;5~ which is sent by on xterm 288 | # some terminals have already such a feature builtin (gnome/KDE 289 | # terminals), others have no distinguishable character sequence sent 290 | # by 291 | bindkey -M emacs '\e[2;5~' push-x-selection 292 | bindkey -M viins '\e[2;5~' push-x-selection 293 | bindkey -M vicmd '\e[2;5~' push-x-selection 294 | 295 | # same for rxvt: 296 | bindkey -M emacs '\e[2^' push-x-selection 297 | bindkey -M viins '\e[2^' push-x-selection 298 | bindkey -M vicmd '\e[2^' push-x-selection 299 | 300 | # for terminals without an insert key: 301 | bindkey -M vicmd X push-x-selection 302 | bindkey -M emacs '^XX' push-x-selection 303 | 304 | # the convoluted stuff below is to work around two problems: 305 | # 1- we can't just redefine the widgets as then yank-pop would 306 | # stop working 307 | # 2- we can't just rebind the keys to as 308 | # then we'll loose the numeric argument 309 | propagate-numeric() { 310 | # next key (\e[0-dum) is mapped to , plus the 311 | # targeted widget with NUMERIC restored. 312 | case $KEYMAP in 313 | vicmd) 314 | bindkey -M vicmd -s '\e[0-dum' $'\e[1-dum'$NUMERIC${KEYS/x/};; 315 | *) 316 | bindkey -M $KEYMAP -s '\e[0-dum' $'\e[1-dum'${NUMERIC//(#m)?/$'\e'$MATCH}${KEYS/x/};; 317 | esac 318 | } 319 | zle -N get-x-clipboard 320 | zle -N propagate-numeric 321 | bindkey -M emacs '\e[1-dum' get-x-clipboard 322 | bindkey -M vicmd '\e[1-dum' get-x-clipboard 323 | bindkey -M emacs '\e[2-dum' yank 324 | bindkey -M emacs '\e[2-xdum' propagate-numeric 325 | bindkey -M emacs -s '^Y' $'\e[2-xdum\e[0-dum' 326 | bindkey -M vicmd '\e[3-dum' vi-put-before 327 | bindkey -M vicmd '\e[3-xdum' propagate-numeric 328 | bindkey -M vicmd -s 'P' $'\e[3-xdum\e[0-dum' 329 | bindkey -M vicmd '\e[4-dum' vi-put-after 330 | bindkey -M vicmd '\e[4-xdum' propagate-numeric 331 | bindkey -M vicmd -s 'p' $'\e[4-xdum\e[0-dum' 332 | fi 333 | 334 | 335 | # MOUSE FUNCTIONS 336 | 337 | zle-update-mouse-driver() { 338 | # default is no mouse support 339 | [[ -n $ZLE_USE_MOUSE ]] && zle-error 'Sorry: mouse not supported' 340 | ZLE_USE_MOUSE= 341 | } 342 | 343 | 344 | if [[ $TERM = *[xeEk]term* || 345 | $TERM = *mlterm* || 346 | $TERM = *rxvt* || 347 | $TERM = *screen* || 348 | ($TERM = *linux* && -S /dev/gpmctl) 349 | ]]; then 350 | 351 | set-status() { return $1; } 352 | 353 | handle-mouse-event() { 354 | emulate -L zsh 355 | local bt=$1 356 | 357 | case $bt in 358 | 3) 359 | return 0;; # Process on press, discard release 360 | # mlterm sends 3 on mouse-wheel-up but also on every button 361 | # release, so it's unusable 362 | 64) 363 | # eterm, rxvt, gnome/KDE terminal mouse wheel 364 | zle up-line-or-history 365 | return;; 366 | 4|65) 367 | # mlterm or eterm, rxvt, gnome/KDE terminal mouse wheel 368 | zle down-line-or-history 369 | return;; 370 | esac 371 | local mx=$2 my=$3 last_status=$4 372 | local cx cy i 373 | setopt extendedglob 374 | 375 | print -n '\e[6n' # query cursor position 376 | 377 | local match mbegin mend buf= 378 | 379 | while read -k i && buf+=$i && [[ $buf != *\[([0-9]##)\;[0-9]##R ]]; do :; done 380 | # read response from terminal. 381 | # note that we may also get a mouse tracking btn-release event, 382 | # which would then be discarded. 383 | 384 | [[ $buf = (#b)*\[([0-9]##)\;[0-9]##R ]] || return 385 | cy=$match[1] # we don't need cx 386 | 387 | local cur_prompt 388 | 389 | # trying to guess the current prompt 390 | case $CONTEXT in 391 | (vared) 392 | if [[ $0 = zcalc ]]; then 393 | cur_prompt=${ZCALCPROMPT-'%1v> '} 394 | setopt nopromptsubst nopromptbang promptpercent 395 | # (ZCALCPROMPT is expanded with (%)) 396 | fi;; 397 | # if vared is passed a prompt, we're lost 398 | (select) 399 | cur_prompt=$PS3;; 400 | (cont) 401 | cur_prompt=$PS2;; 402 | (start) 403 | cur_prompt=$PS1;; 404 | esac 405 | 406 | # if promptsubst, then we need first to do the expansions (to 407 | # be able to remove the visual effects) and disable further 408 | # expansions 409 | [[ -o promptsubst ]] && cur_prompt=${${(e)cur_prompt}//(#b)([\\\$\`])/\\$match} 410 | 411 | # restore the exit status in case $PS relies on it 412 | set-status $last_status 413 | 414 | # remove the visual effects and do the prompt expansion 415 | cur_prompt=${(S%%)cur_prompt//(#b)(%([BSUbsu]|{*%})|(%[^BSUbsu{}]))/$match[3]} 416 | 417 | # we're now looping over the whole editing buffer (plus the last 418 | # line of the prompt) to compute the (x,y) position of each char. We 419 | # store the characters i for which x(i) <= mx < x(i+1) for every 420 | # value of y in the pos array. We also get the Y(CURSOR), so that at 421 | # the end, we're able to say which pos element is the right one 422 | 423 | local -a pos # array holding the possible positions of 424 | # the mouse pointer 425 | local -i n x=0 y=1 cursor=$((${#cur_prompt}+$CURSOR+1)) 426 | local Y 427 | 428 | buf=$cur_prompt$BUFFER 429 | for ((i=1; i<=$#buf; i++)); do 430 | (( i == cursor )) && Y=$y 431 | n=0 432 | case $buf[i] in 433 | ($'\n') # newline 434 | : ${pos[y]=$i} 435 | (( y++, x=0 ));; 436 | ($'\t') # tab advance til next tab stop 437 | (( x = x/8*8+8 ));; 438 | ([$'\0'-$'\037'$'\200'-$'\237']) 439 | # characters like ^M 440 | n=2;; 441 | (*) 442 | n=1;; 443 | esac 444 | while 445 | (( x >= mx )) && : ${pos[y]=$i} 446 | (( x >= COLUMNS )) && (( x=0, y++ )) 447 | (( n > 0 )) 448 | do 449 | (( x++, n-- )) 450 | done 451 | done 452 | : ${pos[y]=$i} ${Y:=$y} 453 | 454 | local mouse_CURSOR 455 | if ((my + Y - cy > y)); then 456 | mouse_CURSOR=$#BUFFER 457 | elif ((my + Y - cy < 1)); then 458 | mouse_CURSOR=0 459 | else 460 | mouse_CURSOR=$(($pos[my + Y - cy] - ${#cur_prompt} - 1)) 461 | fi 462 | 463 | case $bt in 464 | (0) 465 | # Button 1. Move cursor. 466 | CURSOR=$mouse_CURSOR 467 | ;; 468 | 469 | (1) 470 | # Button 2. Insert selection at mouse cursor postion. 471 | get-x-clipboard 472 | BUFFER=$BUFFER[1,mouse_CURSOR]$CUTBUFFER$BUFFER[mouse_CURSOR+1,-1] 473 | (( CURSOR = $mouse_CURSOR + $#CUTBUFFER )) 474 | ;; 475 | 476 | (2) 477 | # Button 3. Copy from cursor to mouse to cutbuffer. 478 | killring=("$CUTBUFFER" "${(@)killring[1,-2]}") 479 | if (( mouse_CURSOR < CURSOR )); then 480 | CUTBUFFER=$BUFFER[mouse_CURSOR+1,CURSOR+1] 481 | else 482 | CUTBUFFER=$BUFFER[CURSOR+1,mouse_CURSOR+1] 483 | fi 484 | set-x-clipboard $CUTBUFFER 485 | ;; 486 | esac 487 | } 488 | 489 | zle -N handle-mouse-event 490 | 491 | handle-xterm-mouse-event() { 492 | local last_status=$? 493 | emulate -L zsh 494 | local bt mx my 495 | 496 | # either xterm mouse tracking or bound xterm event 497 | # read the event from the terminal 498 | read -k bt # mouse button, x, y reported after \e[M 499 | bt=$((#bt & 0x47)) 500 | read -k mx 501 | read -k my 502 | if [[ $mx = $'\030' ]]; then 503 | # assume event is \E[Mdired-button()(^X\EG) 504 | read -k mx 505 | read -k mx 506 | read -k my 507 | (( my = #my - 31 )) 508 | (( mx = #mx - 31 )) 509 | else 510 | # that's a VT200 mouse tracking event 511 | (( my = #my - 32 )) 512 | (( mx = #mx - 32 )) 513 | fi 514 | handle-mouse-event $bt $mx $my $last_status 515 | } 516 | 517 | zle -N handle-xterm-mouse-event 518 | 519 | if [[ $TERM = *linux* && -S /dev/gpmctl ]]; then 520 | # GPM mouse support 521 | if zmodload -i zsh/net/socket; then 522 | 523 | zle-update-mouse-driver() { 524 | if [[ -n $ZLE_USE_MOUSE ]]; then 525 | if (( ! $+ZSH_GPM_FD )); then 526 | if zsocket -d 9 /dev/gpmctl; then 527 | ZSH_GPM_FD=$REPLY 528 | # gpm initialisation: 529 | # request single click events with given modifiers 530 | local -A modifiers 531 | modifiers=( 532 | none 0 533 | shift 1 534 | altgr 2 535 | ctrl 4 536 | alt 8 537 | left-shift 16 538 | right-shift 32 539 | left-ctrl 64 540 | right-ctrl 128 541 | caps-shift 256 542 | ) 543 | local min max 544 | # modifiers that need to be on 545 | min=$((modifiers[none])) 546 | # modifiers that may be on 547 | max=$min 548 | 549 | # send 16 bytes: 550 | # 1-2: LE short: requested events (btn down = 0x0004) 551 | # 3-4: LE short: event passed through (~GPM_HARD=0xFEFF) 552 | # 5-6: LE short: min modifiers 553 | # 7-8: LE short: max modifiers 554 | # 9-12: LE int: pid 555 | # 13-16: LE int: virtual console number 556 | 557 | print -u$ZSH_GPM_FD -n "\4\0\377\376\\$(([##8]min&255 558 | ))\\$(([##8]min>>8))\\$(([##8]max&255))\\$(([##8]max>>8 559 | ))\\$(([##8]$$&255))\\$(([##8]$$>>8&255))\\$(( 560 | [##8]$$>>16&255))\\$(( [##8]$$>>24))\\$(( 561 | [##8]${TTY#/dev/tty}))\0\0\0" 562 | zle -F $ZSH_GPM_FD handle-gpm-mouse-event 563 | else 564 | zle-error 'Error: unable to connect to GPM' 565 | ZLE_USE_MOUSE= 566 | fi 567 | fi 568 | else 569 | # ZLE_USE_MOUSE disabled, close GPM connection 570 | if (( $+ZSH_GPM_FD )); then 571 | eval "exec $ZSH_GPM_FD>&-" 572 | # what if $ZSH_GPM_FD > 9 ? 573 | zle -F $ZSH_GPM_FD # remove the handler 574 | unset ZSH_GPM_FD 575 | fi 576 | fi 577 | } 578 | 579 | handle-gpm-mouse-event() { 580 | local last_status=$? 581 | local event i 582 | if read -u$1 -k28 event; then 583 | local buttons x y 584 | (( buttons = ##$event[1] )) 585 | (( x = ##$event[9] + ##$event[10] << 8 )) 586 | (( y = ##$event[11] + ##$event[12] << 8 )) 587 | zle handle-mouse-event $(( (5 - (buttons & -buttons)) / 2 )) $x $y $last_status 588 | zle -R # redraw buffer 589 | else 590 | zle -M 'Error: connection to GPM lost' 591 | ZLE_USE_MOUSE= 592 | zle-update-mouse-driver 593 | fi 594 | } 595 | fi 596 | else 597 | # xterm-like mouse support 598 | zmodload -i zsh/parameter # needed for $functions 599 | 600 | zle-update-mouse-driver() { 601 | if [[ -n $WIDGET ]]; then 602 | if [[ -n $ZLE_USE_MOUSE ]]; then 603 | print -n '\e[?1000h' 604 | else 605 | print -n '\e[?1000l' 606 | fi 607 | fi 608 | } 609 | 610 | if [[ $functions[precmd] != *ZLE_USE_MOUSE* ]]; then 611 | functions[precmd]+=' 612 | [[ -n $ZLE_USE_MOUSE ]] && print -n '\''\e[?1000h'\' 613 | fi 614 | if [[ $functions[preexec] != *ZLE_USE_MOUSE* ]]; then 615 | functions[preexec]+=' 616 | [[ -n $ZLE_USE_MOUSE ]] && print -n '\''\e[?1000l'\' 617 | fi 618 | 619 | bindkey -M emacs '\e[M' handle-xterm-mouse-event 620 | bindkey -M viins '\e[M' handle-xterm-mouse-event 621 | bindkey -M vicmd '\e[M' handle-xterm-mouse-event 622 | 623 | if [[ $TERM = *Eterm* ]]; then 624 | # Eterm sends \e[5Mxxxxx on drag events, be want to discard them 625 | discard-mouse-drag() { 626 | local junk 627 | read -k5 junk 628 | } 629 | zle -N discard-mouse-drag 630 | bindkey -M emacs '\e[5M' discard-mouse-drag 631 | bindkey -M viins '\e[5M' discard-mouse-drag 632 | bindkey -M vicmd '\e[5M' discard-mouse-drag 633 | fi 634 | fi 635 | 636 | fi 637 | 638 | zle-toggle-mouse() { 639 | # If no prefix, toggle state. 640 | # If positive prefix, turn on. 641 | # If zero or negative prefix, turn off. 642 | 643 | # Allow this to be used as a normal function, too. 644 | if [[ -n $1 ]]; then 645 | local PREFIX=$1 646 | fi 647 | if (( $+PREFIX )); then 648 | if (( PREFIX > 0 )); then 649 | ZLE_USE_MOUSE=1 650 | else 651 | ZLE_USE_MOUSE= 652 | fi 653 | else 654 | if [[ -n $ZLE_USE_MOUSE ]]; then 655 | ZLE_USE_MOUSE= 656 | else 657 | ZLE_USE_MOUSE=1 658 | fi 659 | fi 660 | zle-update-mouse-driver 661 | } 662 | zle -N zle-toggle-mouse 663 | -------------------------------------------------------------------------------- /which_interpreter: -------------------------------------------------------------------------------- 1 | 'echo' +"'[{php }\ 2 | @GOTO DOS [exit[set 1 [[set 2 package] names];set 3 Tcl\ [info patchlevel];\ 3 | if {[lsearch -exact $1 Expect]>=0} {puts expect\ [$2 require Expect]\ ($3)} \ 4 | elseif {[lsearch -exact $1 Tk]>=0} {puts wish\ ($3,\ Tk\ [$2 require Tk])} \ 5 | else {puts $3}]]]' >/dev/null ' {\">/dev/null \ 6 | ">"/dev/null" +"\'";q="#{",1//2,"}";a=+1;q='''=.q,';q=%{\" 7 | 'echo' /*>/dev/null 8 | echo ">/dev/null;status=0;@ {status=1};*=(" '$' ");~ $status 1&&{e='"\ 9 | "';eval catch $2 ^'&version {eval ''echo <='^ $2 ^'&version''}';exit};e='"\ 10 | "';if (eval '{let ''a^~a''} >[2] /dev/null'){e='"\ 11 | "';exec echo akanga};eval exec echo rc $2 ^ version;\" > /dev/null 12 | : #;echo possibly pre-Bourne UNIX V1-6 shell;exit 13 | if (! $?version) set version=csh;exec echo $version 14 | :DOS 15 | @CLS 16 | @IF NOT "%DOSEMU_VERSION%"=="" ECHO DOSEMU %DOSEMU_VERSION% 17 | @ECHO %OS% %COMSPEC% 18 | @VER 19 | @GOTO FIN 20 | ", unless eval 'printf "perl %vd\n",$^V;exit;'> "/dev/null";eval ': "\''; 21 | =S"';f=false e=exec\ echo n=/dev/null v=SH_VERSION;`(eval "f() { echo : 22 | };f")2>$n` $f||$e Bourne-like shell without function 23 | case `(: ${_z_?1}) 2>&1` in 1) $e ash/BSD sh;;esac;t(){ 24 | eval "\${$1$v+:} $f &&exec echo ${2}sh \$$1$v";};t BA ba;t Z z;t PO po;t YA ya 25 | case `(typeset -Z2 b=0;$e $b)2>$n` in 00) (eval ':${.}')2>$n&&eval ' 26 | $e ksh93 ${.sh.version}';t K pdk;$e ksh88;;esac;case `(eval '$e ${f#*s}$($e 1 27 | )$((1+1))')2>$n` in e12)$e POSIX shell;;esac;$e Bourne-like shell;: } 28 | print "ruby ",RUBY_VERSION,"\n";exit;' ''';import sys 29 | print("python "+sys.version);z='''*/; 30 | s="";j="JavaScript";if(typeof process=="object"){p=console.log;p(process.title 31 | ,process.version)}else{p=print;p((f="function")==(t=typeof version)?"string"== 32 | typeof(v=version())?v:(typeof build!=f?"":s= "SpiderMonkey ")+j+" "+v:(t== 33 | "undefined"?j+"?":version)+"\n");if(s)build()}/* 34 | :FIN } *///''' 35 | 36 | -------------------------------------------------------------------------------- /wide_strftime.sh: -------------------------------------------------------------------------------- 1 | div() # args: x, y 2 | # returns the integer before $1 / $2 ($(($1/$2)) is not OK for 3 | # negative numbers 4 | { 5 | REPLY=$(($1 / $2)) 6 | [ "$(($REPLY * $2))" -gt "$1" ] && REPLY=$(($REPLY - 1)) 7 | } 8 | 9 | days_since_epoch() # args: year, month, day 10 | { 11 | # returns (in $REPLY) the number of days since 1970/1/1 GMT 12 | # valid for any date in the limit of your integer size. 13 | # Expects y/m/d in the Gregorian calendar from 1752/9/14 on, 14 | # and in the Julian calendar until 1752/9/2. Note that even 15 | # though there were no days 3 nor 4 nor... 13 in September 16 | # 1752, if you provide those you will get the date in the 17 | # Gregorian calendar. days_since_epoch(1752, 9, 13) == 18 | # days_since_epoch(1752, 9, 2). 19 | 20 | # "set" is used to avoid clobbering the variable namespace 21 | # with a temporary variable 22 | set -- "$((12 * ($1 + ($1 < 0)) + $2 - 3))" "$3" 23 | div "$1" 12 24 | set -- "$1" "$REPLY" "$2" 25 | div "$((367 * $1 + 7))" 12 26 | set -- "$1" "$2" "$3" "$REPLY" 27 | div "$2" 4 28 | set -- "$1" "$2" "$3" "$(($4 - 2 * $2 + $REPLY + $3))" 29 | if [ "$1" -eq 21030 ] && [ "$3" -lt 3 ] || [ "$1" -lt 21030 ]; then 30 | REPLY=$(($4 - 719471)) 31 | else 32 | div "$2" 100 33 | set -- "$2" "$(($4 - $REPLY))" 34 | div "$1" 400 35 | REPLY=$(($2 + $REPLY - 719469)) 36 | fi 37 | } 38 | 39 | is_leap_year() # args: year 40 | { 41 | [ "$(($1 % 4))" -eq 0 ] && { 42 | [ "$(($1 % 100))" -ne 0 ] || [ "$(($1 % 400))" -eq 0 ] \ 43 | || [ "$1" -le 1752 ] 44 | } 45 | } 46 | 47 | timegm() # args: year, month, day, hour, minute, second 48 | { 49 | days_since_epoch "$1" "$2" "$3" 50 | REPLY=$(($6 + 60 * ($5 + 60 * ($4 + 24 * $REPLY)))) 51 | } 52 | 53 | wide_strftime() # args: format, seconds-since-epoch 54 | { 55 | # a POSIX shell strftime implementation but with a wider range 56 | # (provided your shell numbers are 64 bit large). This one 57 | # assumes a GMT timezone and a POSIX LC_TIME. It should be 58 | # valid from 292,271,021,077 BCE (Julian Calendar, so, far 59 | # before the Big Bang) to 292,277,026,596 (Gregorian 60 | # Calendar). 61 | # The computed date is in the Gregorian Calendar from 62 | # 1752-9-14 on and in the Julian Calendar before (the day 63 | # before is 1752-9-2) just as the POSIX cal(1) utility. This 64 | # corresponds to the date when Great Britain adopted the 65 | # Gregorian calendar, that may be different in other 66 | # countries. 67 | # Appart from the directives defined by SUSv3, there is also 68 | # %J which gives the Julian day number (number of days since 69 | # 4713/1/1 12:00 BCE), useful for google "daterange"s, and GNU 70 | # strftime extensions %k, %l, %P, %s. 71 | # Dates before 0001/1/1 (there is no year 0) are noted -. 72 | # -0001/1/1 is January the 1st 0001 BCE. 73 | # Note that %C is negative, %y, %g are positive for a negative 74 | # year. %Y is always %C%y but %C * 100 + %y only for positive 75 | # years. %G is not always %C%g (for instance on 2199/12/31) 76 | # 77 | # Note that one usage of wide_strftime can be: 78 | # wide_strftime "" 123456789 79 | # echo "Date is $T_c" 80 | 81 | T_s=$2 82 | div "$2" 86400 83 | T_d=$REPLY 84 | T_S=$(($2 - $T_d * 86400)) 85 | T_d=$(($T_d + 719468)) 86 | T_J=$(($T_d + 1721120)) # Julian day 87 | div "$(($T_d + 3))" 7 88 | T_w=$(($T_d + 3 - $REPLY * 7)) 89 | REPLY="Sunday:0:Monday:1:Tuesday:2:Wednesday:3 90 | :Thursday:4:Friday:5:Saturday:6" 91 | T_A=${REPLY%%":$T_w"*} 92 | T_A=${T_A##*:} 93 | T_a=${T_A%"${T_A#???}"} 94 | T_j=60 95 | if [ "$T_d" -lt 640102 ]; then 96 | T_d=$(($T_d + 2)) 97 | else 98 | [ "$T_d" -lt 640211 ] && T_j=$(($T_j - 11)) 99 | div "$((4 * $T_d + 3))" 146097 100 | T_d=$(($T_d + $REPLY)) 101 | div "$REPLY" 4 102 | T_d=$(($T_d - $REPLY)) 103 | fi 104 | div "$((4 * $T_d + 3))" 1461 105 | T_Y=$REPLY 106 | div "$(($T_Y * 1461))" 4 107 | T_d=$(($T_d - $REPLY)) 108 | T_j=$(($T_j + $T_d)) 109 | T_m=$(((5 * $T_d + 2) / 153)) 110 | T_d=$(($T_d - (153 * $T_m + 2) / 5 + 1)) 111 | T_H=$(($T_S / 3600)) 112 | if [ "$T_H" -lt 12 ]; then 113 | T_p=AM 114 | T_P=am 115 | T_J=$(($T_J - 1)) 116 | else 117 | T_p=PM 118 | T_P=pm 119 | fi 120 | T_I=$((($T_H + 23) % 12 + 1)) 121 | T_S=$(($T_S % 3600)) 122 | T_M=$(($T_S / 60)) 123 | T_S=$(($T_S % 60)) 124 | T_m=$(($T_m + 3)) 125 | if [ "$T_m" -gt 12 ]; then 126 | T_Y=$(($T_Y + 1)) 127 | T_m=$(($T_m - 12)) 128 | T_j=$(($T_j - 365)) 129 | fi 130 | [ "$T_m" -gt 2 ] && is_leap_year "$T_Y" && T_j=$(($T_j + 1)) 131 | T_G=$T_Y 132 | T_U=$((($T_j - 1) / 7)) 133 | T_W=$T_U 134 | REPLY=$((($T_j - 1) % 7)) 135 | [ "$REPLY" -ge "$T_w" ] && T_U=$(($T_U + 1)) 136 | [ "$REPLY" -ge "$((($T_w + 6) % 7))" ] && T_W=$(($T_W + 1)) 137 | T_V=$T_W 138 | REPLY=$((($T_j + 7 - $T_w) % 7)) # Jan 1st week day as 0=Mo .. 6=Tu 139 | [ "$REPLY" -gt 3 ] && T_V=$(($T_V + 1)) 140 | if [ "$T_V" -eq 0 ]; then # REPLY is 1 (Su), 2 (Sa) or 3 (Fr) 141 | is_leap_year "$(($T_Y - 1))" 142 | T_V=$((52 + ($REPLY > 1 + $?))) 143 | T_G=$(($T_G - 1)) 144 | elif [ "$T_m" -eq 12 ] && [ "$(($T_d - ($T_w + 6) % 7))" -gt 28 ] 145 | then 146 | T_V=1 147 | T_G=$(($T_G + 1)) 148 | fi 149 | [ "$T_Y" -le 0 ] && T_Y=$(($T_Y - 1)) # there is no year 0 150 | [ "$T_G" -le 0 ] && T_G=$(($T_G - 1)) # there is no year 0 151 | REPLY="January:1:February:2:March:3:April:4:May:5:June:6:July:7: 152 | :August:8:September:9:October:10:November:11:December:12:" 153 | T_B=${REPLY%%":$T_m:"*} 154 | T_B=${T_B##*:} 155 | T_b=${T_B%"${T_B#???}"} 156 | T_h=$T_b 157 | T_C=${T_Y%??} 158 | eval "$(printf ' 159 | T_Y=%.4d 160 | T_G=%.4d 161 | T_c="%.3s %.3s%3d %.2d:%.2d:%.2d %.4d" 162 | T_e="%2d" 163 | T_d=%.2d 164 | T_I=%.2d 165 | T_l="%2d" 166 | T_j=%.3d 167 | T_m=%.2d 168 | T_H=%.2d 169 | T_k="%2d" 170 | T_M=%.2d 171 | T_S=%.2d 172 | T_U=%.2d 173 | T_V=%.2d 174 | T_W=%.2d 175 | T_n="\n" 176 | T_t="\t"' "$T_Y" "$T_G" "$T_a" "$T_b" "$T_d" "$T_H" "$T_M" "$T_S" \ 177 | "$T_Y" "$T_d" "$T_d" "$T_I" "$T_I" "$T_j" "$T_m" "$T_H" \ 178 | "$T_H" "$T_M" "$T_S" "$T_U" "$T_V" "$T_W" 179 | )" 180 | T_C=${T_Y%??} 181 | T_y=${T_Y#"$T_C"} 182 | T_g=${T_G#"${T_G%??}"} 183 | T_D=$T_m/$T_d/$T_y 184 | T_F=$T_Y-$T_m-$T_d 185 | T_r="$T_I:$T_M:$T_S $T_p" 186 | T_R=$T_H:$T_M 187 | T_T=$T_H:$T_M:$T_S 188 | T_x=$T_D 189 | T_X=$T_T 190 | T_z=+0000 191 | T_Z=GMT 192 | 193 | if [ -n "$1" ]; then 194 | eval " 195 | REPLY=$(printf '%s\n' "$1" | sed ' 196 | s/["$\\`]/\\&/g;s/,/,c/g;s/%%/,p/g 197 | s/%\([A-DF-JMPR-Za-hj-nprstw-z]\)/${T_\1}/g 198 | s/,p/%/g;s/,c/,/g;1s/^/"/;$s/$/"/')" 199 | else 200 | # optimization if you only want to access the T_* vars 201 | REPLY= 202 | fi 203 | } 204 | --------------------------------------------------------------------------------