Largo perdido y casi olvidado.
Pretendía re-factorizar el código, etc. pero la publicación es como es. Este código se usa en un sistema de 32 bits. No estoy seguro de cómo se comportaría en 64 bits (u otro).
Tener un truco en el código C en algún lugar también (extracción de PID).
Déjalo como una publicación para que cualquiera pueda hackearlo y modificarlo. Mi script actual en su conjunto (usando pid
como opción debería funcionar en cualquier GUI dado que es "GUI-PID / Program" y el uso de wmctrl -l -p
y así sucesivamente):
#!/bin/bash
# Please leave in place:
# http://vi.stackexchange.com/q/562/220
declare -i debug=1
declare -i pid=0
opt=j
# Usage
usage()
{
printf "Usage: %s [[opt] <PID>] | [[opt] <SWP>]\n" "${0/*\//}"
printf "\nopt:\n"
printf " j : Jump to window. (Default)\n"
printf " g : Get window. (E.g. from other workspace.)\n"
printf " l : List windows.\n"
printf " p : Only print. (With some extra info.)\n"
printf " s : Alias for j. (switch)\n"
printf " i : Alias for p. (information)\n"
printf " h : This help.\n"
printf "\n"
printf " <PID>: Process ID.\n"
printf " <SWP>: Read PID from Vim swap file.\n"
if (($#)); then
printf "\nERR: Unknown option %s\n" "$1"
fi
}
# Check if PID is a (G)Vim process
check_vim_pid()
{
local comm=
if ! [[ "$1" =~ ^[0-9]+$ ]];then
printf "ERR: Some weird thing has happened (P: $1).\n" >&2
exit 1
fi
comm="$(ps -p $1 -o comm=)"
[[ "$comm" =~ ^g?vim$ ]] && return 0 || return 1
}
# First two bytes should be b0, bc or bC
# Or in hex 0x6230, 0x6263 or 0x6243
check_b0()
{
local b01="${1:0:2}"
local b02="${1:2:2}"
if [[ $b01 != '62' ]] ||
([[ "$b02" != '30' && "$b02" != '63' && "$b02" != '43' ]]); then
return 1
fi
return 0
}
# Read PID from swap file.
# Se notes below for information.
vim_file=""
vim_swp_pid()
{
local swp="$1"
if ! [[ -r "$swp" ]]; then
printf "ERR: Not able to read $swp.\n" >&2
exit 2
fi
# Read b0 ID
local b0_id="$(xxd -l 2 -p "$swp")"
if ! check_b0 "$b0_id"; then
printf "ERR: Bad b0 ID in file (Not Vim-swap?): %s\n" "$b0_id" >&2
exit 3
fi
# Read PID from .swp file
local -a opid=($(xxd -s 24 -l 4 -p -c 1 "$swp"))
# Read int magic from .swp file
local magic=$(xxd -s 1008 -l 8 -p "$swp")
if [[ "${magic:0:8}" == "33323130" ]]; then
# Intel (LittleEndian)
pid=$(printf "%d" "0x${opid[3]}${opid[2]}${opid[1]}${opid[0]}")
elif [[ "${magic:0:8}" == "30313233" ]] ||
[[ "${magic:8:8}" == "30313233" ]]; then
# Motorola (BigEndian)
pid=$(printf "%d" "0x${opid[0]}${opid[1]}${opid[2]}${opid[3]}")
else
printf "ERR: Unknown byteroder: %s\n" "$magic" >&2
exit 4
fi
if ! check_vim_pid $pid; then
printf "N010: PID %d is not a Vim process.\n" "$pid" >&2
exit 10
fi
# Read file name
vim_file="$(xxd -s 108 -l 800 -ps "$1" | xxd -r -p)"
}
list_windows()
{
local winid desk pid host title comm
printf "%-10s %-3s %-6s %-16s %s\n" "WINID" "DSK" "PID" "COMM" "TITLE"
while IFS=$' \n' read -r winid desk pid host title; do
cf="/proc/$pid/comm"
[[ -r "$cf" ]] && read -r comm < "$cf"
printf "%10s %3d %6d %-16s %s\n" "$winid" "$desk" "$pid" "$comm" "$title"
done <<< "$(wmctrl -lp)"
}
# ------------------------- RUN -------------------------------------------- #
# Check if any arguments (a bit redundant, but OK)
if [[ -z "$1" ]]; then
usage >&2
exit 1
fi
# Loop arguments
while [[ "$1" ]]; do
if [[ "$1" =~ ^[0-9]+$ ]]; then
pid=$1
else
[[ "${1:0:1}" == "-" ]] && op=${1:1} || op=$1
case "$op" in
l) list_windows; exit 0;;
d) debug=1;;
h|-help) usage; exit 0;;
j|s|g|p|i) opt=$op;;
*)
if ! [[ -e "$1" ]]; then
usage >&2;
printf "\nE006: Can't stat \`%s'\n" "$1" >&2
exit 2
fi
vim_swp_pid "$1"
;;
esac
fi
shift
done
# Check if PID is set
if !(($pid)); then
usage >&2
printf "E011: PID required / Not found.\n" >&2
exit 11
fi
# Read WindowID, Workspace, PID of all-windows then filter by PID
read -r wid ws <<<$(wmctrl -l -p | awk -v p="$pid" '$3 == p {print $1,"\t",$2}')
pikoli()
{
local pp=$1
while :; do
awk '/^PPid:/{print $2;next}/^Name:/{print $2;next}' /proc/$pp/status 2>/dev/null || return
pp=$(awk '/^PPid:/{print $2;next}' /proc/$pp/status)
done
}
if ! [[ "$wid" ]]; then
pikoli $pid
printf "ERR: Window not fround from PID %d.\n" "$pid" >&2
exit 12
fi
# As most DM's names desktops from 1 and not 0, a more user-friendly number.
((dmws=ws + 1))
# Do the action!
((debug)) && printf "PID=%d, WID=%s, WS=%d\n" "$pid" "$wid" "$ws"
case "$opt" in
j|s) printf "Swithching to workspace %d raising window %s by PID %d.\n" \
"$dmws" "$wid" "$pid";
wmctrl -ia "$wid"
;;
g) printf "Getting window %s by PID %d from workspace %d.\n" \
"$wid" "$pid" "$dmws";
wmctrl -iR "$wid"
;;
i|p) printf "Window is on workspace %d having window ID %s by PID %d.\n" \
"$dmws" "$wid" "$pid";
xwininfo -id $wid
;;
esac
exit 0
#############################################################################
# ----------------- Vim swap file block zero format ----------------------- #
#############################################################################
#
# No script / bash code beyond here
#
NOTES 'memline.c:139':
:62
#define BLOCK0_ID0 'b' /* block 0 id 0 */
#define BLOCK0_ID1 '0' /* block 0 id 1 */
#define BLOCK0_ID1_C0 'c' /* block 0 id 1 'cm' 0 */
#define BLOCK0_ID1_C1 'C' /* block 0 id 1 'cm' 1 */
:124
#define B0_FNAME_SIZE_ORG 900 /* what it was in older versions */
#define B0_FNAME_SIZE_NOCRYPT 898 /* 2 bytes used for other things */
#define B0_FNAME_SIZE_CRYPT 890 /* 10 bytes used for other things */
#define B0_UNAME_SIZE 40
#define B0_HNAME_SIZE 40
/*
* Restrict the numbers to 32 bits, otherwise most compilers will complain.
* This won\'t detect a 64 bit machine that only swaps a byte in the top 32
* bits, but that is crazy anyway.
*/
#define B0_MAGIC_LONG 0x30313233L
#define B0_MAGIC_INT 0x20212223L
#define B0_MAGIC_SHORT 0x10111213L
#define B0_MAGIC_CHAR 0x55
:139
/*
* Block zero holds all info about the swap file.
*
* NOTE: DEFINITION OF BLOCK 0 SHOULD NOT CHANGE! It would make all existing
* swap files unusable!
*
* If size of block0 changes anyway, adjust MIN_SWAP_PAGE_SIZE in vim.h!!
*
* This block is built up of single bytes, to make it portable across
* different machines. b0_magic_* is used to check the byte order and size of
* variables, because the rest of the swap file is not portable.
*/
struct block0
{
char_u b0_id[2]; /* id for block 0: BLOCK0_ID0 and BLOCK0_ID1,
* BLOCK0_ID1_C0, BLOCK0_ID1_C1 */
char_u b0_version[10]; /* Vim version string */
char_u b0_page_size[4];/* number of bytes per page */
char_u b0_mtime[4]; /* last modification time of file */
char_u b0_ino[4]; /* inode of b0_fname */
char_u b0_pid[4]; /* process id of creator (or 0) */
char_u b0_uname[B0_UNAME_SIZE]; /* name of user (uid if no name) */
char_u b0_hname[B0_HNAME_SIZE]; /* host name (if it has a name) */
char_u b0_fname[B0_FNAME_SIZE_ORG]; /* name of file being edited */
long b0_magic_long; /* check for byte order of long */
int b0_magic_int; /* check for byte order of int */
short b0_magic_short; /* check for byte order of short */
char_u b0_magic_char; /* check for last char */
};
offs len what
0 2 id
2 10 version
12 4 bytes per page
16 4 mtime
20 4 inode
24 4 PID or 0
28 40 name of user or uid
68 40 host name
108 900 fname
1008 4/8/ magic long*
1012 4/8/ magic int*
1016 2/ magic short*
1018 1/ magic char*
Length of magics is arch dependant.
Offset for magic, in example above, is by standard 32 bit.