about summary refs log tree commit diff stats
path: root/examples/ex8.subx
blob: 0e44a8833142d7d32f34ea7e075f1a9e6b9759a7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# Example reading commandline arguments: compute length of first arg.
#
# To run:
#   $ ./subx translate init.linux examples/ex8.subx -o examples/ex8
#   $ ./subx run examples/ex8 abc de fghi
# Expected result:
#   $ echo $?
#   3  # length of 'abc'
#
# At the start of a SubX program:
#   argc: *esp
#   argv[0]: *(esp+4)
#   argv[1]: *(esp+8)
#   ...
# Locals start from esp-4 downwards.

== 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

Entry:
    # . prologue
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # eax = ascii-length(argv[1])
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
    # . . call
    e8/call  ascii-length/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp

    # exit(eax)
    89/copy                         3/mod/direct    3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # copy eax to ebx
    e8/call  syscall_exit/disp32

ascii-length:  # s : (address array byte) -> n/eax
    # edx = s
    8b/copy                         1/mod/*+disp8   4/rm32/sib    4/base/esp  4/index/none  .           2/r32/edx   4/disp8         .                 # copy *(esp+4) to edx
    # var result/eax = 0
    b8/copy-to-eax  0/imm32
$ascii-length:loop:
    # var c/ecx = *s
    8a/copy-byte                    0/mod/*         2/rm32/edx    .           .             .           1/r32/CL    .               .                 # copy byte at *edx to CL
    # if (c == '\0') break
    81          7/subop/compare     3/mod/direct    1/rm32/ecx    .           .             .           .           .               0/imm32           # compare ecx
    74/jump-if-equal  $ascii-length:end/disp8
    # ++s
    42/increment-edx
    # ++result
    40/increment-eax
    # loop
    eb/jump  $ascii-length:loop/disp8
$ascii-length:end:
    # return eax
    c3/return

== data

# . . vim:nowrap:textwidth=0
hlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
import ranger.fsobject
from ranger.file import File
#from ranger.helper import log

from ranger.fsobject import BAD_INFO
from ranger.fsobject import FileSystemObject as SuperClass
from ranger.conf import SettingsAware

def sort_by_basename(path):
	return path.basename

def sort_by_directory(path):
	return -int( isinstance( path, Directory ) )

class NoDirectoryGiven(Exception):
	pass

class Directory(SuperClass, SettingsAware):
	def __init__(self, path):
		from os.path import isdir

		if not isdir(path):
			raise NoDirectoryGiven()

		SuperClass.__init__(self, path)
		self.content_loaded = False
		self.scheduled = False
		self.enterable = False

		self.filenames = None
		self.files = None
		self.filter = None
		self.pointed_index = None
		self.pointed_file = None
		self.scroll_begin = 0

		# to find out if something has changed:
		self.old_show_hidden = self.settings.show_hidden
		self.old_directories_first = self.settings.directories_first
	
	def load_content(self):
		from os.path import join, isdir, basename
		from os import listdir

		self.load_if_outdated()
		self.content_loaded = True

		if self.exists and self.runnable:
			filenames = []
			for fname in listdir(self.path):
				if not self.settings.show_hidden and fname[0] == '.':
					continue
				if isinstance(self.filter, str) and self.filter in fname:
					continue
				filenames.append(join(self.path, fname))
			self.scroll_offset = 0
			self.filenames = filenames
			self.infostring = ' %d' % len(self.filenames) # update the infostring
			files = []
			for name in self.filenames:
				if isdir(name):
					f = Directory(name)
				else:
					f = File(name)
				f.load()
				files.append(f)

			self.files = files
			self.old_directories_first = None
#			self.sort()

			if len(self.files) > 0:
				if self.pointed_file is not None:
					self.move_pointer_to_file_path(self.pointed_file)
#				if self.pointed_file is None:
#					self.correct_pointer()
		else:
			self.filenames = None
			self.files = None
			self.infostring = BAD_INFO

	def sort(self):
		if self.files is None:
			return

		old_pointed_file = self.pointed_file
		self.files.sort(key = sort_by_basename)

		if self.settings.directories_first:
			self.files.sort(key = sort_by_directory)

		if self.pointed_index is not None:
			self.move_pointer_to_file_path(old_pointed_file)
		else:
			self.correct_pointer()

		self.old_directories_first = self.settings.directories_first
	
	def sort_if_outdated(self):
		if self.old_directories_first != self.settings.directories_first:
			self.sort()

	# Notice: fm.env.cf should always point to the current file. If you
	# modify the current directory with this function, make sure
	# to update fm.env.cf aswell.
	def move_pointer(self, relative=0, absolute=None):
		if self.empty(): return
		i = self.pointed_index
		if isinstance(absolute, int):
			if absolute < 0:
				absolute = len(self.files) + absolute
			i = absolute

		if isinstance(relative, int):
			i += relative

		self.pointed_index = i
		self.correct_pointer()
		return self.pointed_file

	def move_pointer_to_file_path(self, path):
		if path is None: return
		try: path = path.path
		except AttributeError: pass

		self.load_content_once()
		if self.empty(): return

		i = 0
		for f in self.files:
			if f.path == path:
				self.move_pointer(absolute = i)
				return True
			i += 1
		return False
	
	def search(self, arg, direction = 1):
		if self.empty() or arg is None:
			return False
		elif hasattr(arg, 'search'):
			fnc = lambda x: arg.search(x.basename)
		else:
			fnc = lambda x: arg in x.basename

		length = len(self)

		if direction > 0:
			generator = ((self.pointed_index + (x + 1)) % length for x in range(length-1))
		else:
			generator = ((self.pointed_index - (x + 1)) % length for x in range(length-1))

		for i in generator:
			_file = self.files[i]
			if fnc(_file):
				self.pointed_index = i
				self.pointed_file = _file
				return True
		return False

	def correct_pointer(self):
		"""make sure the pointer is in the valid range of 0 : len(self.files)-1 (or None if directory is empty.)"""

		if self.files is None or len(self.files) == 0:
			self.pointed_index = None
			self.pointed_file = None

		else:
			i = self.pointed_index

			if i is None: i = 0
			if i >= len(self.files): i = len(self.files) - 1
			if i < 0: i = 0

			self.pointed_index = i
			self.pointed_file = self[i]
		
	def load_content_once(self):
		if not self.content_loaded:
			self.load_content()
			return True
		return False

	def load_content_if_outdated(self):
		if self.load_content_once(): return True

		if self.old_show_hidden != self.settings.show_hidden:
			self.old_show_hidden = self.settings.show_hidden
			self.load_content()
			return True

		import os
		real_mtime = os.stat(self.path).st_mtime
		cached_mtime = self.stat.st_mtime

		if real_mtime != cached_mtime:
			self.load_content()
			return True
		return False

	def empty(self):
		return self.files is None or len(self.files) == 0

	def __nonzero__(self):
		return True

	def __len__(self):
		if not self.accessible: raise ranger.fsobject.NotLoadedYet()
		return len(self.files)
	
	def __getitem__(self, key):
		if not self.accessible: raise ranger.fsobject.NotLoadedYet()
		return self.files[key]