#!/usr/bin/python
# coding=utf-8
#
# Copyright (C) 2009, 2010 Roman Zimbelmann <romanz@lavabit.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import sys
import ranger
from optparse import OptionParser, SUPPRESS_HELP
from ranger.ext.openstruct import OpenStruct
from ranger import __version__, USAGE, DEFAULT_CONFDIR
import ranger.api.commands
from signal import signal, SIGINT
from locale import getdefaultlocale, setlocale, LC_ALL
from ranger.ext import curses_interrupt_handler
from ranger.core.runner import Runner
from ranger.core.fm import FM
from ranger.core.environment import Environment
from ranger.shared import (EnvironmentAware, FileManagerAware,
SettingsAware)
from ranger.gui.defaultui import DefaultUI as UI
from ranger.fsobject import File
def parse_arguments():
"""Parse the program arguments"""
parser = OptionParser(usage=USAGE, version='ranger ' + __version__)
parser.add_option('-d', '--debug', action='store_true',
help="activate debug mode")
parser.add_option('-c', '--clean', action='store_true',
help="don't touch/require any config files. ")
parser.add_option('--fail-if-run', action='store_true',
help="experimental: return the exit code 1 if ranger is" \
"used to run a file (with `ranger filename`)")
parser.add_option('-r', '--confdir', type='string',
metavar='dir', default=DEFAULT_CONFDIR,
help="the configuration directory. (%default)")
parser.add_option('-m', '--mode', type='int', default=0, metavar='n',
help="if a filename is supplied, run it with this mode")
parser.add_option('-f', '--flags', type='string', default='',
metavar='string',
help="if a filename is supplied, run it with these flags.")
options, positional = parser.parse_args()
arg = OpenStruct(options.__dict__, targets=positional)
arg.confdir = os.path.expanduser(arg.confdir)
return arg
def allow_access_to_confdir(confdir, allow):
if allow:
try:
os.makedirs(confdir)
except OSError as err:
if err.errno != 17: # 17 means it already exists
print("This configuration directory could not be created:")
print(confdir)
print("To run ranger without the need for configuration")
print("files, use the --clean option.")
raise SystemExit()
if not confdir in sys.path:
sys.path[0:0] = [confdir]
else:
if sys.path[0] == confdir:
del sys.path[0]
def load_settings(fm, clean):
if not clean:
allow_access_to_confdir(ranger.arg.confdir, True)
# Load commands
comcont = ranger.api.commands.CommandContainer()
ranger.api.commands.alias = comcont.alias
try:
import commands
comcont.load_commands_from_module(commands)
except ImportError:
pass
from ranger.defaults import commands
comcont.load_commands_from_module(commands)
commands = comcont
# Load apps
try:
import apps
except ImportError:
from ranger.defaults import apps
# Load keys
from ranger import shared, api
from ranger.api import keys
keymanager = shared.EnvironmentAware.env.keymanager
keys.keymanager = keymanager
from ranger.defaults import keys
try:
import keys
except ImportError:
pass
# COMPAT WARNING
if hasattr(keys, 'initialize_commands'):
print("Warning: the syntax for ~/.ranger/keys.py has changed.")
print("Your custom keys are not loaded."\
" Please update your configuration.")
allow_access_to_confdir(ranger.arg.confdir, False)
else:
comcont = ranger.api.commands.CommandContainer()
ranger.api.commands.alias = comcont.alias
from ranger.defaults import commands, keys, apps
comcont.load_commands_from_module(commands)
commands = comcont
fm.commands = commands
fm.keys = keys
fm.apps = apps.CustomApplications()
def load_apps(fm, clean):
if not clean:
allow_access_to_confdir(ranger.arg.confdir, True)
try:
import apps
except ImportError:
from ranger.defaults import apps
allow_access_to_confdir(ranger.arg.confdir, False)
else:
from ranger.defaults import apps
fm.apps = apps.CustomApplications()
def # some utilities for converting numbers from hex
# lowercase letters only for now
== code
# instruction effective address register displacement immediate
# . op subop mod rm32 base index scale r32
# . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes
is-hex-int?: # in: (addr slice) -> eax: boolean
# . prologue
55/push-ebp
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
# . save registers
51/push-ecx
52/push-edx
53/push-ebx
# ecx = s
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 8/disp8 . # copy *(ebp+8) to ecx
# edx = s->end
8b/copy 1/mod/*+disp8 1/rm32/ecx . . . 2/r32/edx 4/disp8 . # copy *(ecx+4) to edx
# var curr/ecx: (addr byte) = s->start
8b/copy 0/mod/indirect 1/rm32/ecx . . . 1/r32/ecx . . # copy *ecx to ecx
# if s is empty return false
b8/copy-to-eax 0/imm32/false
39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx
73/jump-if-addr>= $is-hex-int?:end/disp8
# skip past leading '-'
# . if (*curr == '-') ++curr
31/xor 3/mod/direct 3/rm32/ebx . . . 3/r32/ebx . . # clear ebx
8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 3/r32/BL . . # copy byte at *ecx to BL
81 7/subop/compare 3/mod/direct 3/rm32/ebx . . . . . 0x2d/imm32/- # compare ebx
75/jump-if-!= $is-hex-int?:initial-0/disp8
# . ++curr
41/increment-ecx
# skip past leading '0x'
$is-hex-int?:initial-0:
# . if (*curr != '0') jump to loop
31/xor 3/mod/direct 3/rm32/ebx . . . 3/r32/ebx . . # clear ebx
8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 3/r32/BL . . # copy byte at *ecx to BL
81 7/subop/compare 3/mod/direct 3/rm32/ebx . . . . . 0x30/imm32/0 # compare ebx
75/jump-if-!= $is-hex-int?:loop/disp8
# . ++curr
41/increment-ecx
$is-hex-int?:initial-0x:
# . if (curr >= in->end) return true
39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx
73/jump-if-addr>= $is-hex-int?:true/disp8
# . if (*curr != 'x') jump to loop # the previous '0' is still valid so doesn't need to be checked again
31/xor 3/mod/direct 3/rm32/ebx . . . 3/r32/ebx . . # clear ebx
8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 3/r32/BL . . # copy byte at *ecx to BL
81 7/subop/compare 3/mod/direct 3/rm32/ebx . . . . . 0x78/imm32/x # compare ebx
75/jump-if-!= $is-hex-int?:loop/disp8
# . ++curr
41/increment-ecx
$is-hex-int?:loop:
# if (curr >= in->end) return true
39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx
73/jump-if-addr>= $is-hex-int?:true/disp8
# var eax: boolean = is-hex-digit?(*curr)
# . . push args
8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL
50/push-eax
# . . call
e8/call is-hex-digit?/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
# if (eax == false) return false
3d/compare-eax-and 0/imm32/false
74/jump-if-= $is-hex-int?:end/disp8
# ++curr
41/increment-ecx
# loop
eb/jump $is-hex-int?:loop/disp8
$is-hex-int?:true:
# return true
b8/copy-to-eax 1/imm32/true
$is-hex-int?:end:
# . restore registers
5b/pop-to-ebx
5a/pop-to-edx
59/pop-to-ecx
# . epilogue
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
5d/pop-to-ebp
c3/return
test-is-hex-int:
# . prologue
55/push-ebp
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
# (eax..ecx) = "34"
b8/copy-to-eax "34"/imm32
8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx
05/add-to-eax 4/imm32
# var slice/ecx: slice = {eax, ecx}
51/push-ecx
50/push-eax
89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
# eax = is-hex-int?(slice)
# . . push args
51/push-ecx
# . . call
e8/call is-hex-int?/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
# check-ints-equal(eax, 1, msg)
# . . push args
68/push "F - test-is-hex-int"/imm32
68/push 1/imm32/true
50/push-eax
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
# . epilogue
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
5d/pop-to-ebp
c3/return
test-is-hex-int-handles-letters:
# . prologue
55/push-ebp
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
# (eax..ecx) = "34a"
b8/copy-to-eax "34a"/imm32
8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx
05/add-to-eax 4/imm32
# var slice/ecx: slice = {eax, ecx}
51/push-ecx
50/push-eax
89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
# eax = is-hex-int?(slice)
# . . push args
51/push-ecx
# . . call
e8/call is-hex-int?/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
# check-ints-equal(eax, 1, msg)
# . . push args
68/push "F - test-is-hex-int-handles-letters"/imm32
68/push 1/imm32/true
50/push-eax
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
# . epilogue
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
5d/pop-to-ebp
c3/return
test-is-hex-int-with-trailing-char:
# . prologue
55/push-ebp
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
# (eax..ecx) = "34q"
b8/copy-to-eax "34q"/imm32
8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx
05/add-to-eax 4/imm32
# var slice/ecx: slice = {eax, ecx}
51/push-ecx
50/push-eax
89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
# eax = is-hex-int?(slice)
# . . push args
51/push-ecx
# . . call
e8/call is-hex-int?/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
# check-ints-equal(eax, 0, msg)
# . . push args
68/push "F - test-is-hex-int-with-trailing-char"/imm32
68/push 0/imm32/false
50/push-eax
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
# . epilogue
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
5d/pop-to-ebp
c3/return
test-is-hex-int-with-leading-char:
# . prologue
55/push-ebp
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
# (eax..ecx) = "q34"
b8/copy-to-eax "q34"/imm32
8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx
05/add-to-eax 4/imm32
# var slice/ecx: slice = {eax, ecx}
51/push-ecx
50/push-eax
89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
# eax = is-hex-int?(slice)
# . . push args
51/push-ecx
# . . call
e8/call is-hex-int?/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
# check-ints-equal(eax, 0, msg)
# . . push args
68/push "F - test-is-hex-int-with-leading-char"/imm32
68/push 0/imm32/false
50/push-eax
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
# . epilogue
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
5d/pop-to-ebp
c3/return
test-is-hex-int-empty:
# . prologue
55/push-ebp
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
# var slice/ecx: slice = ""
68/push 0/imm32
68/push 0/imm32
89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
# eax = is-hex-int?(slice)
# . . push args
51/push-ecx
# . . call
e8/call is-hex-int?/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
# check-ints-equal(eax, 0, msg)
# . . push args
68/push "F - test-is-hex-int-empty"/imm32
68/push 0/imm32/false
50/push-eax
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
# . epilogue
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
5d/pop-to-ebp
c3/return
test-is-hex-int-handles-0x-prefix:
# . prologue
55/push-ebp
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
# (eax..ecx) = "0x3a"
b8/copy-to-eax "0x3a"/imm32
8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx
05/add-to-eax 4/imm32
# var slice/ecx: slice = {eax, ecx}
51/push-ecx
50/push-eax
89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
# eax = is-hex-int?(slice)
# . . push args
51/push-ecx
# . . call
e8/call is-hex-int?/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
# check-ints-equal(eax, 1, msg)
# . . push args
68/push "F - test-is-hex-int-handles-0x-prefix"/imm32
68/push 1/imm32/true
50/push-eax
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
# . epilogue
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
5d/pop-to-ebp
c3/return
test-is-hex-int-handles-negative:
# . prologue
55/push-ebp
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
# (eax..ecx) = "-34a"
b8/copy-to-eax "-34a"/imm32
8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx
05/add-to-eax 4/imm32
# var slice/ecx: slice = {eax, ecx}
51/push-ecx
50/push-eax
89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
# eax = is-hex-int?(slice)
# . . push args
51/push-ecx
# . . call
e8/call is-hex-int?/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
# check-ints-equal(eax, 1, msg)
# . . push args
68/push "F - test-is-hex-int-handles-negative"/imm32
68/push 1/imm32/true
50/push-eax
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
# . epilogue
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
5d/pop-to-ebp
c3/return
test-is-hex-int-handles-negative-0x-prefix:
# . prologue
55/push-ebp
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
# (eax..ecx) = "-0x3a"
b8/copy-to-eax "-0x3a"/imm32
8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx
05/add-to-eax 4/imm32
# var slice/ecx: slice = {eax, ecx}
51/push-ecx
50/push-eax
89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
# eax = is-hex-int?(slice)
# . . push args
51/push-ecx
# . . call
e8/call is-hex-int?/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
# check-ints-equal(eax, 1, msg)
# . . push args
68/push "F - test-is-hex-int-handles-negative-0x-prefix"/imm32
68/push 1/imm32/true
50/push-eax
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
# . epilogue
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
5d/pop-to-ebp
c3/return
parse-hex-int: # in: (addr array byte) -> result/eax: int
# . prologue
55/push-ebp
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
# . save registers
51/push-ecx
52/push-edx
# eax = in
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 0/r32/eax 8/disp8 . # copy *(ebp+8) to eax
# var curr/ecx: (addr byte) = &in->data
8d/copy-address 1/mod/*+disp8 0/rm32/eax . . . 1/r32/ecx 4/disp8 . # copy eax+4 to ecx
# var max/edx: (addr byte) = &in->data[in->size]
# . edx = in->size
8b/copy 0/mod/indirect 0/rm32/eax . . . 2/r32/edx . . # copy *eax to edx
# . edx = in->data + in->size
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 2/index/edx . 2/r32/edx 4/disp8 . # copy eax+edx+4 to edx
# return parse-hex-int-helper(curr, max)
# . . push args
52/push-edx
51/push-ecx
# . . call
e8/call parse-hex-int-helper/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
$parse-hex-int:end:
# . restore registers
5a/pop-to-edx
59/pop-to-ecx
# . epilogue
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
5d/pop-to-ebp
c3/return
parse-hex-int-from-slice: # in: (addr slice) -> result/eax: int
# . prologue
55/push-ebp
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
# . save registers
51/push-ecx
52/push-edx
# ecx = in
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 8/disp8 . # copy *(ebp+8) to ecx
# edx = in->end
8b/copy 1/mod/*+disp8 1/rm32/ecx . . . 2/r32/edx 4/disp8 . # copy *(ecx+4) to edx
# var curr/ecx: (addr byte) = in->start
8b/copy 0/mod/indirect 1/rm32/ecx . . . 1/r32/ecx . . # copy *ecx to ecx
# return parse-hex-int-helper(curr, max)
# . . push args
52/push-edx
51/push-ecx
# . . call
e8/call parse-hex-int-helper/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
$parse-hex-int-from-slice:end:
# . restore registers
5a/pop-to-edx
59/pop-to-ecx
# . epilogue
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
5d/pop-to-ebp
c3/return
parse-hex-int-helper: # start: (addr byte), end: (addr byte) -> result/eax: int
# . prologue
55/push-ebp
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
# . save registers
51/push-ecx
52/push-edx
53/push-ebx
56/push-esi
# var curr/ecx: (addr byte) = start
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 8/disp8 . # copy *(ebp+8) to ecx
# edx = max
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 2/r32/edx 0xc/disp8 . # copy *(ebp+12) to edx
# var result/ebx: int = 0
31/xor 3/mod/direct 3/rm32/ebx . . . 3/r32/ebx . . # clear ebx
# var negate?/esi: boolean = false
31/xor 3/mod/direct 6/rm32/esi . . . 6/r32/esi . . # clear esi
$parse-hex-int-helper:negative:
# if (*curr == '-') ++curr, negate = true
31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax
8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL
3d/compare-eax-and 0x2d/imm32/-
75/jump-if-!= $parse-hex-int-helper:initial-0/disp8
# . ++curr
41/increment-ecx
# . negate = true
be/copy-to-esi 1/imm32/true
$parse-hex-int-helper:initial-0:
# skip past leading '0x'
# . if (*curr != '0') jump to loop
8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL
3d/compare-eax-and 0x30/imm32/0
75/jump-if-!= $parse-hex-int-helper:loop/disp8
# . ++curr
41/increment-ecx
$parse-hex-int-helper:initial-0x:
# . if (curr >= in->end) return result
39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx
73/jump-if-addr>= $parse-hex-int-helper:end/disp8
# . if (*curr != 'x') jump to loop # the previous '0' is still valid so doesn't need to be checked again
31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax
8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL
3d/compare-eax-and 0x78/imm32/x
75/jump-if-!= $parse-hex-int-helper:loop/disp8
# . ++curr
41/increment-ecx
$parse-hex-int-helper:loop:
# if (curr >= in->end) break
39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx
73/jump-if-addr>= $parse-hex-int-helper:negate/disp8
# var eax: int = from-hex-char(*curr)
# . . copy arg to eax
8a/copy-byte 0/mod/indirect 1/rm32/ecx . . . 0/r32/AL . . # copy byte at *ecx to AL
# . . call
e8/call from-hex-char/disp32
# result = result * 16 + eax
c1/shift 4/subop/left 3/mod/direct 3/rm32/ebx . . . . . 4/imm8 # shift ebx left by 4 bits
01/add 3/mod/direct 3/rm32/ebx . . . 0/r32/eax . . # add eax to ebx
# ++curr
41/increment-ecx
# loop
eb/jump $parse-hex-int-helper:loop/disp8
$parse-hex-int-helper:negate:
# if (negate?) result = -result
81 7/subop/compare 3/mod/direct 6/rm32/esi . . . . . 0/imm32/false # compare esi
74/jump-if-= $parse-hex-int-helper:end/disp8
f7 3/subop/negate 3/mod/direct 3/rm32/ebx . . . . . . # negate ebx
$parse-hex-int-helper:end:
# return result
89/copy 3/mod/direct 0/rm32/eax . . . 3/r32/ebx . . # copy ebx to eax
# . restore registers
5e/pop-to-esi
5b/pop-to-ebx
5a/pop-to-edx
59/pop-to-ecx
# . epilogue
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
5d/pop-to-ebp
c3/return
test-parse-hex-int-from-slice-single-digit:
# . prologue
55/push-ebp
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
# (eax..ecx) = "a"
b8/copy-to-eax "a"/imm32
8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx
05/add-to-eax 4/imm32
# var slice/ecx: slice = {eax, ecx}
51/push-ecx
50/push-eax
89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
# eax = parse-hex-int-from-slice(slice)
# . . push args
51/push-ecx
# . . call
e8/call parse-hex-int-from-slice/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
# check-ints-equal(eax, 0xa, msg)
# . . push args
68/push "F - test-parse-hex-int-from-slice-single-digit"/imm32
68/push 0xa/imm32
50/push-eax
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
# . epilogue
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
5d/pop-to-ebp
c3/return
test-parse-hex-int-from-slice-multi-digit:
# . prologue
55/push-ebp
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
# (eax..ecx) = "34a"
b8/copy-to-eax "34a"/imm32
8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx
05/add-to-eax 4/imm32
# var slice/ecx: slice = {eax, ecx}
51/push-ecx
50/push-eax
89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
# eax = parse-hex-int-from-slice(slice)
# . . push args
51/push-ecx
# . . call
e8/call parse-hex-int-from-slice/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
# check-ints-equal(eax, 0x34a, msg)
# . . push args
68/push "F - test-parse-hex-int-from-slice-multi-digit"/imm32
68/push 0x34a/imm32
50/push-eax
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
# . epilogue
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
5d/pop-to-ebp
c3/return
test-parse-hex-int-from-slice-0x-prefix:
# . prologue
55/push-ebp
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
# (eax..ecx) = "0x34"
b8/copy-to-eax "0x34"/imm32
8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx
05/add-to-eax 4/imm32
# var slice/ecx: slice = {eax, ecx}
51/push-ecx
50/push-eax
89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
# eax = parse-hex-int-from-slice(slice)
# . . push args
51/push-ecx
# . . call
e8/call parse-hex-int-from-slice/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
# check-ints-equal(eax, 0x34a, msg)
# . . push args
68/push "F - test-parse-hex-int-from-slice-0x-prefix"/imm32
68/push 0x34/imm32
50/push-eax
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
# . epilogue
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
5d/pop-to-ebp
c3/return
test-parse-hex-int-from-slice-zero:
# . prologue
55/push-ebp
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
# (eax..ecx) = "0"
b8/copy-to-eax "0"/imm32
8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx
05/add-to-eax 4/imm32
# var slice/ecx: slice = {eax, ecx}
51/push-ecx
50/push-eax
89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
# eax = parse-hex-int-from-slice(slice)
# . . push args
51/push-ecx
# . . call
e8/call parse-hex-int-from-slice/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
# check-ints-equal(eax, 0x34a, msg)
# . . push args
68/push "F - test-parse-hex-int-from-slice-zero"/imm32
68/push 0/imm32
50/push-eax
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
# . epilogue
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
5d/pop-to-ebp
c3/return
test-parse-hex-int-from-slice-0-prefix:
# . prologue
55/push-ebp
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
# (eax..ecx) = "03"
b8/copy-to-eax "03"/imm32
8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx
05/add-to-eax 4/imm32
# var slice/ecx: slice = {eax, ecx}
51/push-ecx
50/push-eax
89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
# eax = parse-hex-int-from-slice(slice)
# . . push args
51/push-ecx
# . . call
e8/call parse-hex-int-from-slice/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
# check-ints-equal(eax, 0x3, msg)
# . . push args
68/push "F - test-parse-hex-int-from-slice-0-prefix"/imm32
68/push 0x3/imm32
50/push-eax
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
# . epilogue
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
5d/pop-to-ebp
c3/return
test-parse-hex-int-from-slice-negative:
# . prologue
55/push-ebp
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
# (eax..ecx) = "-03"
b8/copy-to-eax "-03"/imm32
8b/copy 0/mod/indirect 0/rm32/eax . . . 1/r32/ecx . . # copy *eax to ecx
8d/copy-address 1/mod/*+disp8 4/rm32/sib 0/base/eax 1/index/ecx . 1/r32/ecx 4/disp8 . # copy eax+ecx+4 to ecx
05/add-to-eax 4/imm32
# var slice/ecx: slice = {eax, ecx}
51/push-ecx
50/push-eax
89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx
# eax = parse-hex-int-from-slice(slice)
# . . push args
51/push-ecx
# . . call
e8/call parse-hex-int-from-slice/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
# check-ints-equal(eax, -3, msg)
# . . push args
68/push "F - test-parse-hex-int-from-slice-negative"/imm32
68/push -3/imm32
50/push-eax
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
# . epilogue
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
5d/pop-to-ebp
c3/return
is-hex-digit?: # c: byte -> eax: boolean
# . prologue
55/push-ebp
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
# . save registers
51/push-ecx
# ecx = c
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 1/r32/ecx 8/disp8 . # copy *(ebp+8) to ecx
# return false if c < '0'
81 7/subop/compare 3/mod/direct 1/rm32/ecx . . . . . 0x30/imm32 # compare ecx
7c/jump-if-< $is-hex-digit?:false/disp8
# return true if c <= '9'
81 7/subop/compare 3/mod/direct 1/rm32/ecx . . . . . 0x39/imm32 # compare ecx
7e/jump-if-<= $is-hex-digit?:true/disp8
# drop case
25/and-eax-with 0x5f/imm32
# return false if c > 'f'
81 7/subop/compare 3/mod/direct 1/rm32/ecx . . . . . 0x66/imm32 # compare ecx
7f/jump-if-> $is-hex-digit?:false/disp8
# return true if c >= 'a'
81 7/subop/compare 3/mod/direct 1/rm32/ecx . . . . . 0x61/imm32 # compare ecx
7d/jump-if->= $is-hex-digit?:true/disp8
# otherwise return false
$is-hex-digit?:false:
b8/copy-to-eax 0/imm32/false
eb/jump $is-hex-digit?:end/disp8
$is-hex-digit?:true:
b8/copy-to-eax 1/imm32/true
$is-hex-digit?:end:
# . restore registers
59/pop-to-ecx
# . epilogue
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
5d/pop-to-ebp
c3/return
test-hex-below-0:
# eax = is-hex-digit?(0x2f)
# . . push args
68/push 0x2f/imm32
# . . call
e8/call is-hex-digit?/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
# check-ints-equal(eax, 0, msg)
# . . push args
68/push "F - test-hex-below-0"/imm32
68/push 0/imm32/false
50/push-eax
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
c3/return
test-hex-0-to-9:
# eax = is-hex-digit?(0x30)
# . . push args
68/push 0x30/imm32
# . . call
e8/call is-hex-digit?/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
# check-ints-equal(eax, 1, msg)
# . . push args
68/push "F - test-hex-at-0"/imm32
68/push 1/imm32/true
50/push-eax
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
# eax = is-hex-digit?(0x39)
# . . push args
68/push 0x39/imm32
# . . call
e8/call is-hex-digit?/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
# check-ints-equal(eax, 1, msg)
# . . push args
68/push "F - test-hex-at-9"/imm32
68/push 1/imm32/true
50/push-eax
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
c3/return
test-hex-above-9-to-a:
# eax = is-hex-digit?(0x3a)
# . . push args
68/push 0x3a/imm32
# . . call
e8/call is-hex-digit?/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
# check-ints-equal(eax, 0, msg)
# . . push args
68/push "F - test-hex-above-9-to-a"/imm32
68/push 0/imm32/false
50/push-eax
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
c3/return
test-hex-a-to-f:
# eax = is-hex-digit?(0x61)
# . . push args
68/push 0x61/imm32
# . . call
e8/call is-hex-digit?/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
# check-ints-equal(eax, 1, msg)
# . . push args
68/push "F - test-hex-at-a"/imm32
68/push 1/imm32/true
50/push-eax
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
# eax = is-hex-digit?(0x66)
# . . push args
68/push 0x66/imm32
# . . call
e8/call is-hex-digit?/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
# check-ints-equal(eax, 1, msg)
# . . push args
68/push "F - test-hex-at-f"/imm32
68/push 1/imm32/true
50/push-eax
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
c3/return
test-hex-above-f:
# eax = is-hex-digit?(0x67)
# . . push args
68/push 0x67/imm32
# . . call
e8/call is-hex-digit?/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
# check-ints-equal(eax, 0, msg)
# . . push args
68/push "F - test-hex-above-f"/imm32
68/push 0/imm32/false
50/push-eax
# . . call
e8/call check-ints-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
c3/return
from-hex-char: # in/eax: byte -> out/eax: nibble
$from-hex-char:check0:
# if (eax < '0') goto abort
3d/compare-eax-with 0x30/imm32/0
7c/jump-if-< $from-hex-char:abort/disp8
$from-hex-char:check1:
# if (eax > 'f') goto abort
3d/compare-eax-with 0x66/imm32/f
7f/jump-if-> $from-hex-char:abort/disp8
$from-hex-char:check2:
# if (eax > '9') goto next check
3d/compare-eax-with 0x39/imm32/9
7f/jump-if-> $from-hex-char:check3/disp8
$from-hex-char:digit:
# return eax - '0'
2d/subtract-from-eax 0x30/imm32/0
c3/return
$from-hex-char:check3:
# if (eax < 'a') goto abort
3d/compare-eax-with 0x61/imm32/a
7c/jump-if-< $from-hex-char:abort/disp8
$from-hex-char:letter:
# return eax - ('a'-10)
2d/subtract-from-eax 0x57/imm32/a-10
c3/return
$from-hex-char:abort:
# . _write(2/stderr, error)
# . . push args
68/push "invalid hex char: "/imm32
68/push 2/imm32/stderr
# . . call
e8/call _write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
# . clear-stream($Stderr->buffer)
# . . save eax
50/push-eax
# . . push args
68/push $Stderr->buffer/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
# . . restore eax
58/pop-to-eax
# . print-int32-buffered(Stderr, eax)
# . . push args
50/push-eax
68/push Stderr/imm32
# . . call
e8/call print-int32-buffered/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
# . flush(Stderr)
# . . push args
68/push Stderr/imm32
# . . call
e8/call flush/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
# . _write(2/stderr, "\n")
# . . push args
68/push Newline/imm32
68/push 2/imm32/stderr
# . . call
e8/call _write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
# . syscall(exit, 1)
bb/copy-to-ebx 1/imm32
b8/copy-to-eax 1/imm32/exit
cd/syscall 0x80/imm8
# never gets here
# . . vim:nowrap:textwidth=0