Skip to content

Commit

Permalink
Add an initial entry to FUNCNAME, BASH_SOURCE, and BASH_LINENO.
Browse files Browse the repository at this point in the history
bash does something special when the argument is a file like 'bash
foo.sh', but not in the case of 'bash -c ls'.

Fixes issue #116.
  • Loading branch information
Andy Chu committed Oct 4, 2018
1 parent 46275d9 commit c11145d
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 6 deletions.
7 changes: 6 additions & 1 deletion bin/oil.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,13 +141,18 @@ def OshMain(argv0, argv, login_shell):

if arg_r.AtEnd():
dollar0 = argv0
has_main = False
else:
dollar0 = arg_r.Peek() # the script name, or the arg after -c
has_main = True

pool = alloc.Pool()
arena = pool.NewArena()

mem = state.Mem(dollar0, argv[arg_r.i + 1:], os.environ, arena)
# NOTE: has_main is only for ${BASH_SOURCE[@} and family. Could be a
# required arg.
mem = state.Mem(dollar0, argv[arg_r.i + 1:], os.environ, arena,
has_main=has_main)
funcs = {}

comp_lookup = completion.CompletionLookup()
Expand Down
24 changes: 19 additions & 5 deletions core/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -424,16 +424,21 @@ class Mem(object):
Modules: cmd_exec, word_eval, expr_eval, completion
"""

def __init__(self, argv0, argv, environ, arena):
self.argv0 = argv0
def __init__(self, dollar0, argv, environ, arena, has_main=False):
self.dollar0 = dollar0
self.argv_stack = [_ArgFrame(argv)]
self.var_stack = [_StackFrame()]

# The debug_stack isn't strictly necessary for execution. We use it for
# crash dumps and for 3 parallel arrays: FUNCNAME, BASH_SOURCE,
# BASH_LINENO. The First frame points at the global vars and argv.
self.debug_stack = [(None, None, const.NO_INTEGER, 0, 0)]

self.bash_source = [] # for implementing BASH_SOURCE
self.has_main = has_main
if has_main:
self.bash_source.append(dollar0) # e.g. the filename

self.current_spid = const.NO_INTEGER

# Note: we're reusing these objects because they change on every single
Expand Down Expand Up @@ -635,7 +640,7 @@ def Shift(self, n):

def GetArgNum(self, arg_num):
if arg_num == 0:
return runtime.Str(self.argv0)
return runtime.Str(self.dollar0)

return self.argv_stack[-1].GetArgNum(arg_num)

Expand Down Expand Up @@ -925,6 +930,9 @@ def GetVar(self, name, lookup_mode=scope_e.Dynamic):
if source_name:
strs.append('source') # bash doesn't give name
# Temp stacks are ignored

if self.has_main:
strs.append('main') # bash does this
return runtime.StrArray(strs) # TODO: Reuse this object too?

# This isn't the call source, it's the source of the function DEFINITION
Expand All @@ -936,21 +944,27 @@ def GetVar(self, name, lookup_mode=scope_e.Dynamic):
if name == 'CALL_SOURCE':
strs = []
for func_name, source_name, call_spid, _, _ in reversed(self.debug_stack):
if call_spid == const.NO_INTEGER: # should only happen for the first entry
# should only happen for the first entry
if call_spid == const.NO_INTEGER:
continue
span = self.arena.GetLineSpan(call_spid)
path, _ = self.arena.GetDebugInfo(span.line_id)
strs.append(path)
if self.has_main:
strs.append('-') # Bash does this to line up with main?
return runtime.StrArray(strs) # TODO: Reuse this object too?

if name == 'BASH_LINENO':
strs = []
for func_name, source_name, call_spid, _, _ in reversed(self.debug_stack):
if call_spid == const.NO_INTEGER: # should only happen for the first entry
# should only happen for the first entry
if call_spid == const.NO_INTEGER:
continue
span = self.arena.GetLineSpan(call_spid)
_, line_num = self.arena.GetDebugInfo(span.line_id)
strs.append(str(line_num))
if self.has_main:
strs.append('0') # Bash does this to line up with main?
return runtime.StrArray(strs) # TODO: Reuse this object too?

if name == 'LINENO':
Expand Down

0 comments on commit c11145d

Please sign in to comment.