Ejemplo n.º 1
0
def run_once():
    """ Read-eval-print loop: run once. """
    try:
        while True:
            state.basic_state.last_mode = state.basic_state.execute_mode, state.basic_state.auto_mode
            if state.basic_state.execute_mode:
                try:
                    # may raise Break
                    backend.check_events()
                    handle_basic_events()
                    if not statements.parse_statement():
                        state.basic_state.execute_mode = False
                except error.Break as e:
                    handle_break(e)
            elif state.basic_state.auto_mode:
                try:
                    # auto step, checks events
                    auto_step()
                except error.Break:
                    state.basic_state.auto_mode = False    
            else:    
                show_prompt()
                try:
                    # input loop, checks events
                    line = console.wait_screenline(from_start=True, alt_replace=True) 
                    state.basic_state.prompt = not store_line(line)
                except error.Break:
                    state.basic_state.prompt = False
                    continue
            # change loop modes
            if switch_mode():
                break
    except error.RunError as e:
        handle_error(e) 
        state.basic_state.prompt = True
Ejemplo n.º 2
0
 def paint(self, lcoord, pattern, c, border, background):
     """ Fill an area defined by a border attribute with a tiled pattern. """
     # 4-way scanline flood fill: http://en.wikipedia.org/wiki/Flood_fill
     # flood fill stops on border colour in all directions; it also stops on scanlines in fill_colour
     # pattern tiling stops at intervals that equal the pattern to be drawn, unless this pattern is
     # also equal to the background pattern.
     c, border = self.get_attr_index(c), self.get_attr_index(border)
     solid = pattern == None
     if not solid:
         tile = self.screen.mode.build_tile(pattern) if pattern else None
         back = self.screen.mode.build_tile(background) if background else None
     else:
         tile, back = [[c] * 8], None
     bound_x0, bound_y0, bound_x1, bound_y1 = self.get_view()
     x, y = self.view_coords(*self.get_window_physical(*lcoord))
     line_seed = [(x, x, y, 0)]
     # paint nothing if seed is out of bounds
     if x < bound_x0 or x > bound_x1 or y < bound_y0 or y > bound_y1:
         return
     self.last_point = x, y
     # paint nothing if we start on border attrib
     if self.screen.get_pixel(x, y) == border:
         return
     while len(line_seed) > 0:
         # consider next interval
         x_start, x_stop, y, ydir = line_seed.pop()
         # extend interval as far as it goes to left and right
         x_left = x_start - len(self.screen.get_until(x_start - 1, bound_x0 - 1, y, border))
         x_right = x_stop + len(self.screen.get_until(x_stop + 1, bound_x1 + 1, y, border))
         # check next scanlines and add intervals to the list
         if ydir == 0:
             if y + 1 <= bound_y1:
                 line_seed = self.check_scanline(line_seed, x_left, x_right, y + 1, c, tile, back, border, 1)
             if y - 1 >= bound_y0:
                 line_seed = self.check_scanline(line_seed, x_left, x_right, y - 1, c, tile, back, border, -1)
         else:
             # check the same interval one scanline onward in the same direction
             if y + ydir <= bound_y1 and y + ydir >= bound_y0:
                 line_seed = self.check_scanline(line_seed, x_left, x_right, y + ydir, c, tile, back, border, ydir)
             # check any bit of the interval that was extended one scanline backward
             # this is where the flood fill goes around corners.
             if y - ydir <= bound_y1 and y - ydir >= bound_y0:
                 line_seed = self.check_scanline(
                     line_seed, x_left, x_start - 1, y - ydir, c, tile, back, border, -ydir
                 )
                 line_seed = self.check_scanline(
                     line_seed, x_stop + 1, x_right, y - ydir, c, tile, back, border, -ydir
                 )
         # draw the pixels for the current interval
         if solid:
             self.screen.fill_interval(x_left, x_right, y, tile[0][0])
         else:
             interval = tile_to_interval(x_left, x_right, y, tile)
             self.screen.put_interval(self.screen.apagenum, x_left, y, interval)
         # show progress
         if y % 4 == 0:
             backend.check_events()
     self.last_attr = c
Ejemplo n.º 3
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())
Ejemplo n.º 4
0
def run_once():
    """ Read-eval-print loop: run once. """
    try:
        while True:
            state.basic_state.last_mode = state.basic_state.execute_mode, state.basic_state.auto_mode
            if state.basic_state.execute_mode:
                try:
                    # may raise Break
                    backend.check_events()
                    handle_basic_events()
                    # returns True if more statements to parse
                    if not statements.parse_statement():
                        state.basic_state.execute_mode = False
                except error.RunError as e:
                    trap_error(e)
                except error.Break as e:
                    # ctrl-break stops foreground and background sound
                    state.console_state.sound.stop_all_sound()
                    handle_break(e)
            elif state.basic_state.auto_mode:
                try:
                    # auto step, checks events
                    auto_step()
                except error.Break:
                    # ctrl+break, ctrl-c both stop background sound
                    state.console_state.sound.stop_all_sound()
                    state.basic_state.auto_mode = False
            else:
                show_prompt()
                try:
                    # input loop, checks events
                    line = console.wait_screenline(from_start=True)
                    state.basic_state.prompt = not store_line(line)
                except error.Break:
                    state.console_state.sound.stop_all_sound()
                    state.basic_state.prompt = False
                    continue
            # change loop modes
            if switch_mode():
                break
    except error.RunError as e:
        handle_error(e)
        state.basic_state.prompt = True
    except error.Exit:
        raise
    except Exception as e:
        if debug.debug_mode:
            raise
        bluescreen(e)
Ejemplo n.º 5
0
def list_line(line, newline=True):
    """ Print a line from a program listing or EDIT prompt. """
    # no wrap if 80-column line, clear row before printing.
    # flow of listing is visible on screen
    backend.check_events()
    cuts = line.split('\n')
    for i, l in enumerate(cuts):
        # clear_line looks back along wraps, use clear_rest_of_line instead
        clear_rest_of_line(state.console_state.row, 1)
        write(str(l))
        if i != len(cuts)-1:
            write('\n')
    if newline:
        write_line()
    # remove wrap after 80-column program line
    if len(line) == state.console_state.screen.mode.width and state.console_state.row > 2:
        state.console_state.screen.apage.row[state.console_state.row-3].wrap = False
Ejemplo n.º 6
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())
Ejemplo n.º 7
0
def list_line(line, newline=True):
    """ Print a line from a program listing or EDIT prompt. """
    # no wrap if 80-column line, clear row before printing.
    # flow of listing is visible on screen
    backend.check_events()
    cuts = line.split('\n')
    for i, l in enumerate(cuts):
        # clear_line looks back along wraps, use clear_rest_of_line instead
        clear_rest_of_line(state.console_state.row, 1)
        write(str(l))
        if i != len(cuts) - 1:
            write('\n')
    if newline:
        write_line()
    # remove wrap after 80-column program line
    if len(
            line
    ) == state.console_state.screen.mode.width and state.console_state.row > 2:
        state.console_state.screen.apage.row[state.console_state.row -
                                             3].wrap = False
Ejemplo n.º 8
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))
Ejemplo n.º 9
0
 def paint(self, lcoord, pattern, c, border, background):
     """ Fill an area defined by a border attribute with a tiled pattern. """
     # 4-way scanline flood fill: http://en.wikipedia.org/wiki/Flood_fill
     # flood fill stops on border colour in all directions; it also stops on scanlines in fill_colour
     # pattern tiling stops at intervals that equal the pattern to be drawn, unless this pattern is
     # also equal to the background pattern.
     c, border = self.get_attr_index(c), self.get_attr_index(border)
     solid = (pattern is None)
     if not solid:
         tile = self.screen.mode.build_tile(pattern) if pattern else None
         back = self.screen.mode.build_tile(
             background) if background else None
     else:
         tile, back = [[c] * 8], None
     bound_x0, bound_y0, bound_x1, bound_y1 = self.get_view()
     x, y = self.view_coords(*self.get_window_physical(*lcoord))
     line_seed = [(x, x, y, 0)]
     # paint nothing if seed is out of bounds
     if x < bound_x0 or x > bound_x1 or y < bound_y0 or y > bound_y1:
         return
     self.last_point = x, y
     # paint nothing if we start on border attrib
     if self.screen.get_pixel(x, y) == border:
         return
     while len(line_seed) > 0:
         # consider next interval
         x_start, x_stop, y, ydir = line_seed.pop()
         # extend interval as far as it goes to left and right
         x_left = x_start - len(
             self.screen.get_until(x_start - 1, bound_x0 - 1, y, border))
         x_right = x_stop + len(
             self.screen.get_until(x_stop + 1, bound_x1 + 1, y, border))
         # check next scanlines and add intervals to the list
         if ydir == 0:
             if y + 1 <= bound_y1:
                 line_seed = self.check_scanline(line_seed, x_left, x_right,
                                                 y + 1, c, tile, back,
                                                 border, 1)
             if y - 1 >= bound_y0:
                 line_seed = self.check_scanline(line_seed, x_left, x_right,
                                                 y - 1, c, tile, back,
                                                 border, -1)
         else:
             # check the same interval one scanline onward in the same direction
             if y + ydir <= bound_y1 and y + ydir >= bound_y0:
                 line_seed = self.check_scanline(line_seed, x_left, x_right,
                                                 y + ydir, c, tile, back,
                                                 border, ydir)
             # check any bit of the interval that was extended one scanline backward
             # this is where the flood fill goes around corners.
             if y - ydir <= bound_y1 and y - ydir >= bound_y0:
                 line_seed = self.check_scanline(line_seed, x_left,
                                                 x_start - 1, y - ydir, c,
                                                 tile, back, border, -ydir)
                 line_seed = self.check_scanline(line_seed, x_stop + 1,
                                                 x_right, y - ydir, c, tile,
                                                 back, border, -ydir)
         # draw the pixels for the current interval
         if solid:
             self.screen.fill_interval(x_left, x_right, y, tile[0][0])
         else:
             interval = tile_to_interval(x_left, x_right, y, tile)
             self.screen.put_interval(self.screen.apagenum, x_left, y,
                                      interval)
         # show progress
         if y % 4 == 0:
             backend.check_events()
     self.last_attr = c