aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README4
-rwxr-xr-xaddemup125
-rwxr-xr-xbsgrep77
-rw-r--r--lcd.sh23
-rwxr-xr-xlitterbox465
-rwxr-xr-xslacklog3
-rwxr-xr-xstealvim98
-rwxr-xr-xtermbin44
-rwxr-xr-xtolatin8
-rwxr-xr-xuleft25
-rwxr-xr-xvol110
11 files changed, 905 insertions, 77 deletions
diff --git a/README b/README
index 0215e2a..035adf7 100644
--- a/README
+++ b/README
@@ -1,5 +1,6 @@
Stuff from my ~/bin directory.
+addemup - add up numbers in stdin, files, or command line args; print total.
bchunkmulti - wrapper for bchunk, to support multiple .bin files
bkt - count repeats in input, show percentage/graph/etc
calc_bitrate.pl - scan a DVD, calculate bitrate for ripping
@@ -19,8 +20,10 @@ fraktur.pl - convert text to unicode fraktur/blackletter
freqnote.pl - convert a frequency in Hz to the nearest note
gammatrip.sh - randomly change gamma in X, crude simulation of an acid trip
imagebin - pastebin an image
+lcd.sh - "linked cd" for multiple terminals.
lddsafe - https://github.com/rg3/lddsafe/ (local copy here)
lddtree - show library dependencies as a tree
+litterbox - upload files/directories to litter.catbox.moe
mkclick.pl - generate a click track at a given tempo
netqiv - wget and display an image file
noobfarm2fortune.sh - scrape noobfarm.org, create fortune(6) file (no longer works!)
@@ -38,6 +41,7 @@ slacklog - show Slackware ChangeLog
slacksrc - download source directory of an official Slackware package
slacktopic.pl - set ##slackware /topic from Slackware ChangeLog
smartfmt - wrapper for fmt, ignores invariant prefixes
+stealvim - take over a vim process remotely, with reptyr
termbin - paste a file or stdin to termbin.com
uleft - start urxvt with my preferred settings
unfb2 - poor man's FictionBook2 to HTML or plain text converter
diff --git a/addemup b/addemup
new file mode 100755
index 0000000..b8b73ba
--- /dev/null
+++ b/addemup
@@ -0,0 +1,125 @@
+#!/usr/bin/perl -w
+
+use POSIX 'round';
+use Getopt::Std;
+$Getopt::Std::STANDARD_HELP_VERSION++;
+
+$VERSION = "0.0.1";
+($SELF = $0) =~ s,.*/,,;
+
+sub VERSION_MESSAGE {
+ print "$SELF $VERSION\n";
+}
+
+sub HELP_MESSAGE {
+ print <<EOF;
+$SELF - add up numbers in stdin, files, or command line args; print total.
+
+Usage: $SELF [-a] [-i] [-m] [args ...]
+
+By default, lines are read from standard input or the files given as
+arguments. All numbers (integers, floating point, or hexadecimal with
+leading 0x) found in the input are added together, and the total is
+printed to stdout.
+
+Options:
+ -a Treats the arguments as numbers to add, rather than filenames.
+ -i Integers only. Any fractional part is truncated (use -r to round).
+ -m Also print the mean (average) of the numbers read.
+ -M Print only the mean (not the total).
+ -r Round to nearest integer (implies -i).
+ -h, --help
+ Print this usage message and exit.
+ -v, --version
+ Print version number and exit.
+
+Written by B. Watson <urchlay\@slackware.uk>, licensed WTFPL.
+EOF
+}
+
+# This regular expression doesn't recognize numbers without
+# a digit before the decimal point, such as .01 or -.123. However,
+# before this is used, the caller puts a 0 in the right place for
+# such numbers.
+# Doesn't the regex syntax with /x and comments remind you of
+# assembly language?
+$re = qr {
+ ( # EITHER:
+ (?: # hex number,
+ 0[xX] # leading 0x or 0X required,
+ [0-9a-fA-F]+ # hex digits, case insensitive.
+ )
+ | # OR:
+ (?: # decimal number,
+ [-+]? # with optional leading sign,
+ \d+ # at least one digit required left of the decimal point,
+ (?:\.\d+)? # optional decimal point with trailing digits,
+ (?: # MAYBE:
+ [eE] # optional "e" or "E" for scientific notation,
+ [-+]? # optional exponent sign,
+ \d+ # at least one exponent digit,
+ )? # ...but the whole exponent part is optional!
+ )
+ )
+}x;
+
+getopts('aihmMrv', \%opt) || exit 1;
+
+VERSION_MESSAGE(), exit(0) if $opt{v};
+HELP_MESSAGE(), exit(0) if $opt{h};
+
+$opt{i} = 1 if $opt{r};
+
+$sum = $count = 0;
+
+if($opt{a}) {
+ for(@ARGV) {
+ $sum += $_ for extract_numbers();
+ }
+} else {
+ while(<>) {
+ $sum += $_ for extract_numbers();
+ }
+}
+
+print $sum . "\n" unless $opt{M};
+if($opt{m} || $opt{M}) {
+ if($count) {
+ $avg = $sum / $count;
+ $avg = to_int($avg) if $opt{i};
+ } else {
+ # always print an average, even if no numbers were read.
+ $avg = 0;
+ }
+ print $avg . "\n";
+}
+exit 0;
+
+###
+# Extract all the numbers in $_, return them an in array.
+sub extract_numbers {
+ my @ret;
+
+ # Handle numbers like .12 or -.99 by inserting a 0 before the .
+ s/(^|\D)(\.\d)/$1 . "0" . $2/ge;
+
+ for(/$re/gc) {
+ $_ = hex $_ if /^0[xX]/;
+ $_ = to_int($_) if $opt{i};
+ push @ret, $_;
+ $count++;
+ }
+
+ return @ret;
+}
+
+sub to_int {
+ warn "was: $_\n";
+ if($opt{r}) {
+ $_ = round($_);
+ } else {
+ $_ = int $_;
+ }
+ warn "now: $_\n";
+ return $_;
+}
diff --git a/bsgrep b/bsgrep
index 211a6f9..19ca3aa 100755
--- a/bsgrep
+++ b/bsgrep
@@ -22,7 +22,7 @@ $SIG{__WARN__} = sub {
# from the 'while(<>)' or File::Find.
if($m !~ /^$self:/) {
$m = "$self: $m";
- $ret = 2 unless $opt{s};
+ $ret = 2 unless $opt{q};
}
print STDERR $m unless $opt{s};
@@ -315,22 +315,29 @@ select lines that match all of the patterns; the default is to select
lines that match any of the patterns. This option doesn't exist
in B<grep>.
+=item -q
+
+Quiet: don't write to standard output. Exit status will be zero if
+a match was found, even if there were errors. This doesn't prevent
+warnings/errors being printed to standard error; use B<-s> to silence
+those. Same as B<grep>.
+
=item -r
Recursively read all files under each directory, following symlinks
only if they're on the command line. If no files or directories are
given, reads the current directory. Same as B<grep>.
-=item -v
-
-Print only lines that do I<not> match (same as B<grep>).
-
=item -s
Silence warnings (same as B<grep>). This includes error messages
about unreadable files as well as warnings about the input (see
B<DIAGNOSTICS>, below).
+=item -v
+
+Print only lines that do I<not> match (same as B<grep>).
+
=back
=head1 EXAMPLE
@@ -409,7 +416,7 @@ to be Unicode, it will be assumed ISO-8859-1, and converted to Unicode.
=head1 EXIT STATUS
0 if there were any matches, 1 if there were none, or 2 if there
-were errors (e.g. nonexistent file). However, with B<-s>, the exit
+were errors (e.g. nonexistent file). However, with B<-q>, the exit
status will be 0 or 1 even if there were errors. This is the same as
B<grep>'s exit status.
@@ -445,3 +452,61 @@ under the WTFPL: Do WTF you want with this.
B<grep>(1), B<perl>(1)
=cut
+
+__END__
+
+implemented:
+ --help
+ -V, --version
+ -F, --fixed-strings
+ -e PATTERNS, --regexp=PATTERNS
+ -i, --ignore-case
+ -v, --invert-match
+ -q, --quiet, --silent
+ -s, --no-messages
+ -n, --line-number
+ -z, --null-data
+ -r, --recursive
+ -l, --files-with-matches
+
+todo:
+ -f FILE, --file=FILE
+ -y Obsolete synonym for -i.
+ -c, --count
+ -R, --dereference-recursive
+ -L, --files-without-match
+ -Z, --null
+ -A NUM, --after-context=NUM
+ -B NUM, --before-context=NUM
+ -C NUM, -NUM, --context=NUM
+ -H, --with-filename
+ -h, --no-filename
+ -w, --word-regexp
+ -x, --line-regexp
+
+do not implement:
+ -E, --extended-regexp
+ -G, --basic-regexp
+ -P, --perl-regexp
+ --no-ignore-case
+
+undecided:
+ --color[=WHEN], --colour[=WHEN]
+ -m NUM, --max-count=NUM
+ -o, --only-matching
+ -b, --byte-offset
+ --label=LABEL
+ -T, --initial-tab
+ --group-separator=SEP
+ --no-group-separator
+ -a, --text
+ --binary-files=TYPE
+ -D ACTION, --devices=ACTION
+ -d ACTION, --directories=ACTION
+ --exclude=GLOB
+ --exclude-from=FILE
+ --exclude-dir=GLOB
+ -I
+ --include=GLOB
+ --line-buffered
+ -U, --binary
diff --git a/lcd.sh b/lcd.sh
new file mode 100644
index 0000000..1cd19ea
--- /dev/null
+++ b/lcd.sh
@@ -0,0 +1,23 @@
+# lcd.sh - "Linked" cd, for people who use multiple terminals.
+
+# Copy me to e.g. ~/.lcd.sh, then in your .bash_profile, .bashrc,
+# or whatever shell startup script you use:
+
+# [ -e ~/.lcd.sh ] && source ~/.lcd.sh
+
+# Log out & back in, or close and restart all your terminal windows.
+
+# Now when you type a cd command in one shell, such as:
+# cd /usr/src/linux-$( uname -r )/Documentation
+# ...you can switch over to another terminal and type:
+# lcd
+# ...and now that terminal is cd'ed to the same directory.
+
+cd() {
+ builtin cd "$@"
+ pwd > ~/.lcd.dir
+}
+
+lcd() {
+ [ -e ~/.lcd.dir ] && cd "$( cat ~/.lcd.dir )"
+}
diff --git a/litterbox b/litterbox
new file mode 100755
index 0000000..ad730ab
--- /dev/null
+++ b/litterbox
@@ -0,0 +1,465 @@
+#!/bin/bash
+
+# based on the API spec: https://litterbox.catbox.moe/tools.php
+
+VERSION="0.0.1"
+SELF="$( basename $0 )"
+APIURL="https://litterbox.catbox.moe/resources/internals/api.php"
+URLS=""
+EXPIRE="1"
+DELAY="${DELAY:-2}"
+UPLOAD_COUNT=0
+TMP="$( mktemp -t -d $SELF.XXXXXXXXXX )"
+trap cleanup EXIT
+
+die() {
+ echo "$SELF: fatal: $@" 1>&2
+ exit 1
+}
+
+warn() {
+ echo "$SELF: warning: $@" 1>&2
+}
+
+info() {
+ [ "$VERBOSE" = "1" ] && echo "$SELF: info: $@" 1>&2
+}
+
+check_path() {
+ type -p "$1" &>/dev/null
+}
+
+cleanup() {
+ [ "$TMP" != "" ] && rm -rf "$TMP"
+}
+
+usage() {
+ if ! check_path perldoc; then
+ warn "can't find perldoc on PATH, printing raw POD."
+ exec sed -n '/^=pod/,/^=cut/p' $0
+ fi
+
+ exec perldoc "$0"
+}
+
+manpage() {
+ exec pod2man --stderr -s1 -c"UrchlaysStuff" -r$VERSION "$0"
+}
+
+pluralize() {
+ echo -n "$1 $2"
+ [ "$1" != 1 ] && echo -n "s"
+}
+
+delay() {
+ info "sleeping $DELAY sec between $1"
+ sleep "$DELAY"
+}
+
+set_expiration() {
+ case "$1" in
+ 1|12|24|72) ;; # OK
+ *) die "invalid expiration time, allowed values are: 1 12 24 72" ;;
+ esac
+ EXPIRE="$1"
+}
+
+add_url() {
+ if [ "$URLS" = "" ]; then
+ URLS="$1"
+ else
+ URLS+=" $1"
+ fi
+ : $(( UPLOAD_COUNT++ ))
+}
+
+copy_urls() {
+ if ! check_path xsel; then
+ warn "xsel not found in PATH, not copying URL(s) to clipboard"
+ return
+ fi
+
+ if [ "$DISPLAY" = "" ]; then
+ warn "DISPLAY not set in env, not copying URL(s) to clipboard"
+ return
+ fi
+
+ echo -n "$URLS" | xsel -i
+}
+
+# compress_file() gets called on both files and directories.
+compress_file() {
+ local ext
+ local basefile
+ local is_dir
+
+ [ -d "$FILE" ] && is_dir=1
+
+ if [ "$ZIP" = "1" ]; then
+ ext=.zip
+ else
+ ext=.gz
+ fi
+
+ basefile="$( basename "$FILE" )"
+
+ # TODO: create a random tmp dir, don't use /tmp!
+ TMPFILE="$TMP/$basefile$ext"
+ rm -f "$TMPFILE"
+ if [ "$ZIP" = "1" ]; then
+ zip -qr "$TMPFILE" "$FILE"
+ info "zipped $FILE as $TMPFILE"
+ else
+ if [ "$is_dir" = 1 ]; then
+ tar cfz "$TMPFILE" "$FILE"
+ info "tarred up $FILE as $TMPFILE"
+ else
+ gzip -9 < "$FILE" > "$TMPFILE"
+ info "gzipped $FILE as $TMPFILE"
+ fi
+ fi
+ FILE="$TMPFILE"
+}
+
+# TODO: curl options:
+# --max-time --retry --retry-max-time
+upload_file() {
+ local url
+ local use_compression
+
+ info "checking $FILE"
+
+ case "$FILE" in
+ *.exe|*.scr|*.cpl|*.doc*|*.jar)
+ warn "forbidden file extension, compression forced"
+ use_compression=1 ;;
+ *.zip|*.gz)
+ use_compression=0 ;;
+ *)
+ use_compression="$COMPRESS" ;;
+ esac
+
+ if [ "$use_compression" = 1 ]; then
+ # can't easily zip stdin, write it to a file
+ if [ "$FILE" = "-" ]; then
+ FILE="$TMP/$SELF.stdin"
+ cat > "$FILE"
+ if [ "$?" != 0 ]; then
+ rm -f "$FILE"
+ return
+ fi
+ fi
+ compress_file # resets FILE, sets TMPFILE
+ fi
+
+ # at this point, we have an actual file, even if input was stdin,
+ # so we can encrypt it.
+ if [ "$ENC" = "1" ]; then
+ CRYPTFILE="$FILE.aes"
+ openssl enc -pbkdf2 -aes-256-cbc < "$FILE" > "$CRYPTFILE"
+ if [ "$?" != "0" ]; then
+ warn "encryption failed, skipping file"
+ return
+ fi
+ FILE="$CRYPTFILE"
+ fi
+
+ if [ "$URLS" != "" ]; then
+ delay "uploads"
+ fi
+
+ info "uploading $FILE"
+
+ url="$(
+ cat "$FILE" | \
+ curl --silent \
+ -F "reqtype=fileupload" \
+ -F "time=${EXPIRE}h" \
+ -F "fileToUpload=@-" \
+ "$APIURL"
+ )"
+ # TODO: check curl's exit status!
+
+ case "$url" in
+ https://litter.catbox.moe/*) add_url "$url" ;;
+ *) warn "upload failed" ;;
+ esac
+}
+
+download_and_decrypt() {
+ local url="$1"
+ info "downloading and decrypting $url"
+ curl --silent "$url" | openssl enc -d -pbkdf2 -aes-256-cbc
+ [ "$?" != 0 ] && warn "download/decrypt failed"
+}
+
+# main()
+if [ "$1" = "--man" ]; then
+ manpage ; exit 0
+fi
+
+if [ "$1" = "--help" ]; then
+ usage ; exit 0
+fi
+
+if ! check_path curl; then
+ die "can't find curl on PATH (PATH is \"$PATH\")"
+fi
+
+# option string starts with a :, meaning we're responsible for
+# printing our own error messages.
+while getopts ":e:gzcvdo:" OPT; do
+ case "$OPT" in
+ e) set_expiration "$OPTARG"; opt_e=1 ;;
+ o) DLOUT="$OPTARG" ;;
+ g) GZIP=1 ;;
+ z) ZIP=1 ;;
+ c) ENC=1 ;;
+ v) VERBOSE=1 ;;
+ d) DOWNLOAD=1 ;;
+ *) die "invalid option -$OPTARG, try --help" ;;
+ esac
+done
+
+# getopts doesn't remove the args/options for us, so:
+shift $(($OPTIND - 1))
+
+# sanity check options and external binaries' existence.
+[ "$GZIP" = 1 -a "$ZIP" = 1 ] && die "can't give both -g and -z"
+
+if [ "$ZIP" = 1 ] && ! check_path zip; then
+ warn "can't find zip on PATH, disabling -z option"
+ ZIP=0
+fi
+
+if [ "$GZIP" = 1 ] && ! check_path gzip; then
+ warn "can't find gzip on PATH, disabling -g option"
+ GZIP=0
+fi
+
+[ "$GZIP" = 1 -o "$ZIP" = 1 ] && COMPRESS=1
+
+if [ "$DOWNLOAD" = 1 -o "$ENC" = 1 ]; then
+ check_path openssl || die "can't find openssl on path, -c/-d won't work"
+fi
+
+# download mode (-d)
+if [ "$DOWNLOAD" = 1 ]; then
+ [ "$GZIP" = 1 ] && warn "-g option ignored when using -d"
+ [ "$ZIP" = 1 ] && warn "-z option ignored when using -d"
+ [ "$ENC" = 1 ] && warn "-c option ignored when using -d"
+ [ "$opt_e" = 1 ] && warn "-e option ignored when using -d"
+ [ "$DLOUT" != "" ] && exec 1>"$DLOUT" || die "can't redirect stdout"
+ for arg; do
+ [ "$need_delay" = "1" ] && delay "downloads"
+ download_and_decrypt "$arg"
+ need_delay=1
+ done
+ exit 0
+else
+ [ "$DLOUT" != "" ] && warn "-o option ignored when not using -d"
+fi
+
+info "expire time set to $( pluralize $EXPIRE hour )"
+
+# upload mode
+[ "$1" = "" ] && set -- -
+for arg; do
+ TMPFILE=""
+ CRYPTFILE=""
+
+ if [ "$arg" = "-" -o -f "$arg" ]; then
+ FILE="$arg"
+ elif [ -d "$arg" ]; then
+ FILE="$arg"
+ compress_file # sets FILE
+ else
+ # broken symlink, device node, FIFO, ???
+ warn "$arg not a regular file, ignoring"
+ continue
+ fi
+
+ upload_file
+
+ # clean up if needed
+ if [ "$TMPFILE" != "" ]; then
+ info "removing temp file $TMPFILE"
+ rm -f "$TMPFILE"
+ fi
+
+ if [ "$TMPFILE" != "" ]; then
+ info "removing temp encrypted file $CRYPTFILE"
+ rm -f "$CRYPTFILE"
+ fi
+done
+
+if [ "$UPLOAD_COUNT" = "0" ]; then
+ die "no files uploaded"
+fi
+
+echo "$URLS"
+copy_urls
+
+info "$( pluralize $UPLOAD_COUNT file ) uploaded"
+
+exit 0
+
+# Rest of the file is perldoc.
+: <<EOF
+=pod
+
+=head1 NAME
+
+B<litterbox> - upload files to litterbox.catbox.moe
+
+=head1 SYNOPSIS
+
+B<litterbox> [-e I<hours>] [-g] [-z] [-c] [-v] I<file> <I<file ...>>
+
+B<litterbox> -d [-o I<output>] I<url> <I<url ...>>
+
+=head1 DESCRIPTION
+
+B<litterbox> uploads files to (or downloads files from) the temporary
+file storage site B<https://litterbox.catbox.moe>. The site is
+similar to a "pastebin" site, except that it allows any type of
+file (not just text), and uploads can be up to 1GB in size.
+
+=head2 Uploading
+
+Each I<file> can be a filename, a directory name, or "-" for standard
+input. If no files are given, litterbox reads from standard input.
+Directories are uploaded as B<.tar.gz> archives, by default. Files
+can be optionally encrypted with AES-256.
+
+Once a file is uploaded, its URL is printed on stdout (one per
+line). If B<xsel>(1) is installed and X is running, URLs are also
+copied to the X paste buffer (separated by spaces).
+
+When uploading multiple files, a delay of 2 seconds is added between
+uploads, to avoid hammering the site.
+
+=head2 Downloading
+
+Download mode is only for downloading AES-256 encrypted files that
+were previously uploaded with B<litterbox>. Non-encrypted files can
+simply be downloaded with B<wget>(1), B<curl>(1), a web browser, etc.
+You will, of course, have to provide the correct decryption key
+(password).
+
+=head1 OPTIONS
+
+=head2 Upload Options
+
+=over 4
+
+=item B<-e> I<hours>
+
+Set expiration time in hours. Allowed values are B<1>, B<12>,
+B<24>, or B<72>. Default is B<1>.
+
+=item B<-g>
+
+Upload gzipped files. This is automatically enabled
+when uploading files whose names end in .exe, .scr,
+.cpl, .doc*, .jar (unless B<-z> is given). Also, directories
+are automatically tarred/gzipped (unless B<-z> is given).
+
+=item B<-z>
+
+Upload zipped files or dirs, rather than .gz or .tar.gz.
+
+=item B<-c>
+
+Upload encrypted file. Currently this means the file
+is encrypted with 'openssl enc -pbkdf2 -aes-256-cbc', and
+you're prompted for an encryption key. Whoever downloads
+the encrypted file will have to decrypt it with the B<-d>
+option, or else do it manually.
+
+=back
+
+=head2 Download Options
+
+=over 4
+
+=item B<-d>
+
+Download and decrypt previously uploaded file(s) from URL(s).
+Equivalent to downloading the file normally, then piping it
+through:
+
+ openssl enc -d -pbkdf2 -aes-256-cbc
+
+...which means the file will be printed to your terminal, unless you
+use shell redirection or the B<-o> option. The upload options above (B<-e>
+B<-g> B<-z> B<-t> B<-c>) are ignored in download mode.
+
+=item B<-o> I<file>
+
+Set output file for B<-d> option. Note that giving multiple URLs
+will result in all the data being written to the same file. If you need
+separate files, run B<litterbox> multiple times.
+
+The B<-o> option is ignored in upload mode (when B<-d> is not used).
+
+=back
+
+=head2 General Options
+
+=over 4
+
+=item B<-v>
+
+Verbose operation.
+
+=item B<--help>
+
+Print this help to standard output and exit. Since the help is long,
+it will be passed through your pager.
+
+=item B<--man>
+
+Print this help in man page (troff) format to standard output and exit.
+
+=back
+
+=head1 NOTES
+
+=over 2
+
+=item B<->
+
+B<litter.catbox.moe> is an amazingly useful service. B<Please> be
+respectful of the site's owner, B<follow> the site's rules, and don't
+abuse the service with excessive requests. You should also consider
+supporting the site financially, by buying merch from its store, or
+simply making a donation.
+
+=item B<->
+
+With the B<-c> and B<-d> options, you will be prompted interactively
+for the encryption key (password), on the process's controlling tty.
+This could pose a problem if there's no controlling tty. With
+multiple files, you will be prompted separately for each.
+
+=item B<->
+
+Copying URLs to the copy/paste buffer only works under X11. It might
+be possible to support gpm(8) for the console. If Wayland has an
+xsel-like utility, it could be supported too (the author doesn't use
+Wayland so it's not high on the priority list).
+
+=back
+
+=head1 AUTHOR
+
+B. Watson <urchlay@slackware.uk>
+
+=head1 COPYRIGHT
+
+B<litterbox> is licensed under the WTFPL: do WTF you want to with this.
+See http://www.wtfpl.net/txt/copying/ for details.
+
+=cut
+EOF
diff --git a/slacklog b/slacklog
index 87cdc76..d686fab 100755
--- a/slacklog
+++ b/slacklog
@@ -1,4 +1,3 @@
#!/bin/sh
-VER=${@:-15.0}
-exec tmux new elinks http://ftp.osuosl.org/pub/slackware/slackware-$VER/ChangeLog.txt
+exec elinks http://ftp.osuosl.org/pub/slackware/slackware-${@:-15.0}/ChangeLog.txt
diff --git a/stealvim b/stealvim
new file mode 100755
index 0000000..754b02d
--- /dev/null
+++ b/stealvim
@@ -0,0 +1,98 @@
+#!/bin/bash
+
+SELF="$( basename $0 )"
+
+warn() {
+ echo "$SELF: $*" 1>&2
+}
+
+die() {
+ echo "$SELF: fatal: $*" 1>&2
+ exit 1
+}
+
+if [ "$1" = "-h" -o "$1" = "--help" -o "$2" != "" ]; then
+ cat <<EOF
+$SELF - take over a running vim instance via reptyr
+
+Usage: $SELF [<file>}
+
+With no argument, $SELF searches for .*.swp files in the current
+directory. If only one is found, the PID of the process that owns it
+is redirected to the current TTY by running "reptyr <pid>". If there
+are multiple .*.swp files, no process is redirected; instead the PIDs
+that own the files are printed to stderr.
+
+With a <file> argument, the vim process editing that file (if any)
+is passed to reptyr. The <file> can either be the actual file
+being edited, or the .*.swp file.
+
+Typical use case: you were editing a file remotely (via ssh), left
+yourself logged in and forgot to exit vim; now you're at the console
+or logged in from a different host and want to continue editing the
+same file.
+
+After "stealing" the vim process, it's best to write any changes
+and then exit vim immediately. To continue editing, run vim again.
+If you ignore this suggestion, things might or might not work OK
+depending on the terminal emulators in use, and/or the TERM setting.
+EOF
+fi
+
+[ "$( type -p reptyr )" = "" ] && \
+ die "reptyr not installed!"
+
+old=""
+
+for i in .*.swp; do
+ [ ! -e "$i" ] && die "no .*.swp files"
+
+ swppid="$( file $i | sed 's/.*, pid \([^,]*\),.*/\1/' )"
+
+ # If there's an argument and we found the matching .swp, use it.
+ if [ "$i" = "$1" -o "$i" = ".$1.swp" ]; then
+ pid=$swppid
+ break
+ fi
+
+ # If there's an argument and the current .swp file doesn't
+ # match, ignore this .swp.
+ [ "$1" != "" ] && continue
+
+ # If the .swp's PID is no longer running, ignore it.
+ if [ ! -d /proc/$swppid ]; then
+ warn "$i: PID $swppid no longer running"
+ continue
+ fi
+
+ # If we can't read the exe, it likely means it belongs to root,
+ # or anyway not the current user.
+ if [ ! -r /proc/$swppid/exe ]; then
+ warn "$i: PID $swppid doesn't belong to user $( whoami )"
+ continue
+ fi
+
+ # If the .swp's PID is running but it's not vim, the PID has been
+ # reused. ignore it. This works even if vim was called by a
+ # symlink (e.g. /usr/bin/vi => vim).
+ case "$( realpath /proc/$swppid/exe )" in
+ */vim) ;;
+ *) warn "$i: PID $swppid not a vim process"; continue ;;
+ esac
+
+ pid=$swppid
+ if [ "$old" != "" ] && [ "$pid" != "$old" ]; then
+ die "multiple vim PIDs: $old $pid"
+ exit 1
+ fi
+
+ old=$pid
+done
+
+if [ "$pid" = "" ]; then
+ msg="no vim PID found"
+ [ "$1" != "" ] && msg+=" for $1"
+ die $msg
+fi
+
+reptyr "$pid"
diff --git a/termbin b/termbin
index 441be32..6a9f304 100755
--- a/termbin
+++ b/termbin
@@ -1,16 +1,25 @@
-#!/bin/sh
+#!/bin/bash
+
+VERSION="0.1.0"
+SELF="$( basename $0 )"
# 20200424 bkw: This used to be a one-line script:
# cat "${1:--}" | nc termbin.com 9999
# ...but I really wanted the "copy link to X clipboard" feature.
-if [ "$1" = "--help" ]; then
+if [ "$1" = "--help" -o "$1" = "-h" ]; then
cat <<EOF
-Usage: $( basename $0 ) <filename>
+termbin v$VERSION
+
+Usage: $SELF <filename> [<filename> ...]
+
+Uses nc (netcat) to paste stdin to termbin.com, or pastes one or more
+files if <filename(s)> are given. Spits out paste URL on stdout. Also
+copies URL to the X clipboard if X is running and either xsel or xclip
+is installed.
-Uses nc (NetCat) to paste stdin to termbin.com, or pastes a file if
-<filename> is given. Spits out paste URL on stdout. Also copies URL to
-the X clipboard if X is running and either xsel or xclip is installed.
+Only one paste is created. If you give multiple filenames, they are
+concatenated together.
Written by B. Watson <urchlay@slackware.uk>, released under the WTFPL:
do WTF you want with this.
@@ -18,20 +27,21 @@ EOF
exit 0
fi
-if ! which nc &>/dev/null; then
- echo "$( basename $0 ): can't find nc on path, install nc or netcat package"
- exit 1
-fi
+# 20251226 bkw: the sed is because termbin.com sends us e.g.
+# https://termbin.com/XXXX\n\0
+# and we get "warning: ignoring null byte" from bash.
+url="$( cat "${1:--}" | nc termbin.com 9999 | sed 's,\x00,,' )"
-url="$( cat "${1:--}" | nc termbin.com 9999 )"
-[ -z "$url" ] && exit "$?"
+# 20251227 bkw: don't print an error message if nc fails (nc will print
+# its own, or the shell will if it's "command not found").
+err="$?"
+[ -z "$url" ] && exit "$err"
echo "$url"
if [ -n "$DISPLAY" ]; then
- if which xsel &>/dev/null; then
- echo -n "$url" | xsel -i
- elif which xclip &>/dev/null; then
- echo -n "$url" | xclip
- fi
+ echo -n "$url" | xsel -i >/dev/null 2>&1 || \
+ echo -n "$url" | xclip >/dev/null 2>&1
fi
+
+exit 0
diff --git a/tolatin b/tolatin
new file mode 100755
index 0000000..44b04c1
--- /dev/null
+++ b/tolatin
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+case "$@" in
+ -u) PIPE="| unaccent utf8" ;;
+ *) ;;
+esac
+
+eval exec uconv -x Any-Latin $PIPE
diff --git a/uleft b/uleft
index eac3856..a1554d6 100755
--- a/uleft
+++ b/uleft
@@ -25,9 +25,20 @@
#GLEFT="104x51+1280+0"
#GRIGHT="101x51+2222+0"
#GFULL="205x51-71+0"
-GLEFT="101x49+1280+0"
-GRIGHT="90x49+2295+0"
-GFULL="191x49+1280+0"
+
+# Before my Dell widescreen monitor died:
+#GLEFT="101x49+1280+0"
+#GRIGHT="90x49+2295+0"
+#GFULL="191x49+1280+0"
+
+GLEFT="80x54+1919+0"
+GRIGHT="80x54+2720+0"
+GFULL="160x54+1920+0"
+
+# try #100010 for right (dark purple)
+CLEFT="-bg #000a00 --color0 #000a00"
+CRIGHT="-bg #100010 --color0 #100010"
+CFULL=""
murder_shell() {
# kill the shell that called the shell that's running this script
@@ -50,11 +61,11 @@ get_next_geom() {
case "$0" in
*kill*) murder_shell ;;
- *left*) G=$GLEFT ;;
- *full*) G=$GFULL ;;
+ *left*) G=$GLEFT; C="$CLEFT" ;;
+ *full*) G=$GFULL; C="$CFULL" ;;
*next*) G=$( get_next_geom ) ;;
- *) G=$GRIGHT ;;
+ *) G=$GRIGHT; C="$CRIGHT" ;;
esac
-urxvt -g "$G" "$@" -e sh -c "while true; do bash -login; done" &>/dev/null &
+urxvt -g "$G" $C "$@" -e sh -c "while true; do bash -login; done" &>/dev/null &
disown
diff --git a/vol b/vol
index 14425d7..7f644e7 100755
--- a/vol
+++ b/vol
@@ -5,7 +5,7 @@
# (c) 2020 B. Watson <urchlay@slackware.uk>
# Released under the WTFPL, see http://www.wtfpl.net/txt/copying/
-# Requires xosd.
+# Requires aosd_cat (on Slackware, libaosd from SBo).
# Intended for use with xbindkeys, like so:
#$ cat ~/.xbindkeysrc
@@ -20,7 +20,8 @@
# "Next" and "Prior" are PageDown and PageUp. Replace with "Up" and "Down"
# to use arrow keys. If you have multimedia keys, you can probably use
-# them. See xbindkeys(1).
+# them (try XF86AudioRaiseVolume, XF86AudioLowerVolume, and
+# XF86AudioMute). See xbindkeys(1).
# Can also be used from the command line. Run with no args for help.
@@ -33,27 +34,23 @@
CHANNEL=Master
# Each up/down adjustment is by this much. Use the dB suffix if you
-# prefer decibels, or leave it off for percentage.
-ADJ=3dB
+# prefer decibels, % percentage, no suffix for raw units (on one of my
+# sound cards, the raw unit range is 0 to 87; on another, 0-127).
+ADJ=1%
-# osd_cat seems a bit picky about what fonts it'll use. If you give a
-# nonexistent font, it won't run at all. If you give a font it "doesn't
-# like", you'll see the percentage bar, but no "Volume" text.
-FONT=12x24
+# Pango font string, see:
+# https://docs.gtk.org/Pango/type_func.FontDescription.from_string.html
+# The size is in points; 30px would be pixels.
+FONT="Mono Normal 30"
-# What color is the OSD bar and text? See /usr/share/X11/rgb.txt.
+# What color is the OSD bar and text? See /usr/share/X11/rgb.txt,
+# or use hex escapes (with #).
# COLOR is for when we're unmuted, MUTECOLOR is for muted.
-COLOR=orange
-MUTECOLOR=red
+COLOR='#00ff00'
+MUTECOLOR='#ff0000'
-# Text drop shadow, 0 to disable.
-SHADOW=3
-
-# Where does the OSD show up on screen? One of: top middle bottom
-POSITION=bottom
-
-# How long does the OSD persist? In seconds, integer only.
-DELAY=2
+# How long does the OSD persist? In milliseconds.
+DELAY=2000
# amixer options. Could use -c, -D here. Don't use -q.
# default is "-M", see amixer(1).
@@ -67,23 +64,43 @@ SELF="$( basename $0 )"
PIDFILE="$HOME/.$SELF.osd.pid"
-# osd() will kill any previously-spawned osd_cat process. Ideally this
+BLOCKS="██████████████████████████████████████████████████"
+BLANKS="──────────────────────────────────────────────────"
+PARTIAL="▌"
+
+# progress() prints a UTF-8 progress bar with 50 characters.
+# takes a percentage, 0 to 100
+progress() {
+ local text="$1"
+ local count="$2"
+ local solidblocks
+ local partial
+ local trailing
+
+ solidblocks="$(( $count / 2 ))"
+ partial="$(( $count % 2 ))"
+ trailing="$(( 50 - ( $solidblocks + $partial) ))"
+
+ echo -n "$text${BLOCKS:0:$solidblocks}"
+ [ "$partial" = "1" ] && echo -n $PARTIAL
+ echo -n "${BLANKS:0:$trailing}"
+}
+
+# osd() will kill any previously-spawned aosd_cat process. Ideally this
# means rapid multiple keypresses won't "step on" each other. In practice
# it seems to work OK, but if you press the key really fast on a slow
# system, or hold it down with your key-repeat rate cranked up (on any
# system), the OSD bar will never get a chance to display.
-
osd() {
local got="$( amixer $AMIXER_OPTS get $CHANNEL | tail -1 )"
local muted="$( echo "$got" | grep '\[off\]$' )"
local volpct="$( echo "$got" | cut -d'[' -f2 | cut -d% -f1 )"
local db="$( echo "$got" | cut -d'[' -f3 | cut -d']' -f1 )"
- local text="Volume $db ($volpct%)"
local color="$COLOR"
+ local text="$( printf "%8s" $db) $( printf "%-3s" $volpct% ) "
local oldpid
if [ -n "$muted" ]; then
- text="$text [Muted]"
color="$MUTECOLOR"
fi
@@ -91,18 +108,29 @@ osd() {
# files whose PIDs have been recycled.
if [ -e $PIDFILE ]; then
oldpid="$( cat $PIDFILE )"
- grep -q '^osd_cat' /proc/$oldpid/cmdline 2>/dev/null && \
- kill "$oldpid" 2>/dev/null
+ grep -q '^aosd_cat' /proc/$oldpid/cmdline 2>/dev/null && \
+ kill -9 "$oldpid" 2>/dev/null
+ rm -f $PIDFILE
fi
- osd_cat -b percentage \
- -d $DELAY \
- -P $volpct \
- -p $POSITION \
- -c $color \
- -s $SHADOW \
- -f $FONT \
- -T "$text" &
+ # TODO: make these variables in the config section rather than
+ # hardcoding them.
+ progress "$text" "$volpct" | \
+ aosd_cat \
+ --fore-color $color \
+ --back-color '#808080' \
+ --font "$FONT" \
+ --output 1 \
+ --x-offset 159 \
+ --y-offset 0 \
+ --position 7 \
+ --transparency 2 \
+ --back-opacity 128 \
+ --padding 7 \
+ --alignment 0 \
+ --fade-in 0 \
+ --fade-out 0 \
+ --fade-full $DELAY &
echo "$!" > $PIDFILE
}
@@ -121,17 +149,17 @@ mute() {
usage() {
cat <<EOF
-$SELF [up|down|mute|<nnn>]
+$SELF [up|down|mute|<nn>]
-<nnn> is a numeric volume, possibly followed by "dB" and/or "+" or "-".
- It will be passed to 'amixer $AMIXER_OPTS set $CHANNEL' as-is.
+<nn> is a numeric volume, possibly followed by "dB" or "%", and/or
+ "+" or "-". It will be passed to 'amixer $AMIXER_OPTS set $CHANNEL' as-is.
EOF
exit 1
}
check_deps() {
local missing="no"
- for dep in osd_cat amixer; do
+ for dep in aosd_cat amixer; do
if ! type -p "$dep" > /dev/null; then
echo "$SELF: missing required executable '$dep'" 1>&2
missing="yes"
@@ -157,11 +185,3 @@ esac
osd
exit 0
-
-# For reference:
-#$ amixer get Master
-#Simple mixer control 'Master',0
-# Capabilities: pvolume pvolume-joined pswitch pswitch-joined
-# Playback channels: Mono
-# Limits: Playback 0 - 87
-# Mono: Playback 31 [36%] [-42.00dB] [on]