Esempio n. 1
2
def renum(new_line, start_line, step):
    """ Renumber stored program. """
    new_line = 10 if new_line is None else new_line
    start_line = 0 if start_line is None else start_line
    step = 10 if step is None else step
    # get a sorted list of line numbers
    keys = sorted([ k for k in state.basic_state.line_numbers.keys() if k >= start_line])
    # assign the new numbers
    old_to_new = {}
    for old_line in keys:
        if old_line < 65535 and new_line > 65529:
            raise error.RunError(error.IFC)
        if old_line == 65536:
            break
        old_to_new[old_line] = new_line
        state.basic_state.last_stored = new_line
        new_line += step
    # write the new numbers
    for old_line in old_to_new:
        state.basic_state.bytecode.seek(state.basic_state.line_numbers[old_line])
        # skip the \x00\xC0\xDE & overwrite line number
        state.basic_state.bytecode.read(3)
        state.basic_state.bytecode.write(str(vartypes.value_to_uint(old_to_new[old_line])))
    # rebuild the line number dictionary
    new_lines = {}
    for old_line in old_to_new:
        new_lines[old_to_new[old_line]] = state.basic_state.line_numbers[old_line]
        del state.basic_state.line_numbers[old_line]
    state.basic_state.line_numbers.update(new_lines)
    # write the indirect line numbers
    state.basic_state.bytecode.seek(0)
    while util.skip_to_read(state.basic_state.bytecode, ('\x0e',)) == '\x0e':
        # get the old g number
        jumpnum = vartypes.uint_to_value(bytearray(state.basic_state.bytecode.read(2)))
        try:
            newjump = old_to_new[jumpnum]
        except KeyError:
            # not redefined, exists in program?
            if jumpnum in state.basic_state.line_numbers:
                newjump = jumpnum
            else:
                linum = get_line_number(state.basic_state.bytecode.tell())
                console.write_line('Undefined line ' + str(jumpnum) + ' in ' + str(linum))
        state.basic_state.bytecode.seek(-2, 1)
        state.basic_state.bytecode.write(str(vartypes.value_to_uint(newjump)))
    # stop running if we were
    flow.set_pointer(False)
    # reset loop stacks
    state.basic_state.gosub_return = []
    state.basic_state.for_next_stack = []
    state.basic_state.while_wend_stack = []
    # renumber error handler
    if state.basic_state.on_error:
        state.basic_state.on_error = old_to_new[state.basic_state.on_error]
    # renumber event traps
    for handler in state.basic_state.events.all:
        if handler.gosub:
            handler.set_jump(old_to_new[handler.gosub])
Esempio n. 2
0
 def __init__(self, greet, load):
     """ Initialise the interpreter session. """
     # true if a prompt is needed on next cycle
     self.prompt = True
     # input mode is AUTO (used by AUTO)
     state.basic_state.auto_mode = False
     # interpreter is executing a command
     state.basic_state.parse_mode = False
     # interpreter is waiting for INPUT or LINE INPUT
     state.basic_state.input_mode = False
     # previous interpreter mode
     self.last_mode = False, False
     # syntax error prompt and EDIT
     state.basic_state.edit_prompt = False
     # initialise the display
     display.init()
     # initialise the console
     console.init_mode()
     # set up event handlers
     state.basic_state.events = events.Events()
     # load initial program
     if load:
         # on load, accept capitalised versions and default extension
         with disk.open_native_or_dos_filename(load) as progfile:
             program.load(progfile)
     # set up interpreter and memory model state
     reset.clear()
     # greeting and keys
     if greet:
         console.clear()
         console.write_line(greeting.format(version=plat.version, free=var.fre()))
         console.show_keys(True)
Esempio n. 3
0
 def spawn_shell(command):
     """ Run a SHELL subprocess. """
     cmd = shell_command
     if command:
         cmd += ' -c "' + command + '"'
     p = pexpect.spawn(str(cmd))
     while True:
         try:
             c = state.console_state.keyb.get_char()
         except error.Break:
             # ignore ctrl+break in SHELL
             pass
         if c == '\b':  # BACKSPACE
             p.send('\x7f')
         elif c != '':
             p.send(c)
         while True:
             try:
                 c = p.read_nonblocking(1, timeout=0)
             except:
                 c = ''
             if c == '' or c == '\n':
                 break
             elif c == '\r':
                 console.write_line()
             elif c == '\b':
                 if state.console_state.col != 1:
                     console.set_pos(state.console_state.row,
                                     state.console_state.col - 1)
             else:
                 console.write(c)
         if c == '' and not p.isalive():
             return
Esempio n. 4
0
 def spawn_shell(command):
     """ Run a SHELL subprocess. """
     cmd = shell_command
     if command:
         cmd += ' -c "' + command + '"'            
     p = pexpect.spawn(str(cmd))
     while True:
         try:
             c = state.console_state.keyb.get_char()
         except error.Break:
             # ignore ctrl+break in SHELL
             pass
         if c == '\b': # BACKSPACE
             p.send('\x7f')
         elif c != '':
             p.send(c)
         while True:
             try:
                 c = p.read_nonblocking(1, timeout=0)
             except: 
                 c = ''
             if c == '' or c == '\n':
                 break
             elif c == '\r':
                 console.write_line()    
             elif c == '\b':
                 if state.console_state.col != 1:
                     console.set_pos(state.console_state.row, 
                                     state.console_state.col-1)
             else:
                 console.write(c)
         if c == '' and not p.isalive(): 
             return
Esempio n. 5
0
def show_prompt():
    """ Show the Ok or EDIT prompt, unless suppressed. """
    if state.basic_state.execute_mode:
        return
    if state.basic_state.edit_prompt:
        linenum, tell = state.basic_state.edit_prompt
        program.edit(linenum, tell)
        state.basic_state.edit_prompt = False
    elif state.basic_state.prompt:
        console.start_line()
        console.write_line("Ok\xff")
Esempio n. 6
0
 def show_prompt(self):
     """ Show the Ok or EDIT prompt, unless suppressed. """
     if state.basic_state.parse_mode:
         return
     if state.basic_state.edit_prompt:
         linenum, tell = state.basic_state.edit_prompt
         program.edit(linenum, tell)
         state.basic_state.edit_prompt = False
     elif self.prompt:
         console.start_line()
         console.write_line("Ok\xff")
Esempio n. 7
0
 def spawn_shell(command):
     """ Run a SHELL subprocess. """
     global shell_output
     cmd = shell_command
     if command:
         cmd += ' /C "' + command + '"'
     p = subprocess.Popen(
         str(cmd).split(), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True
     )
     outp = threading.Thread(target=process_stdout, args=(p, p.stdout))
     outp.daemon = True
     outp.start()
     errp = threading.Thread(target=process_stdout, args=(p, p.stderr))
     errp.daemon = True
     errp.start()
     word = ""
     while p.poll() == None or shell_output:
         if shell_output:
             lines, shell_output = shell_output.split("\r\n"), ""
             last = lines.pop()
             for line in lines:
                 # progress visible - keep updating the backend
                 # don't process anything but video events here
                 backend.video.check_events()
                 console.write_line(line)
             console.write(last)
         if p.poll() != None:
             # drain output then break
             continue
         try:
             c = state.console_state.keyb.get_char()
         except error.Break:
             pass
         if c in ("\r", "\n"):
             # shift the cursor left so that CMD.EXE's echo can overwrite
             # the command that's already there. Note that Wine's CMD.EXE
             # doesn't echo the command, so it's overwritten by the output...
             console.write("\x1D" * len(word))
             p.stdin.write(word + "\r\n")
             word = ""
         elif c == "\b":
             # handle backspace
             if word:
                 word = word[:-1]
                 console.write("\x1D \x1D")
         elif c != "":
             # only send to pipe when enter is pressed
             # needed for Wine and to handle backspace properly
             word += c
             console.write(c)
     outp.join()
     errp.join()
Esempio n. 8
0
 def spawn_shell(command):
     """ Run a SHELL subprocess. """
     global shell_output
     cmd = shell_command
     if command:
         cmd += ' /C "' + command + '"'
     p = subprocess.Popen(str(cmd).split(),
                          stdin=subprocess.PIPE,
                          stdout=subprocess.PIPE,
                          stderr=subprocess.PIPE,
                          shell=True)
     outp = threading.Thread(target=process_stdout, args=(p, p.stdout))
     outp.daemon = True
     outp.start()
     errp = threading.Thread(target=process_stdout, args=(p, p.stderr))
     errp.daemon = True
     errp.start()
     word = ''
     while p.poll() is None or shell_output:
         if shell_output:
             lines, shell_output = shell_output.split('\r\n'), ''
             last = lines.pop()
             for line in lines:
                 console.write_line(line)
             console.write(last)
         if p.poll() is not None:
             # drain output then break
             continue
         try:
             c = state.console_state.keyb.get_char()
         except error.Break:
             pass
         if c in ('\r', '\n'):
             # shift the cursor left so that CMD.EXE's echo can overwrite
             # the command that's already there. Note that Wine's CMD.EXE
             # doesn't echo the command, so it's overwritten by the output...
             console.write('\x1D' * len(word))
             p.stdin.write(word + '\r\n')
             word = ''
         elif c == '\b':
             # handle backspace
             if word:
                 word = word[:-1]
                 console.write('\x1D \x1D')
         elif c != '':
             # only send to pipe when enter is pressed
             # needed for Wine and to handle backspace properly
             word += c
             console.write(c)
     outp.join()
     errp.join()
Esempio n. 9
0
 def spawn_shell(command):
     """ Run a SHELL subprocess. """
     global shell_output
     cmd = shell_command
     if command:
         cmd += ' /C "' + command + '"'
     p = subprocess.Popen( str(cmd).split(), stdin=subprocess.PIPE,
                 stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
     outp = threading.Thread(target=process_stdout, args=(p, p.stdout))
     outp.daemon = True
     outp.start()
     errp = threading.Thread(target=process_stdout, args=(p, p.stderr))
     errp.daemon = True
     errp.start()
     word = ''
     while p.poll() is None or shell_output:
         if shell_output:
             lines, shell_output = shell_output.split('\r\n'), ''
             last = lines.pop()
             for line in lines:
                 console.write_line(line)
             console.write(last)
         if p.poll() is not None:
             # drain output then break
             continue
         try:
             c = state.console_state.keyb.get_char()
         except error.Break:
             pass
         if c in ('\r', '\n'):
             # shift the cursor left so that CMD.EXE's echo can overwrite
             # the command that's already there. Note that Wine's CMD.EXE
             # doesn't echo the command, so it's overwritten by the output...
             console.write('\x1D' * len(word))
             p.stdin.write(word + '\r\n')
             word = ''
         elif c == '\b':
             # handle backspace
             if word:
                 word = word[:-1]
                 console.write('\x1D \x1D')
         elif c != '':
             # only send to pipe when enter is pressed
             # needed for Wine and to handle backspace properly
             word += c
             console.write(c)
     outp.join()
     errp.join()
Esempio n. 10
0
def print_greeting(console):
    """ Print the greeting and the KEY row if we're not running a program. """
    import var
    greeting = ('PC-BASIC {version} {note}\r'
                '(C) Copyright 2013--2015 Rob Hagemans.\r'
                '{free} Bytes free')
    # following GW, don't write greeting for redirected input
    # or command-line filter run
    if (not config.get('run') and not config.get('exec')
            and not config.get('input') and not config.get(0)
            and not config.get('interface') == 'none'):
        debugstr = ' [DEBUG mode]' if config.get('debug') else ''
        params = {'version': plat.version, 'note': debugstr, 'free': var.fre()}
        console.clear()
        console.write_line(greeting.format(**params))
        console.show_keys(True)
Esempio n. 11
0
def print_greeting(console):
    """ Print the greeting and the KEY row if we're not running a program. """
    import var
    greeting = (
        'PC-BASIC {version} {note}\r'
        '(C) Copyright 2013--2015 Rob Hagemans.\r'
        '{free} Bytes free')
    # following GW, don't write greeting for redirected input
    # or command-line filter run
    if (not config.get('run') and not config.get('exec') and
             not config.get('input') and not config.get(0) and
             not config.get('interface') == 'none'):
        debugstr = ' [DEBUG mode]' if config.get('debug') else ''
        params = { 'version': plat.version, 'note': debugstr, 'free': var.fre()}
        console.clear()
        console.write_line(greeting.format(**params))
        console.show_keys(True)
Esempio n. 12
0
def input_console(prompt, readvar, newline):
    """ Read a list of variables for INPUT. """
    # readvar is a list of (name, indices) tuples
    # we return a list of (name, indices, values) tuples
    while True:
        console.write(prompt)
        line = console.wait_screenline(write_endl=newline)
        inputstream = InputTextFile(line)
        # read the values and group them and the separators
        values, seps = zip(*[inputstream.read_var(v) for v in readvar])
        # last separator not empty: there were too many values or commas
        # if there are Nones: there were too few or empty values
        if (seps[-1] or None in values):
            # good old Redo!
            console.write_line('?Redo from start')
        else:
            return [r + [v] for r, v in zip(readvar, values)]
Esempio n. 13
0
def input_console(prompt, readvar, newline):
    """ Read a list of variables for INPUT. """
    # readvar is a list of (name, indices) tuples
    # we return a list of (name, indices, values) tuples
    while True:
        console.write(prompt)
        line = console.wait_screenline(write_endl=newline)
        inputstream = InputTextFile(line)
        # read the values and group them and the separators
        values, seps = zip(*[inputstream.read_var(v) for v in readvar])
        # last separator not empty: there were too many values or commas
        # if there are Nones: there were too few or empty values
        if (seps[-1] or None in values):
            # good old Redo!
            console.write_line('?Redo from start')
        else:
            return [ r + [v] for r, v in zip(readvar, values) ]
Esempio n. 14
0
def input_console(prompt, readvar, newline):
    """ Read a list of variables for INPUT. """
    # readvar is a list of (name, indices) tuples
    # we return a list of (name, indices, values) tuples
    while True:
        console.write(prompt)
        line = console.wait_screenline(write_endl=newline)
        inputstream = InputTextFile(line)
        # read the values and group them and the separators
        values, seps = zip(*[inputstream.read_var(v) for v in readvar])
        # last separator not empty: there were too many values or commas
        # earlier separators empty: there were too few values
        # empty values will be converted to zero by str_to_value_keep
        # Nene means a conversion error occurred
        if (seps[-1] or '' in seps[:-1] or None in values):
            # good old Redo!
            console.write_line('?Redo from start')
        else:
            return [r + [v] for r, v in zip(readvar, values)]
Esempio n. 15
0
def input_console(prompt, readvar, newline):
    """ Read a list of variables for INPUT. """
    # readvar is a list of (name, indices) tuples
    # we return a list of (name, indices, values) tuples
    while True:
        console.write(prompt)
        line = console.wait_screenline(write_endl=newline)
        inputstream = InputTextFile(line)
        # read the values and group them and the separators
        values, seps = zip(*[inputstream.read_var(v) for v in readvar])
        # last separator not empty: there were too many values or commas
        # earlier separators empty: there were too few values
        # empty values will be converted to zero by string_to_number
        # None means a conversion error occurred
        if (seps[-1] or '' in seps[:-1] or None in values):
            # good old Redo!
            console.write_line('?Redo from start')
        else:
            return [r + [v] for r, v in zip(readvar, values)]
Esempio n. 16
0
 def _search(self, trunk_req=None, filetypes_req=None):
     """ Play until a file header record is found for the given filename. """
     try:
         while True:
             trunk, filetype, seg, offset, length = self.tapestream.open_read()
             if ((not trunk_req or trunk.rstrip() == trunk_req.rstrip()) and
                     (not filetypes_req or filetype in filetypes_req)):
                 message = "%s Found." % (trunk + '.' + filetype)
                 if not state.basic_state.run_mode:
                     console.write_line(message)
                 logging.debug(timestamp(self.tapestream.counter()) + message)
                 return trunk, filetype, seg, offset, length
             else:
                 message = "%s Skipped." % (trunk + '.' + filetype)
                 if not state.basic_state.run_mode:
                     console.write_line(message)
                 logging.debug(timestamp(self.tapestream.counter()) + message)
     except EndOfTape:
         # reached end-of-tape without finding appropriate file
         raise error.RunError(error.DEVICE_TIMEOUT)
Esempio n. 17
0
def _handle_math_error(e):
    """ Handle Overflow or Division by Zero. """
    if isinstance(e, ValueError):
        # math domain errors such as SQR(-1)
        raise error.RunError(error.IFC)
    elif isinstance(e, OverflowError):
        math_error = error.OVERFLOW
    elif isinstance(e, ZeroDivisionError):
        math_error = error.DIVISION_BY_ZERO
    else:
        raise e
    if state.basic_state.on_error:
        # also raises exception in error_handle_mode!
        # in that case, prints a normal error message
        raise error.RunError(math_error)
    else:
        # write a message & continue as normal
        console.write_line(error.RunError(math_error).message)
    # return max value for the appropriate float type
    if e.args and e.args[0] and isinstance(e.args[0], fp.Float):
        return fp.pack(e.args[0])
    return fp.pack(fp.Single.max.copy())
Esempio n. 18
0
def _handle_math_error(e):
    """ Handle Overflow or Division by Zero. """
    if isinstance(e, ValueError):
        # math domain errors such as SQR(-1)
        raise error.RunError(error.IFC)
    elif isinstance(e, OverflowError):
        math_error = error.OVERFLOW
    elif isinstance(e, ZeroDivisionError):
        math_error = error.DIVISION_BY_ZERO
    else:
        raise e
    if state.basic_state.on_error:
        # also raises exception in error_handle_mode!
        # in that case, prints a normal error message
        raise error.RunError(math_error)
    else:
        # write a message & continue as normal
        console.write_line(error.RunError(math_error).message)
    # return max value for the appropriate float type
    if e.args and e.args[0] and isinstance(e.args[0], fp.Float):
        return fp.pack(e.args[0])
    return fp.pack(fp.Single.max.copy())
Esempio n. 19
0
 def write(self, s):
     """ Write string s to SCRN: """
     # writes to SCRN files should *not* be echoed
     do_echo = self.is_master
     self._col = state.console_state.col
     # take column 80+overflow into account
     if state.console_state.overflow:
         self._col += 1
     # only break lines at the start of a new string. width 255 means unlimited width
     s_width = 0
     newline = False
     # find width of first line in s
     for c in str(s):
         if c in ('\r', '\n'):
             newline = True
             break
         if c == '\b':
             # for lpt1 and files, nonprinting chars are not counted in LPOS; but chr$(8) will take a byte out of the buffer
             s_width -= 1
         elif ord(c) >= 32:
             # nonprinting characters including tabs are not counted for WIDTH
             s_width += 1
     if (self.width != 255 and state.console_state.row !=
             state.console_state.screen.mode.height and self.col != 1
             and self.col - 1 + s_width > self.width and not newline):
         console.write_line(do_echo=do_echo)
         self._col = 1
     cwidth = state.console_state.screen.mode.width
     for c in str(s):
         if self.width <= cwidth and self.col > self.width:
             console.write_line(do_echo=do_echo)
             self._col = 1
         if self.col <= cwidth or self.width <= cwidth:
             console.write(c, do_echo=do_echo)
         if c in ('\n', '\r'):
             self._col = 1
         else:
             self._col += 1
Esempio n. 20
0
 def write(self, s):
     """ Write string s to SCRN: """
     # writes to SCRN files should *not* be echoed
     do_echo = self.is_master
     self._col = state.console_state.col
     # take column 80+overflow into account
     if state.console_state.overflow:
         self._col += 1
     # only break lines at the start of a new string. width 255 means unlimited width
     s_width = 0
     newline = False
     # find width of first line in s
     for c in str(s):
         if c in ('\r', '\n'):
             newline = True
             break
         if c == '\b':
             # for lpt1 and files, nonprinting chars are not counted in LPOS; but chr$(8) will take a byte out of the buffer
             s_width -= 1
         elif ord(c) >= 32:
             # nonprinting characters including tabs are not counted for WIDTH
             s_width += 1
     if (self.width != 255 and state.console_state.row != state.console_state.screen.mode.height
             and self.col != 1 and self.col-1 + s_width > self.width and not newline):
         console.write_line(do_echo=do_echo)
         self._col = 1
     cwidth = state.console_state.screen.mode.width
     for c in str(s):
         if self.width <= cwidth and self.col > self.width:
             console.write_line(do_echo=do_echo)
             self._col = 1
         if self.col <= cwidth or self.width <= cwidth:
             console.write(c, do_echo=do_echo)
         if c in ('\n', '\r'):
             self._col = 1
         else:
             self._col += 1
Esempio n. 21
0
    def files(self, pathmask):
        """ Write directory listing to console. """
        # forward slashes - file not found
        # GW-BASIC sometimes allows leading or trailing slashes
        # and then does weird things I don't understand.
        if b'/' in bytes(pathmask):
            raise error.RunError(error.FILE_NOT_FOUND)
        if not self.path:
            # undefined disk drive: file not found
            raise error.RunError(error.FILE_NOT_FOUND)
        drivepath, relpath, mask = self._native_path_elements(
            pathmask, path_err=error.FILE_NOT_FOUND)
        path = os.path.join(drivepath, relpath)

        mask = mask.upper() or b'*.*'
        # output working dir in DOS format
        # NOTE: this is always the current dir, not the one being listed
        dir_elems = [
            join_dosname(*short_name(path, e)) for e in self.cwd.split(os.sep)
        ]
        console.write_line(self.letter + b':\\' + b'\\'.join(dir_elems))
        fils = []
        if mask == b'.':
            dirs = [split_dosname((os.sep + relpath).split(os.sep)[-1:][0])]
        elif mask == b'..':
            dirs = [split_dosname((os.sep + relpath).split(os.sep)[-2:][0])]
        else:
            all_names = safe(os.listdir, path)
            dirs = [
                filename_from_unicode(n) for n in all_names
                if os.path.isdir(os.path.join(path, n))
            ]
            fils = [
                filename_from_unicode(n) for n in all_names
                if not os.path.isdir(os.path.join(path, n))
            ]
            # filter according to mask
            dirs = filter_names(path, dirs + [b'.', b'..'], mask)
            fils = filter_names(path, fils, mask)
        if not dirs and not fils:
            raise error.RunError(error.FILE_NOT_FOUND)
        # format and print contents
        output = ([(b'%-8s.%-3s' % (t, e) if
                    (e or not t) else b'%-8s    ' % t) + b'<DIR>'
                   for t, e in dirs] +
                  [(b'%-8s.%-3s' % (t, e) if e else b'%-8s    ' % t) + b'     '
                   for t, e in fils])
        num = state.console_state.screen.mode.width // 20
        while len(output) > 0:
            line = b' '.join(output[:num])
            output = output[num:]
            console.write_line(line)
            # allow to break during dir listing & show names flowing on screen
            backend.check_events()
        console.write_line(b' %d Bytes free' % self.get_free())
Esempio n. 22
0
    def files(self, pathmask):
        """ Write directory listing to console. """
        # forward slashes - file not found
        # GW-BASIC sometimes allows leading or trailing slashes
        # and then does weird things I don't understand.
        if b'/' in bytes(pathmask):
            raise error.RunError(error.FILE_NOT_FOUND)
        if not self.path:
            # undefined disk drive: file not found
            raise error.RunError(error.FILE_NOT_FOUND)
        drivepath, relpath, mask = self._native_path_elements(pathmask, path_err=error.FILE_NOT_FOUND)
        path = os.path.join(drivepath, relpath)

        mask = mask.upper() or b'*.*'
        # output working dir in DOS format
        # NOTE: this is always the current dir, not the one being listed
        dir_elems = [join_dosname(*short_name(path, e)) for e in self.cwd.split(os.sep)]
        console.write_line(self.letter + b':\\' + b'\\'.join(dir_elems))
        fils = []
        if mask == b'.':
            dirs = [split_dosname((os.sep+relpath).split(os.sep)[-1:][0])]
        elif mask == b'..':
            dirs = [split_dosname((os.sep+relpath).split(os.sep)[-2:][0])]
        else:
            all_names = safe(os.listdir, path)
            dirs = [filename_from_unicode(n) for n in all_names if os.path.isdir(os.path.join(path, n))]
            fils = [filename_from_unicode(n) for n in all_names if not os.path.isdir(os.path.join(path, n))]
            # filter according to mask
            dirs = filter_names(path, dirs + [b'.', b'..'], mask)
            fils = filter_names(path, fils, mask)
        if not dirs and not fils:
            raise error.RunError(error.FILE_NOT_FOUND)
        # format and print contents
        output = (
              [(b'%-8s.%-3s' % (t, e) if (e or not t) else b'%-8s    ' % t) + b'<DIR>' for t, e in dirs]
            + [(b'%-8s.%-3s' % (t, e) if e else b'%-8s    ' % t) + b'     ' for t, e in fils])
        num = state.console_state.screen.mode.width // 20
        while len(output) > 0:
            line = b' '.join(output[:num])
            output = output[num:]
            console.write_line(line)
            # allow to break during dir listing & show names flowing on screen
            backend.check_events()
        console.write_line(b' %d Bytes free' % self.get_free())
Esempio n. 23
0
def files(pathmask):
    """ Write directory listing to console. """
    # forward slashes - file not found
    # GW-BASIC sometimes allows leading or trailing slashes
    # and then does weird things I don't understand. 
    if '/' in str(pathmask):
        raise error.RunError(53)   
    drive, drivepath, relpath, mask = native_path_elements(pathmask, err=53)
    path = os.path.join(drivepath, relpath)
    mask = mask.upper() or '*.*'
    # output working dir in DOS format
    # NOTE: this is always the current dir, not the one being listed
    dir_elems = [join_dosname(*short_name(path, e)) 
                 for e in state.io_state.drive_cwd[drive].split(os.sep)]
    console.write_line(drive + ':\\' + '\\'.join(dir_elems))
    fils = ''
    if mask == '.':
        dirs = [split_dosname(dossify((os.sep+relpath).split(os.sep)[-1:][0]))]
    elif mask == '..':
        dirs = [split_dosname(dossify((os.sep+relpath).split(os.sep)[-2:][0]))]
    else:        
        all_names = safe(os.listdir, path)
        dirs = [n for n in all_names if os.path.isdir(os.path.join(path, n))]
        fils = [n for n in all_names if not os.path.isdir(os.path.join(path, n))]
        # filter according to mask
        dirs = filter_names(path, dirs + ['.', '..'], mask)
        fils = filter_names(path, fils, mask)
    if not dirs and not fils:
        raise error.RunError(53)
    # format and print contents
    output = ( 
          [('%-8s.%-3s' % (t, e) if (e or not t) else '%-8s    ' % t) + '<DIR>' for t, e in dirs]
        + [('%-8s.%-3s' % (t, e) if e else '%-8s    ' % t) + '     ' for t, e in fils])
    num = state.console_state.screen.mode.width // 20
    while len(output) > 0:
        line = ' '.join(output[:num])
        output = output[num:]
        console.write_line(line)       
        # allow to break during dir listing & show names flowing on screen
        backend.check_events()             
    console.write_line(' %d Bytes free' % disk_free(path))
Esempio n. 24
0
def renum(new_line, start_line, step):
    """ Renumber stored program. """
    new_line = 10 if new_line is None else new_line
    start_line = 0 if start_line is None else start_line
    step = 10 if step is None else step
    # get a sorted list of line numbers
    keys = sorted(
        [k for k in state.basic_state.line_numbers.keys() if k >= start_line])
    # assign the new numbers
    old_to_new = {}
    for old_line in keys:
        if old_line < 65535 and new_line > 65529:
            raise error.RunError(error.IFC)
        if old_line == 65536:
            break
        old_to_new[old_line] = new_line
        state.basic_state.last_stored = new_line
        new_line += step
    # write the new numbers
    for old_line in old_to_new:
        state.basic_state.bytecode.seek(
            state.basic_state.line_numbers[old_line])
        # skip the \x00\xC0\xDE & overwrite line number
        state.basic_state.bytecode.read(3)
        state.basic_state.bytecode.write(
            str(vartypes.value_to_uint(old_to_new[old_line])))
    # rebuild the line number dictionary
    new_lines = {}
    for old_line in old_to_new:
        new_lines[
            old_to_new[old_line]] = state.basic_state.line_numbers[old_line]
        del state.basic_state.line_numbers[old_line]
    state.basic_state.line_numbers.update(new_lines)
    # write the indirect line numbers
    state.basic_state.bytecode.seek(0)
    while util.skip_to_read(state.basic_state.bytecode, ('\x0e', )) == '\x0e':
        # get the old g number
        jumpnum = vartypes.uint_to_value(
            bytearray(state.basic_state.bytecode.read(2)))
        try:
            newjump = old_to_new[jumpnum]
        except KeyError:
            # not redefined, exists in program?
            if jumpnum in state.basic_state.line_numbers:
                newjump = jumpnum
            else:
                linum = get_line_number(state.basic_state.bytecode.tell())
                console.write_line('Undefined line ' + str(jumpnum) + ' in ' +
                                   str(linum))
        state.basic_state.bytecode.seek(-2, 1)
        state.basic_state.bytecode.write(str(vartypes.value_to_uint(newjump)))
    # stop running if we were
    flow.set_pointer(False)
    # reset loop stacks
    state.basic_state.gosub_return = []
    state.basic_state.for_next_stack = []
    state.basic_state.while_wend_stack = []
    # renumber error handler
    if state.basic_state.on_error:
        state.basic_state.on_error = old_to_new[state.basic_state.on_error]
    # renumber event traps
    for handler in state.basic_state.events.all:
        if handler.gosub:
            handler.set_jump(old_to_new[handler.gosub])
Esempio n. 25
0
def bluescreen(e):
    """ Display a modal exception message. """
    state.console_state.screen.screen(0, 0, 0, 0, new_width=80)
    console.clear()
    console.init_mode()
    exc_type, exc_value, exc_traceback = sys.exc_info()
    # log the standard python error
    logging.error(''.join(traceback.format_exception(exc_type, exc_value, exc_traceback)))
    # format the error more readably on the screen
    state.console_state.screen.set_border(4)
    state.console_state.screen.set_attr(0x70)
    console.write_line('EXCEPTION')
    state.console_state.screen.set_attr(15)
    if state.basic_state.run_mode:
        state.basic_state.bytecode.seek(-1, 1)
        program.edit(program.get_line_number(state.basic_state.bytecode.tell()),
                                         state.basic_state.bytecode.tell())
        console.write_line('\n')
    else:
        state.basic_state.direct_line.seek(0)
        console.write_line(str(tokenise.detokenise_compound_statement(state.basic_state.direct_line)[0])+'\n')
    stack = traceback.extract_tb(exc_traceback)
    for s in stack[-4:]:
        stack_line = '{0}:{1}, {2}'.format(
            os.path.split(s[0])[-1], s[1], s[2])
        stack_line_2 = '    {0}'.format(s[3])
        state.console_state.screen.set_attr(15)
        console.write_line(stack_line)
        state.console_state.screen.set_attr(7)
        console.write_line(stack_line_2)
    exc_message = traceback.format_exception_only(exc_type, exc_value)[0]
    state.console_state.screen.set_attr(15)
    console.write('{0}:'.format(exc_type.__name__))
    state.console_state.screen.set_attr(7)
    console.write_line(' {0}'.format(str(exc_value)))
    state.console_state.screen.set_attr(0x70)
    console.write_line(
        '\nThis is a bug in PC-BASIC.')
    state.console_state.screen.set_attr(7)
    console.write(
        'Sorry about that. Please send the above messages to the bugs forum\nby e-mail to ')
    state.console_state.screen.set_attr(15)
    console.write(
        '*****@*****.**')
    state.console_state.screen.set_attr(7)
    console.write(
        ' or by filing a bug\nreport at ')
    state.console_state.screen.set_attr(15)
    console.write(
        'https://github.com/robhagemans/pcbasic/issues')
    state.console_state.screen.set_attr(7)
    console.write_line(
        '. Please include')
    console.write_line('as much information as you can about what you were doing and how this happened.')
    console.write_line('Thank you!')
    state.console_state.screen.set_attr(7)
    flow.set_pointer(False)
Esempio n. 26
0
def renum(new_line, start_line, step):
    """ Renumber stored program. """
    new_line = 10 if new_line is None else new_line
    start_line = 0 if start_line is None else start_line
    step = 10 if step is None else step
    # get a sorted list of line numbers
    keys = sorted([ k for k in state.basic_state.line_numbers.keys() if k >= start_line])
    # assign the new numbers
    old_to_new = {}
    for old_line in keys:
        if old_line < 65535 and new_line > 65529:
            raise error.RunError(error.IFC)
        if old_line == 65536:
            break
        old_to_new[old_line] = new_line
        state.basic_state.last_stored = new_line
        new_line += step
    # write the new numbers
    for old_line in old_to_new:
        state.basic_state.bytecode.seek(state.basic_state.line_numbers[old_line])
        # skip the \x00\xC0\xDE & overwrite line number
        state.basic_state.bytecode.read(3)
        state.basic_state.bytecode.write(str(vartypes.integer_to_bytes(vartypes.int_to_integer_unsigned(old_to_new[old_line]))))
    # write the indirect line numbers
    ins = state.basic_state.bytecode
    ins.seek(0)
    while util.skip_to_read(ins, (tk.T_UINT,)) == tk.T_UINT:
        # get the old g number
        jumpnum = vartypes.integer_to_int_unsigned(vartypes.bytes_to_integer(ins.read(2)))
        # handle exception for ERROR GOTO
        if jumpnum == 0:
            pos = ins.tell()
            # skip line number token
            ins.seek(-3, 1)
            if util.backskip_white(ins) == tk.GOTO and util.backskip_white(ins) == tk.ERROR:
                ins.seek(pos)
                continue
            ins.seek(pos)
        try:
            newjump = old_to_new[jumpnum]
        except KeyError:
            # not redefined, exists in program?
            if jumpnum not in state.basic_state.line_numbers:
                linum = get_line_number(ins.tell()-1)
                console.write_line('Undefined line ' + str(jumpnum) + ' in ' + str(linum))
            newjump = jumpnum
        ins.seek(-2, 1)
        ins.write(str(vartypes.integer_to_bytes(vartypes.int_to_integer_unsigned(newjump))))
    # rebuild the line number dictionary
    new_lines = {}
    for old_line in old_to_new:
        new_lines[old_to_new[old_line]] = state.basic_state.line_numbers[old_line]
        del state.basic_state.line_numbers[old_line]
    state.basic_state.line_numbers.update(new_lines)
    # stop running if we were
    flow.set_pointer(False)
    # reset loop stacks
    state.basic_state.gosub_return = []
    state.basic_state.for_next_stack = []
    state.basic_state.while_wend_stack = []
    # renumber error handler
    if state.basic_state.on_error:
        state.basic_state.on_error = old_to_new[state.basic_state.on_error]
    # renumber event traps
    for handler in state.basic_state.events.all:
        if handler.gosub:
            handler.set_jump(old_to_new[handler.gosub])
Esempio n. 27
0
def renum(new_line, start_line, step):
    """ Renumber stored program. """
    new_line = 10 if new_line is None else new_line
    start_line = 0 if start_line is None else start_line
    step = 10 if step is None else step
    # get a sorted list of line numbers
    keys = sorted(
        [k for k in state.basic_state.line_numbers.keys() if k >= start_line])
    # assign the new numbers
    old_to_new = {}
    for old_line in keys:
        if old_line < 65535 and new_line > 65529:
            raise error.RunError(error.IFC)
        if old_line == 65536:
            break
        old_to_new[old_line] = new_line
        state.basic_state.last_stored = new_line
        new_line += step
    # write the new numbers
    for old_line in old_to_new:
        state.basic_state.bytecode.seek(
            state.basic_state.line_numbers[old_line])
        # skip the \x00\xC0\xDE & overwrite line number
        state.basic_state.bytecode.read(3)
        state.basic_state.bytecode.write(
            str(
                vartypes.integer_to_bytes(
                    vartypes.int_to_integer_unsigned(old_to_new[old_line]))))
    # write the indirect line numbers
    ins = state.basic_state.bytecode
    ins.seek(0)
    while util.skip_to_read(ins, (tk.T_UINT, )) == tk.T_UINT:
        # get the old g number
        jumpnum = vartypes.integer_to_int_unsigned(
            vartypes.bytes_to_integer(ins.read(2)))
        # handle exception for ERROR GOTO
        if jumpnum == 0:
            pos = ins.tell()
            # skip line number token
            ins.seek(-3, 1)
            if util.backskip_white(ins) == tk.GOTO and util.backskip_white(
                    ins) == tk.ERROR:
                ins.seek(pos)
                continue
            ins.seek(pos)
        try:
            newjump = old_to_new[jumpnum]
        except KeyError:
            # not redefined, exists in program?
            if jumpnum not in state.basic_state.line_numbers:
                linum = get_line_number(ins.tell() - 1)
                console.write_line('Undefined line ' + str(jumpnum) + ' in ' +
                                   str(linum))
            newjump = jumpnum
        ins.seek(-2, 1)
        ins.write(
            str(
                vartypes.integer_to_bytes(
                    vartypes.int_to_integer_unsigned(newjump))))
    # rebuild the line number dictionary
    new_lines = {}
    for old_line in old_to_new:
        new_lines[
            old_to_new[old_line]] = state.basic_state.line_numbers[old_line]
        del state.basic_state.line_numbers[old_line]
    state.basic_state.line_numbers.update(new_lines)
    # stop running if we were
    flow.set_pointer(False)
    # reset loop stacks
    state.basic_state.gosub_return = []
    state.basic_state.for_next_stack = []
    state.basic_state.while_wend_stack = []
    # renumber error handler
    if state.basic_state.on_error:
        state.basic_state.on_error = old_to_new[state.basic_state.on_error]
    # renumber event traps
    for handler in state.basic_state.events.all:
        if handler.gosub:
            handler.set_jump(old_to_new[handler.gosub])
Esempio n. 28
0
def bluescreen(e):
    """ Display a modal exception message. """
    state.console_state.screen.screen(0, 0, 0, 0, new_width=80)
    console.clear()
    console.init_mode()
    exc_type, exc_value, exc_traceback = sys.exc_info()
    # log the standard python error
    logging.error(''.join(traceback.format_exception(exc_type, exc_value, exc_traceback)))
    # format the error more readably on the screen
    state.console_state.screen.set_border(4)
    state.console_state.screen.set_attr(0x70)
    console.write_line('EXCEPTION')
    state.console_state.screen.set_attr(15)
    if state.basic_state.run_mode:
        state.basic_state.bytecode.seek(-1, 1)
        program.edit(program.get_line_number(state.basic_state.bytecode.tell()),
                                         state.basic_state.bytecode.tell())
        console.write_line('\n')
    else:
        state.basic_state.direct_line.seek(0)
        console.write_line(str(tokenise.detokenise_compound_statement(state.basic_state.direct_line)[0])+'\n')
    stack = traceback.extract_tb(exc_traceback)
    for s in stack[-4:]:
        stack_line = '{0}:{1}, {2}'.format(
            os.path.split(s[0])[-1], s[1], s[2])
        stack_line_2 = '    {0}'.format(s[3])
        state.console_state.screen.set_attr(15)
        console.write_line(stack_line)
        state.console_state.screen.set_attr(7)
        console.write_line(stack_line_2)
    exc_message = traceback.format_exception_only(exc_type, exc_value)[0]
    state.console_state.screen.set_attr(15)
    console.write('{0}:'.format(exc_type.__name__))
    state.console_state.screen.set_attr(7)
    console.write_line(' {0}'.format(str(exc_value)))
    state.console_state.screen.set_attr(0x70)
    console.write_line(
        '\nThis is a bug in PC-BASIC.')
    state.console_state.screen.set_attr(7)
    console.write(
        'Sorry about that. Please send the above messages to the bugs forum\nby e-mail to ')
    state.console_state.screen.set_attr(15)
    console.write(
        '*****@*****.**')
    state.console_state.screen.set_attr(7)
    console.write(
        ' or by filing a bug\nreport at ')
    state.console_state.screen.set_attr(15)
    console.write(
        'https://github.com/robhagemans/pcbasic/issues')
    state.console_state.screen.set_attr(7)
    console.write_line(
        '. Please include')
    console.write_line('as much information as you can about what you were doing and how this happened.')
    console.write_line('Thank you!')
    state.console_state.screen.set_attr(7)
    flow.set_pointer(False)
Esempio n. 29
0
 def write_line(self, inp=''):
     """ Write a string to the screen and follow by CR. """
     self.write(inp)
     console.write_line(do_echo=self.is_master)
Esempio n. 30
0
 def write_line(self, inp=''):
     """ Write a string to the screen and follow by CR. """
     self.write(inp)
     console.write_line(do_echo=self.is_master)
Esempio n. 31
0
 def write_line(self, inp=''):
     """ Write a string to the screen and follow by CR. """
     self.write(inp)
     console.write_line(do_echo=(self.number==0))