Ejemplo n.º 1
0
    def from_packed(cls, data):
        obj = cls()
        ret_addr_bytearray = bytearray([0, 0, 0, 0])
        ret_addr_bytearray[1:] = bytearray(data[:3])
        ret_addr_bytes = bytes(ret_addr_bytearray)
        obj.return_addr = struct.unpack('>I', ret_addr_bytes)[0]
        flags = six.indexbytes(data, 3)
        num_locals = flags & 15
        if flags & 16:
            # discard return val
            obj.return_val_loc = None
        else:
            obj.return_val_loc = six.indexbytes(data, 4)

        # this should never have non-consecutive ones, right?
        # i.e. you can't have arg 3 without having args 1 and 2 (right?)
        args_flag = six.indexbytes(data, 5)
        obj.num_args = 0
        for i in range(7):
            if args_flag >> i:
                obj.num_args += 1

        used_stack_size = struct.unpack('>H', data[6:8])[0]
        obj.locals = []
        for i in range(num_locals):
            addr = 8 + i * 2
            local = struct.unpack('>H', data[addr:addr + 2])[0]
            obj.locals.append(local)
        obj.stack = []
        for i in range(used_stack_size):
            addr = 8 + num_locals * 2 + i * 2
            word = struct.unpack('>H', data[addr:addr + 2])[0]
            obj.stack.append(word)
        obj.size = 8 + num_locals * 2 + used_stack_size * 2
        return obj
Ejemplo n.º 2
0
    def from_packed(cls, data):
        obj = cls()
        ret_addr_bytearray = bytearray([0,0,0,0])
        ret_addr_bytearray[1:] = bytearray(data[:3])
        ret_addr_bytes = bytes(ret_addr_bytearray)
        obj.return_addr = struct.unpack('>I', ret_addr_bytes)[0]
        flags = six.indexbytes(data, 3)
        num_locals = flags & 15
        if flags & 16:
            # discard return val
            obj.return_val_loc = None
        else:
            obj.return_val_loc = six.indexbytes(data, 4)

        # this should never have non-consecutive ones, right?
        # i.e. you can't have arg 3 without having args 1 and 2 (right?)
        args_flag = six.indexbytes(data, 5)
        obj.num_args = 0
        for i in range(7):
            if args_flag >> i:
                obj.num_args += 1

        used_stack_size = struct.unpack('>H', data[6:8])[0]
        obj.locals = []
        for i in range(num_locals):
            addr = 8+i*2
            local = struct.unpack('>H', data[addr:addr+2])[0]
            obj.locals.append(local)
        obj.stack = []
        for i in range(used_stack_size):
            addr = 8+num_locals*2+i*2
            word = struct.unpack('>H', data[addr:addr+2])[0]
            obj.stack.append(word)
        obj.size = 8+num_locals*2+used_stack_size*2
        return obj
Ejemplo n.º 3
0
def print_table(env, opinfo):
    env.screen.finish_wrapping()

    tab_addr = opinfo.operands[0]
    width = opinfo.operands[1]

    if len(opinfo.operands) > 2:
        height = opinfo.operands[2]
    else:
        height = 1

    if len(opinfo.operands) > 3:
        skip = opinfo.operands[3]
    else:
        skip = 0

    col = env.cursor[env.current_window][1]
    for i in range(height):
        row = env.cursor[env.current_window][0]
        line = [
            env.mem[tab_addr + i * (width + skip) + j] for j in range(width)
        ]
        write(env, zscii_to_ascii(env, line))
        if i < height - 1:
            env.screen.finish_wrapping()
            if (env.current_window == 0
                    and row < env.hdr.screen_height_units - 1
                    or env.current_window == 1
                    and row < env.top_window_height - 1):
                env.cursor[env.current_window] = row + 1, col
            else:
                env.cursor[env.current_window] = row, col
Ejemplo n.º 4
0
def print_table(env, opinfo):
    env.screen.finish_wrapping()

    tab_addr = opinfo.operands[0]
    width = opinfo.operands[1]

    if len(opinfo.operands) > 2:
        height = opinfo.operands[2]
    else:
        height = 1

    if len(opinfo.operands) > 3:
        skip = opinfo.operands[3]
    else:
        skip = 0

    col = env.cursor[env.current_window][1]
    for i in range(height):
        row = env.cursor[env.current_window][0]
        line = [env.mem[tab_addr + i*(width+skip) + j] for j in range(width)]
        write(env, zscii_to_ascii(env, line))
        if i < height - 1:
            env.screen.finish_wrapping()
            if (env.current_window == 0 and row < env.hdr.screen_height_units-1 or
              env.current_window == 1 and row < env.top_window_height-1):
                env.cursor[env.current_window] = row+1, col
            else:
                env.cursor[env.current_window] = row, col
Ejemplo n.º 5
0
 def flush(self):
     self.finish_wrapping()
     term.home_cursor()
     buf = self.textBuf
     for i in range(len(buf)):
         for j in range(len(buf[i])):
             c = buf[i][j]
             write_char(c.char, c.fg_color, c.bg_color, c.text_style)
         if i < len(buf) - 1:
             write_char('\n', c.fg_color, c.bg_color, c.text_style)
         else:
             term.fill_to_eol_with_bg_color()
     term.flush()
Ejemplo n.º 6
0
def load_to_env(env, filename):
    msg = env.screen.msg
    try:
        subname, hdrChunk, memChunk, frames = read(filename)
    except IOError as ioerr:
        msg('error reading file: '+str(ioerr)+'\n')
        return False

    if subname != b'IFZS':
        msg('not a quetzal save file\n')
    if env.hdr.release != hdrChunk.release:
        msg('release doesn\'t match\n')
    elif env.hdr.serial != hdrChunk.serial:
        msg('serial doesn\'t match\n')
    elif env.hdr.checksum != hdrChunk.checksum:
        msg('checksum does\'t match\n')
    else:
        env.reset()
        for i in range(len(memChunk.mem)):
            if memChunk.compressed:
                env.mem[i] ^= six.indexbytes(memChunk.mem, i)
            else:
                env.mem[i] = six.indexbytes(memChunk.mem, i)
        env.fixup_after_restore()
        env.pc = hdrChunk.pc
        env.callstack = frames

        # pc is now in wrong place:
        # must fix based on z version
        # after this func returns!
        return True
    return False
Ejemplo n.º 7
0
def load_to_env(env, filename):
    msg = env.screen.msg
    try:
        subname, hdrChunk, memChunk, frames = read(filename)
    except IOError as ioerr:
        msg('error reading file: ' + str(ioerr) + '\n')
        return False

    if subname != b'IFZS':
        msg('not a quetzal save file\n')
    if env.hdr.release != hdrChunk.release:
        msg('release doesn\'t match\n')
    elif env.hdr.serial != hdrChunk.serial:
        msg('serial doesn\'t match\n')
    elif env.hdr.checksum != hdrChunk.checksum:
        msg('checksum does\'t match\n')
    else:
        env.reset()
        for i in range(len(memChunk.mem)):
            if memChunk.compressed:
                env.mem[i] ^= six.indexbytes(memChunk.mem, i)
            else:
                env.mem[i] = six.indexbytes(memChunk.mem, i)
        env.fixup_after_restore()
        env.pc = hdrChunk.pc
        env.callstack = frames

        # pc is now in wrong place:
        # must fix based on z version
        # after this func returns!
        return True
    return False
Ejemplo n.º 8
0
def scan_table(env, opinfo):
    val = opinfo.operands[0]
    tab_addr = opinfo.operands[1]
    tab_len = opinfo.operands[2]
    if len(opinfo.operands) > 3:
        form = opinfo.operands[3]
    else:
        form = 0x82
    val_size = (form >> 7) + 1 # word or byte
    field_len = form & 127

    addr = 0
    for i in range(tab_len):
        test_addr = tab_addr + i*field_len
        if val_size == 2:
            test_val = env.u16(test_addr)
        else:
            test_val = env.mem[test_addr]
        if val == test_val:
            addr = test_addr
            break
    found = addr != 0
    set_var(env, opinfo.store_var, addr)
    if found == opinfo.branch_on:
        handle_branch(env, opinfo.branch_offset)

    if DBG:
        warn('    found', found)
        warn('    addr', addr)
Ejemplo n.º 9
0
def fill_text_buffer(env, user_input, text_buffer):

    text_buf_len = env.mem[text_buffer]
    if text_buf_len < 2:
        err('read error: malformed text buffer')

    text_buf_ptr = text_buffer + 1

    # TODO: make sure I'm interpreting this right.
    # Finding in test suites that you should be able
    # to edit the prefilled text, despite spec seeming
    # to say that any new input goes after prefilled
    # input. Maybe that directive includes ^H's?
    if env.hdr.version >= 5:
        text_buf_ptr += 1

    max_len = text_buf_len-(text_buf_ptr-text_buffer)
    text_len = min(len(user_input), max_len)
    for i in range(text_len):
        env.write8(text_buf_ptr, user_input[i])
        text_buf_ptr += 1

    if env.hdr.version >= 5:
        env.write8(text_buffer + 1, text_buf_ptr-text_buffer-2)
    else:
        env.write8(text_buf_ptr, 0)
Ejemplo n.º 10
0
def fill_text_buffer(env, user_input, text_buffer):

    text_buf_len = env.mem[text_buffer]
    if text_buf_len < 2:
        err('read error: malformed text buffer')

    text_buf_ptr = text_buffer + 1

    # TODO: make sure I'm interpreting this right.
    # Finding in test suites that you should be able
    # to edit the prefilled text, despite spec seeming
    # to say that any new input goes after prefilled
    # input. Maybe that directive includes ^H's?
    if env.hdr.version >= 5:
        text_buf_ptr += 1

    max_len = text_buf_len-(text_buf_ptr-text_buffer)
    text_len = min(len(user_input), max_len)
    for i in range(text_len):
        env.write8(text_buf_ptr, user_input[i])
        text_buf_ptr += 1

    if env.hdr.version >= 5:
        env.write8(text_buffer + 1, text_buf_ptr-text_buffer-2)
    else:
        env.write8(text_buf_ptr, 0)
Ejemplo n.º 11
0
def scan_table(env, opinfo):
    val = opinfo.operands[0]
    tab_addr = opinfo.operands[1]
    tab_len = opinfo.operands[2]
    if len(opinfo.operands) > 3:
        form = opinfo.operands[3]
    else:
        form = 0x82
    val_size = (form >> 7) + 1  # word or byte
    field_len = form & 127

    addr = 0
    for i in range(tab_len):
        test_addr = tab_addr + i * field_len
        if val_size == 2:
            test_val = env.u16(test_addr)
        else:
            test_val = env.mem[test_addr]
        if val == test_val:
            addr = test_addr
            break
    found = addr != 0
    set_var(env, opinfo.store_var, addr)
    if found == opinfo.branch_on:
        handle_branch(env, opinfo.branch_offset)

    if DBG:
        warn('    found', found)
        warn('    addr', addr)
Ejemplo n.º 12
0
 def blank_top_win(self):
     env = self.env
     term.home_cursor()
     for i in range(env.top_window_height):
         write_char('\n', env.fg_color, env.bg_color, env.text_style)
         self.textBuf[i] = self.make_screen_line()
         self.seenBuf[self.textBuf[i]] = False
Ejemplo n.º 13
0
Archivo: blorb.py Proyecto: jan-g/xyfny
 def from_chunk(cls, chunk):
     obj = cls()
     obj.name, obj.size, obj.data = chunk.name, chunk.size, chunk.data
     num_resources = struct.unpack_from('>I', chunk.data)[0]
     obj.resources = []
     for i in range(num_resources):
         usage, number, start = struct.unpack_from('>4sII', chunk.data[4+i*12:])
         obj.resources.append(Resource(usage, number, start))
     return obj
Ejemplo n.º 14
0
def clip_word_list(env, words):
    if env.hdr.version <= 3:
        MAX_WORD_LEN = 6
    else:
        MAX_WORD_LEN = 9
    for i in range(len(words)):
        if len(words[i]) > MAX_WORD_LEN:
            words[i] = words[i][:MAX_WORD_LEN]
    return words
Ejemplo n.º 15
0
def clip_word_list(env, words):
    if env.hdr.version <= 3:
        MAX_WORD_LEN = 6
    else:
        MAX_WORD_LEN = 9
    for i in range(len(words)):
        if len(words[i]) > MAX_WORD_LEN:
            words[i] = words[i][:MAX_WORD_LEN]
    return words
Ejemplo n.º 16
0
def make_dict_string(env, text):

    if env.hdr.version >= 5 and env.hdr.alpha_tab_base:
        base = env.hdr.alpha_tab_base
        A0 = ''.join(map(chr, list(env.mem[base + 0 * 26:base + 1 * 26])))
        A1 = ''.join(map(chr, list(env.mem[base + 1 * 26:base + 2 * 26])))
        A2 = ''.join(map(chr, list(env.mem[base + 2 * 26:base + 3 * 26])))
    else:
        A0 = Default_A0
        A1 = Default_A1
        A2 = Default_A2

    if env.hdr.version == 1:
        A2 = Default_A2_for_z1

    # TODO: S 3.7.1, which expects 4,5 for len-2 shift
    # seqs (not full lock) and works this way only for
    # dict lookups? Still unclear to me, can find no
    # examples of this.

    if env.hdr.version <= 3:
        KEY_LEN = 6
    else:
        KEY_LEN = 9
    text = text[:KEY_LEN]  # will truncate again later, but shortens the loop

    ztext = []
    for char in text:
        if char in A0:
            ztext.append(A0.index(char) + 6)
        elif char in A1:
            # only can be custom alphabets, no version 1/2 code needed
            ztext.append(4)
            ztext.append(A1.index(char) + 6)
        elif char in A2 and A2.index(char) != 0 and (env.hdr.version == 1
                                                     or A2.index(char) != 1):
            if env.hdr.version <= 2:
                ztext.append(3)
            else:
                ztext.append(5)
            ztext.append(A2.index(char) + 6)
        else:
            # 10-bit ZSCII (only 8 bits ever used)
            ztext.append(ord(char) >> 5)  # top 3 bits
            ztext.append(ord(char) & 0x1f)  # bottom 5 bits

    ztext = ztext[:KEY_LEN]  # truncating multi-byte chars here
    while len(ztext) < KEY_LEN:
        ztext.append(5)

    packed_text = []
    for i in range(0, len(ztext), 3):
        c, c1, c2 = ztext[i:i + 3]
        packed_text.append((c << 10) | (c1 << 5) | c2)
    packed_text[-1] |= 0x8000
    return packed_text
Ejemplo n.º 17
0
def copy_table(env, opinfo):
    first = opinfo.operands[0]
    second = opinfo.operands[1]
    size = to_signed_word(opinfo.operands[2])
    if second == 0:
        # zeros out first
        size = abs(size)
        for i in range(size):
            env.write8(first+i, 0)
    elif size > 0:
        # protects against corruption of overlapping tables
        tab = env.mem[first:first+size]
        for i in range(size):
            env.write8(second+i, tab[i])
    elif size < 0:
        # allows for the corruption of overlapping tables
        size = abs(size)
        for i in range(size):
            env.write8(second+i, env.mem[first+i])
Ejemplo n.º 18
0
def copy_table(env, opinfo):
    first = opinfo.operands[0]
    second = opinfo.operands[1]
    size = to_signed_word(opinfo.operands[2])
    if second == 0:
        # zeros out first
        size = abs(size)
        for i in range(size):
            env.write8(first + i, 0)
    elif size > 0:
        # protects against corruption of overlapping tables
        tab = env.mem[first:first + size]
        for i in range(size):
            env.write8(second + i, tab[i])
    elif size < 0:
        # allows for the corruption of overlapping tables
        size = abs(size)
        for i in range(size):
            env.write8(second + i, env.mem[first + i])
Ejemplo n.º 19
0
def make_dict_string(env, text):

    if env.hdr.version >= 5 and env.hdr.alpha_tab_base:
        base = env.hdr.alpha_tab_base
        A0 = ''.join(map(chr, list(env.mem[base+0*26:base+1*26])))
        A1 = ''.join(map(chr, list(env.mem[base+1*26:base+2*26])))
        A2 = ''.join(map(chr, list(env.mem[base+2*26:base+3*26])))
    else:
        A0 = Default_A0
        A1 = Default_A1
        A2 = Default_A2

    if env.hdr.version == 1:
        A2 = Default_A2_for_z1

    # TODO: S 3.7.1, which expects 4,5 for len-2 shift
    # seqs (not full lock) and works this way only for
    # dict lookups? Still unclear to me, can find no
    # examples of this.

    if env.hdr.version <= 3:
        KEY_LEN = 6
    else:
        KEY_LEN = 9
    text = text[:KEY_LEN] # will truncate again later, but shortens the loop

    ztext = []
    for char in text:
        if char in A0:
            ztext.append(A0.index(char)+6)
        elif char in A1:
            # only can be custom alphabets, no version 1/2 code needed
            ztext.append(4)
            ztext.append(A1.index(char)+6)
        elif char in A2 and A2.index(char) != 0 and (env.hdr.version == 1 or A2.index(char) != 1):
            if env.hdr.version <= 2:
                ztext.append(3)
            else:
                ztext.append(5)
            ztext.append(A2.index(char)+6)
        else:
            # 10-bit ZSCII (only 8 bits ever used)
            ztext.append(ord(char) >> 5) # top 3 bits
            ztext.append(ord(char) & 0x1f) # bottom 5 bits

    ztext = ztext[:KEY_LEN] # truncating multi-byte chars here
    while len(ztext) < KEY_LEN:
        ztext.append(5)

    packed_text = []
    for i in range(0, len(ztext), 3):
        c, c1, c2 = ztext[i:i+3]
        packed_text.append((c << 10) | (c1 << 5) | c2)
    packed_text[-1] |= 0x8000
    return packed_text
Ejemplo n.º 20
0
 def from_env(cls, env):
     obj = cls()
     obj.name = b'CMem'
     obj.mem = env.mem[:env.hdr.static_mem_base]
     for i in range(len(obj.mem)):
         obj.mem[i] ^= six.indexbytes(env.orig_mem, i)
     while obj.mem[-1] == 0:
         obj.mem.pop()
     obj.mem = bytes(bytearray(obj.mem))
     obj.compressed = True
     return obj
Ejemplo n.º 21
0
 def from_env(cls, env):
     obj = cls()
     obj.name = b'CMem'
     obj.mem = env.mem[:env.hdr.static_mem_base]
     for i in range(len(obj.mem)):
         obj.mem[i] ^= six.indexbytes(env.orig_mem, i)
     while obj.mem[-1] == 0:
         obj.mem.pop()
     obj.mem = bytes(bytearray(obj.mem))
     obj.compressed = True
     return obj
Ejemplo n.º 22
0
def print_prop_list(env, obj):
    warn('   ',obj,'-',get_obj_str(env, obj)+':')
    ptr = get_prop_list_start(env, obj)
    while env.mem[ptr]:
        num = get_prop_num(env, ptr)
        size = get_prop_size(env, ptr)
        data_ptr = get_prop_data_ptr(env, ptr)
        warn('    prop #',num,' - size',size, end='')
        for i in range(size):
            warn('   ',hex(env.mem[data_ptr+i]), end='')
        warn()
        ptr = data_ptr + size
Ejemplo n.º 23
0
def print_prop_list(env, obj):
    warn('   ',obj,'-',get_obj_str(env, obj)+':')
    ptr = get_prop_list_start(env, obj)
    while env.mem[ptr]:
        num = get_prop_num(env, ptr)
        size = get_prop_size(env, ptr)
        data_ptr = get_prop_data_ptr(env, ptr)
        warn('    prop #',num,' - size',size, end='')
        for i in range(size):
            warn('   ',hex(env.mem[data_ptr+i]), end='')
        warn()
        ptr = data_ptr + size
Ejemplo n.º 24
0
def dbg_dump_dictionary(env):
    dict_base = env.hdr.dict_base
    num_word_seps = env.mem[dict_base]
    entry_length = env.mem[dict_base + 1 + num_word_seps]
    num_entries = env.u16(dict_base + 1 + num_word_seps + 1)
    entries_start = dict_base + 1 + num_word_seps + 1 + 2
    env.screen.write('\n')
    for i in range(num_entries):
        entry_addr = entries_start + i * entry_length
        entry = [env.u16(entry_addr), env.u16(entry_addr + 2)]
        entry_unpacked = ops.unpack_string(env, entry, warn_unknown_char=False)
        raw_hex = ' '.join(map(hex, entry))
        env.screen.write(raw_hex + ' ' + repr(entry_unpacked) + '\n')
        env.screen.flush()
Ejemplo n.º 25
0
def dbg_dump_dictionary(env):
    dict_base = env.hdr.dict_base
    num_word_seps = env.mem[dict_base]
    entry_length = env.mem[dict_base+1+num_word_seps]
    num_entries = env.u16(dict_base+1+num_word_seps+1)
    entries_start = dict_base+1+num_word_seps+1+2
    env.screen.write('\n')
    for i in range(num_entries):
        entry_addr = entries_start+i*entry_length
        entry = [env.u16(entry_addr),
                 env.u16(entry_addr+2)]
        entry_unpacked = ops.unpack_string(env, entry, warn_unknown_char=False)
        raw_hex = ' '.join(map(hex, entry))
        env.screen.write(raw_hex + ' ' + repr(entry_unpacked) + '\n')
        env.screen.flush()
Ejemplo n.º 26
0
def verify(env, opinfo):
    vsum = 0
    for i in range(0x40, get_file_len(env)):
        vsum += six.indexbytes(env.orig_mem, i)
    vsum &= 0xffff
    result = vsum == env.hdr.checksum

    if result == opinfo.branch_on:
        handle_branch(env, opinfo.branch_offset)

    if DBG:
        warn('    vsum', vsum)
        warn('    checksum in header', env.hdr.checksum)
        warn('    branch_on', opinfo.branch_on)
        warn('    result', result)
Ejemplo n.º 27
0
def verify(env, opinfo):
    vsum = 0
    for i in range(0x40, get_file_len(env)):
        vsum += six.indexbytes(env.orig_mem, i)
    vsum &= 0xffff
    result = vsum == env.hdr.checksum

    if result == opinfo.branch_on:
        handle_branch(env, opinfo.branch_offset)

    if DBG:
        warn('    vsum', vsum)
        warn('    checksum in header', env.hdr.checksum)
        warn('    branch_on', opinfo.branch_on)
        warn('    result', result)
Ejemplo n.º 28
0
def parse_call_header(env, call_addr):
    num_locals = env.mem[call_addr]

    if num_locals > 15:
        err('calling a non-function (more than 15 local vars)')

    if env.hdr.version < 5:
        locals_ptr = call_addr + 1
        locals = []
        for i in range(num_locals):
            locals.append(env.u16(locals_ptr))
            locals_ptr += 2
        code_ptr = locals_ptr
    else:
        locals = [0] * num_locals
        code_ptr = call_addr + 1

    return locals, code_ptr
Ejemplo n.º 29
0
def parse_call_header(env, call_addr):
    num_locals = env.mem[call_addr]

    if num_locals > 15:
        err('calling a non-function (more than 15 local vars)')

    if env.hdr.version < 5:
        locals_ptr = call_addr + 1
        locals = []
        for i in range(num_locals):
            locals.append(env.u16(locals_ptr))
            locals_ptr += 2
        code_ptr = locals_ptr
    else:
        locals = [0] * num_locals
        code_ptr = call_addr + 1

    return locals, code_ptr
Ejemplo n.º 30
0
def output_stream(env, opinfo):
    stream = to_signed_word(opinfo.operands[0])
    if stream < 0:
        stream = abs(stream)
        if stream == 3:
            table_addr = env.memory_ostream_stack.pop()
            zscii_buffer = ascii_to_zscii(env.output_buffer[stream])
            buflen = len(zscii_buffer)
            env.write16(table_addr, buflen)
            for i in range(len(zscii_buffer)):
                env.write8(table_addr + 2 + i, zscii_buffer[i])
            env.output_buffer[stream] = ''
            if len(env.memory_ostream_stack) == 0:
                env.selected_ostreams.discard(stream)
        else:
            env.selected_ostreams.discard(stream)
    elif stream > 0:
        env.selected_ostreams.add(stream)
        if stream == 3:
            table_addr = opinfo.operands[1]
            if len(env.memory_ostream_stack) == 16:
                err('too many memory-based ostreams (>16)')
            env.memory_ostream_stack.append(table_addr)
Ejemplo n.º 31
0
def output_stream(env, opinfo):
    stream = to_signed_word(opinfo.operands[0])
    if stream < 0:
        stream = abs(stream)
        if stream == 3:
            table_addr = env.memory_ostream_stack.pop()
            zscii_buffer = ascii_to_zscii(env.output_buffer[stream])
            buflen = len(zscii_buffer)
            env.write16(table_addr, buflen)
            for i in range(len(zscii_buffer)):
                env.write8(table_addr+2+i, zscii_buffer[i])
            env.output_buffer[stream] = ''
            if len(env.memory_ostream_stack) == 0:
                env.selected_ostreams.discard(stream)
        else:
            env.selected_ostreams.discard(stream)
    elif stream > 0:
        env.selected_ostreams.add(stream)
        if stream == 3:
            table_addr = opinfo.operands[1]
            if len(env.memory_ostream_stack) == 16:
                err('too many memory-based ostreams (>16)')
            env.memory_ostream_stack.append(table_addr)
Ejemplo n.º 32
0
def decode(env, pc):

    opcode = env.mem[pc]
    form = get_opcode_form(env, opcode)
    count = get_operand_count(opcode, form)

    if form == ExtForm:
        opcode = env.mem[pc+1]

    if form == ShortForm:
        szbyte = (opcode >> 4) & 3
        szbyte = (szbyte << 6) | 0x3f
        operand_ptr = pc+1
        sizes = get_operand_sizes(szbyte)
    elif form == VarForm:
        szbyte = env.mem[pc+1]
        operand_ptr = pc+2
        sizes = get_operand_sizes(szbyte)
        # handle call_vn2/vs2's extra szbyte
        if opcode in (236, 250):
            szbyte2 = env.mem[pc+2]
            sizes += get_operand_sizes(szbyte2)
            operand_ptr = pc+3
    elif form == ExtForm:
        szbyte = env.mem[pc+2]
        operand_ptr = pc+3
        sizes = get_operand_sizes(szbyte)
    elif form == LongForm:
        operand_ptr = pc+1
        sizes = []
        for offset in (6,5):
            if (opcode >> offset) & 1:
                sizes.append(VarSize)
            else:
                sizes.append(ByteSize)
    else:
        err('unknown opform specified: ' + str(form))

    operands = []
    var_op_info = []
    for i in range(len(sizes)):
        size = sizes[i]
        if size == WordSize:
            operands.append(env.u16(operand_ptr))
            operand_ptr += 2
        elif size == ByteSize:
            operands.append(env.mem[operand_ptr])
            operand_ptr += 1
        elif size == VarSize:
            operands.append(None) #this is fixedup after every load from icache
            var_num = env.mem[operand_ptr]
            var_op_info.append( (i,var_num) )
            operand_ptr += 1
        else:
            err('unknown operand size specified: ' + str(size))

    if form == ExtForm:
        dispatch = ops.ext_dispatch
        has_store_var = ops.ext_has_store_var
        has_branch_var = ops.ext_has_branch_var
    else:
        dispatch = ops.dispatch
        has_store_var = ops.has_store_var
        has_branch_var = ops.has_branch_var

    opinfo = OpInfo(operands, var_op_info)

    opinfo.opcode = opcode
    opinfo.is_extended = form == ExtForm

    if has_store_var[opcode]:
        opinfo.store_var = env.mem[operand_ptr]
        opinfo.last_pc_store_var = operand_ptr # to make quetzal saves easier
        operand_ptr += 1

    if has_branch_var[opcode]: # std:4.7
        branch_info = env.mem[operand_ptr]
        opinfo.last_pc_branch_var = operand_ptr # to make quetzal saves easier
        operand_ptr += 1
        opinfo.branch_on = (branch_info & 128) == 128
        if branch_info & 64:
            opinfo.branch_offset = branch_info & 0x3f
        else:
            branch_offset = branch_info & 0x3f
            branch_offset <<= 8
            branch_offset |= env.mem[operand_ptr]
            operand_ptr += 1
            # sign extend 14b # to 16b
            if branch_offset & 0x2000:
                branch_offset |= 0xc000
            opinfo.branch_offset = to_signed_word(branch_offset)

    # handle print_ and print_ret's string operand
    if form != ExtForm and opcode in (178, 179):
        while True:
            word = env.u16(operand_ptr)
            operand_ptr += 2
            operands.append(word)
            if word & 0x8000:
                break

    # After all that, operand_ptr should point to the next opcode
    next_pc = operand_ptr

    if DBG:
        def hex_out(bytes):
            s = ''
            for b in bytes:
                s += hex(b) + ' '
            return s
        op_hex = hex_out(env.mem[pc:next_pc])

        warn('decode: pc', hex(pc))
        warn('      opcode', opcode)
        warn('      form', form)
        warn('      count', count)
        if opinfo.store_var:
            warn('      store_var', ops.get_var_name(opinfo.store_var))
        warn('      sizes', sizes)
        warn('      operands', opinfo.operands)
        warn('      next_pc', hex(next_pc))
        #warn('      bytes', op_hex)

    return dispatch[opcode], opinfo, next_pc
Ejemplo n.º 33
0
def handle_parse(env, text_buffer, parse_buffer, dict_base=0, skip_unknown_words=0):

    used_tbuf_len = get_used_tbuf_len(env, text_buffer)
    parse_buf_len = env.mem[parse_buffer]
    if parse_buf_len < 1:
        err('read error: malformed parse buffer')

    word_separators = []
    if dict_base == 0:
        dict_base = env.hdr.dict_base
    num_word_seps = env.mem[dict_base]
    for i in range(num_word_seps):
        word_separators.append(env.mem[dict_base+1+i])

    word = []
    words = []
    word_locs = []
    word_len = 0
    word_lens = []
    scan_ptr = get_text_scan_ptr(env, text_buffer)
    for i in range(used_tbuf_len):

        c = env.mem[scan_ptr]

        if c == ord(' '):
            if word:
                word_lens.append(word_len)
                word_len = 0
                words.append(word)
                word = []
            scan_ptr += 1

        elif c in word_separators:
            if word:
                word_lens.append(word_len)
                word_len = 0
                words.append(word)
                word = []
            word_locs.append(scan_ptr-text_buffer)
            word_lens.append(1)
            words.append([c])
            scan_ptr += 1

        else:
            if not word:
                word_locs.append(scan_ptr-text_buffer)
            word.append(c)
            word_len += 1
            scan_ptr += 1

    if word:
        word_lens.append(word_len)
        words.append(word)

    words = clip_word_list(env, words)

    # limit to parse_buf_len (which is num words)
    words = words[:parse_buf_len]
    word_locs = word_locs[:parse_buf_len]
    word_lens = word_lens[:parse_buf_len]

    # NOTE: This could be a binary search for read() opcodes,
    # but dictionaries for tokenize() can be unsorted. So maybe
    # just always do a linear search if speed is never an issue
    # these days?

    dict_base = env.hdr.dict_base
    num_word_seps = env.mem[dict_base]

    entry_length = env.mem[dict_base+1+num_word_seps]
    num_entries = env.u16(dict_base+1+num_word_seps+1)
    # this can be negative to signify dictionary is unsorted
    num_entries = abs(num_entries)
    entries_start = dict_base+1+num_word_seps+1+2

    env.write8(parse_buffer+1, len(words))
    parse_ptr = parse_buffer+2
    for word,wloc,wlen in zip(words, word_locs, word_lens):

        wordstr = ''.join(map(chr, word))
        packed_word = make_dict_string(env, wordstr)

        dict_addr = 0
        for i in range(num_entries):
            entry_addr = entries_start+i*entry_length
            if match_dict_entry(env, entry_addr, packed_word):
                dict_addr = entry_addr
                break
        if dict_addr != 0 or skip_unknown_words == 0:
            env.write16(parse_ptr, dict_addr)
            env.write8(parse_ptr+2, wlen)
            env.write8(parse_ptr+3, wloc)
        parse_ptr += 4
Ejemplo n.º 34
0
 def find_char_or_return_len(cs, c):
     for i in range(len(cs)):
         if cs[i].char == c:
             return i
     return len(cs)
Ejemplo n.º 35
0
 def blank_bottom_win(self):
     for i in range(self.env.top_window_height,
                    self.env.hdr.screen_height_units):
         self.scroll()
Ejemplo n.º 36
0
def decode(env, pc):

    opcode = env.mem[pc]
    form = get_opcode_form(env, opcode)
    count = get_operand_count(opcode, form)

    if form == ExtForm:
        opcode = env.mem[pc + 1]

    if form == ShortForm:
        szbyte = (opcode >> 4) & 3
        szbyte = (szbyte << 6) | 0x3f
        operand_ptr = pc + 1
        sizes = get_operand_sizes(szbyte)
    elif form == VarForm:
        szbyte = env.mem[pc + 1]
        operand_ptr = pc + 2
        sizes = get_operand_sizes(szbyte)
        # handle call_vn2/vs2's extra szbyte
        if opcode in (236, 250):
            szbyte2 = env.mem[pc + 2]
            sizes += get_operand_sizes(szbyte2)
            operand_ptr = pc + 3
    elif form == ExtForm:
        szbyte = env.mem[pc + 2]
        operand_ptr = pc + 3
        sizes = get_operand_sizes(szbyte)
    elif form == LongForm:
        operand_ptr = pc + 1
        sizes = []
        for offset in (6, 5):
            if (opcode >> offset) & 1:
                sizes.append(VarSize)
            else:
                sizes.append(ByteSize)
    else:
        err('unknown opform specified: ' + str(form))

    operands = []
    var_op_info = []
    for i in range(len(sizes)):
        size = sizes[i]
        if size == WordSize:
            operands.append(env.u16(operand_ptr))
            operand_ptr += 2
        elif size == ByteSize:
            operands.append(env.mem[operand_ptr])
            operand_ptr += 1
        elif size == VarSize:
            operands.append(
                None)  #this is fixedup after every load from icache
            var_num = env.mem[operand_ptr]
            var_op_info.append((i, var_num))
            operand_ptr += 1
        else:
            err('unknown operand size specified: ' + str(size))

    if form == ExtForm:
        dispatch = ops.ext_dispatch
        has_store_var = ops.ext_has_store_var
        has_branch_var = ops.ext_has_branch_var
    else:
        dispatch = ops.dispatch
        has_store_var = ops.has_store_var
        has_branch_var = ops.has_branch_var

    opinfo = OpInfo(operands, var_op_info)

    opinfo.opcode = opcode
    opinfo.is_extended = form == ExtForm

    if has_store_var[opcode]:
        opinfo.store_var = env.mem[operand_ptr]
        opinfo.last_pc_store_var = operand_ptr  # to make quetzal saves easier
        operand_ptr += 1

    if has_branch_var[opcode]:  # std:4.7
        branch_info = env.mem[operand_ptr]
        opinfo.last_pc_branch_var = operand_ptr  # to make quetzal saves easier
        operand_ptr += 1
        opinfo.branch_on = (branch_info & 128) == 128
        if branch_info & 64:
            opinfo.branch_offset = branch_info & 0x3f
        else:
            branch_offset = branch_info & 0x3f
            branch_offset <<= 8
            branch_offset |= env.mem[operand_ptr]
            operand_ptr += 1
            # sign extend 14b # to 16b
            if branch_offset & 0x2000:
                branch_offset |= 0xc000
            opinfo.branch_offset = to_signed_word(branch_offset)

    # handle print_ and print_ret's string operand
    if form != ExtForm and opcode in (178, 179):
        while True:
            word = env.u16(operand_ptr)
            operand_ptr += 2
            operands.append(word)
            if word & 0x8000:
                break

    # After all that, operand_ptr should point to the next opcode
    next_pc = operand_ptr

    if DBG:

        def hex_out(bytes):
            s = ''
            for b in bytes:
                s += hex(b) + ' '
            return s

        op_hex = hex_out(env.mem[pc:next_pc])

        warn('decode: pc', hex(pc))
        warn('      opcode', opcode)
        warn('      form', form)
        warn('      count', count)
        if opinfo.store_var:
            warn('      store_var', ops.get_var_name(opinfo.store_var))
        warn('      sizes', sizes)
        warn('      operands', opinfo.operands)
        warn('      next_pc', hex(next_pc))
        #warn('      bytes', op_hex)

    return dispatch[opcode], opinfo, next_pc
Ejemplo n.º 37
0
 def make_screen_line(self):
     c, fg, bg, style = ' ', self.env.fg_color, self.env.bg_color, 'normal'
     return ScreenLine([
         ScreenChar(c, fg, bg, style)
         for i in range(self.env.hdr.screen_width_units)
     ])
Ejemplo n.º 38
0
 def first_draw(self):
     env = self.env
     for i in range(env.hdr.screen_height_units - 1):
         write_char('\n', env.fg_color, env.bg_color, env.text_style)
     term.fill_to_eol_with_bg_color()
     term.home_cursor()
Ejemplo n.º 39
0
 def make_screen_buf(self):
     return [
         self.make_screen_line()
         for i in range(self.env.hdr.screen_height_units)
     ]
Ejemplo n.º 40
0
def handle_parse(env, text_buffer, parse_buffer, dict_base=0, skip_unknown_words=0):

    used_tbuf_len = get_used_tbuf_len(env, text_buffer)
    parse_buf_len = env.mem[parse_buffer]
    if parse_buf_len < 1:
        err('read error: malformed parse buffer')

    word_separators = []
    if dict_base == 0:
        dict_base = env.hdr.dict_base
    num_word_seps = env.mem[dict_base]
    for i in range(num_word_seps):
        word_separators.append(env.mem[dict_base+1+i])

    word = []
    words = []
    word_locs = []
    word_len = 0
    word_lens = []
    scan_ptr = get_text_scan_ptr(env, text_buffer)
    for i in range(used_tbuf_len):

        c = env.mem[scan_ptr]

        if c == ord(' '):
            if word:
                word_lens.append(word_len)
                word_len = 0
                words.append(word)
                word = []
            scan_ptr += 1

        elif c in word_separators:
            if word:
                word_lens.append(word_len)
                word_len = 0
                words.append(word)
                word = []
            word_locs.append(scan_ptr-text_buffer)
            word_lens.append(1)
            words.append([c])
            scan_ptr += 1

        else:
            if not word:
                word_locs.append(scan_ptr-text_buffer)
            word.append(c)
            word_len += 1
            scan_ptr += 1

    if word:
        word_lens.append(word_len)
        words.append(word)

    words = clip_word_list(env, words)

    # limit to parse_buf_len (which is num words)
    words = words[:parse_buf_len]
    word_locs = word_locs[:parse_buf_len]
    word_lens = word_lens[:parse_buf_len]

    # NOTE: This could be a binary search for read() opcodes,
    # but dictionaries for tokenize() can be unsorted. So maybe
    # just always do a linear search if speed is never an issue
    # these days?

    dict_base = env.hdr.dict_base
    num_word_seps = env.mem[dict_base]

    entry_length = env.mem[dict_base+1+num_word_seps]
    num_entries = env.u16(dict_base+1+num_word_seps+1)
    # this can be negative to signify dictionary is unsorted
    num_entries = abs(num_entries)
    entries_start = dict_base+1+num_word_seps+1+2

    env.write8(parse_buffer+1, len(words))
    parse_ptr = parse_buffer+2
    for word,wloc,wlen in zip(words, word_locs, word_lens):

        wordstr = ''.join(map(chr, word))
        packed_word = make_dict_string(env, wordstr)

        dict_addr = 0
        for i in range(num_entries):
            entry_addr = entries_start+i*entry_length
            if match_dict_entry(env, entry_addr, packed_word):
                dict_addr = entry_addr
                break
        if dict_addr != 0 or skip_unknown_words == 0:
            env.write16(parse_ptr, dict_addr)
            env.write8(parse_ptr+2, wlen)
            env.write8(parse_ptr+3, wloc)
        parse_ptr += 4
Ejemplo n.º 41
0
    def get_line_of_input(self, prompt='', prefilled=''):
        env = self.env

        for c in prompt:
            self.write_unwrapped(
                [ScreenChar(c, env.fg_color, env.bg_color, env.text_style)])
        self.flush()
        self.update_seen_lines()

        row, col = env.cursor[env.current_window]

        term.home_cursor()
        term.cursor_down(row)
        term.cursor_right(col)
        term.set_color(env.fg_color, env.bg_color)
        if line_empty(self.textBuf[row][col:]):
            term.fill_to_eol_with_bg_color()
        term.show_cursor()

        col = max(
            0, col - len(prefilled)
        )  # TODO: prefilled is a seldom-used old and crusty feature, but make unicode safe
        env.cursor[env.current_window] = row, col

        class CursorLine(object):
            def __init__(self, cursor_start, chars):
                self.cursor = cursor_start
                self.chars = chars

            def backspace(self):
                if self.cursor == 0:
                    return
                self.left()
                self.delete_char()

            def delete_char(self):
                del self.chars[self.cursor:self.cursor + 1]
                self.refresh_rest_of_line(is_delete=True)

            def refresh_rest_of_line(self, is_delete=False):
                rest = self.chars[self.cursor:]
                term.puts(''.join(rest))
                to_back_up = len(rest)
                if is_delete:
                    term.puts(' ')
                    to_back_up += 1
                if to_back_up:
                    term.cursor_left(to_back_up)

            def left(self):
                if self.cursor > 0:
                    self.cursor -= 1
                    term.cursor_left()

            def right(self):
                if self.cursor < len(self.chars):
                    self.cursor += 1
                    term.cursor_right()

            def home(self):
                while self.cursor > 0:
                    self.left()

            def end(self):
                while self.cursor != len(self.chars):
                    self.right()

            def kill_left(self):
                while self.chars[:self.cursor]:
                    self.backspace()

            def kill_right(self):
                while self.chars[self.cursor:]:
                    self.delete_char()

            def insert(self, c):
                self.chars.insert(self.cursor, c)
                term.puts(c)
                self.cursor += 1
                self.refresh_rest_of_line()

        cursor_start = len(prefilled)
        cursor_line = CursorLine(cursor_start, [c for c in prefilled])

        max_input_len = 120  # 120 char limit seen on gargoyle
        c = term.getch_or_esc_seq()
        while c != '\n' and c != '\r':
            if c == '\b' or c == '\x7f':
                cursor_line.backspace()

            # normal edit keys and a bit of readline flavor

            # left arrow or C-b
            elif c == '\x1b[D' or c == '\x02':
                cursor_line.left()

            # right arrow or C-f
            elif c == '\x1b[C' or c == '\x06':
                cursor_line.right()

            # home or C-a
            elif c == '\x1b[H' or c == '\x01':
                cursor_line.home()

            # end or C-e
            elif c == '\x1b[F' or c == '\x05':
                cursor_line.end()

            # delete or C-d
            elif c == '\x1b[3~' or c == '\x04':
                cursor_line.delete_char()

            # C-u, kill left of cursor
            elif c == '\x15':
                cursor_line.kill_left()

            # C-u, kill right of cursor
            elif c == '\x0b':
                cursor_line.kill_right()

            else:
                if is_valid_inline_char(c) and len(
                        cursor_line.chars) < max_input_len:
                    if c == '\t':
                        if len(cursor_line.chars) + 4 <= max_input_len:
                            for i in range(4):
                                cursor_line.insert(' ')
                    else:
                        cursor_line.insert(c)

            c = term.getch_or_esc_seq()

        term.hide_cursor()
        term.flush()
        for c in cursor_line.chars:
            self.write_unwrapped(
                [ScreenChar(c, env.fg_color, env.bg_color, env.text_style)])
        self.new_line_via_spaces(env.fg_color, env.bg_color, env.text_style)
        term.home_cursor()
        return ''.join(cursor_line.chars)