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])
def switch_mode(self): """ Switch loop mode. """ last_execute, last_auto = self.last_mode if state.basic_state.parse_mode != last_execute: # move pointer to the start of direct line (for both on and off!) flow.set_pointer(False, 0) state.console_state.screen.cursor.reset_visibility() return ((not state.basic_state.auto_mode) and (not state.basic_state.parse_mode) and last_execute)
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)
def switch_mode(): """ Switch loop mode. """ last_execute, last_auto = state.basic_state.last_mode if state.basic_state.execute_mode != last_execute: # move pointer to the start of direct line (for both on and off!) flow.set_pointer(False, 0) state.console_state.screen.cursor.reset_visibility() return ((not state.basic_state.auto_mode) and (not state.basic_state.execute_mode) and last_execute)
def list_lines(from_line, to_line): """ List line range. """ if state.basic_state.protected: # don't list protected files raise error.RunError(error.IFC) # 65529 is max insertable line number for GW-BASIC 3.23. # however, 65530-65535 are executed if present in tokenised form. # in GW-BASIC, 65530 appears in LIST, 65531 and above are hidden if to_line is None: to_line = max_list_line # sort by positions, not line numbers! listable = sorted([ state.basic_state.line_numbers[num] for num in state.basic_state.line_numbers if num >= from_line and num <= to_line ]) lines = [] for pos in listable: state.basic_state.bytecode.seek(pos + 1) _, line, _ = tokenise.detokenise_line(state.basic_state.bytecode) lines.append(str(line)) flow.set_pointer(False) return lines
def list_lines(dev, from_line, to_line): """ List line range to console or device. """ if state.basic_state.protected: # don't list protected files raise error.RunError(5) # 65529 is max insertable line number for GW-BASIC 3.23. # however, 65530-65535 are executed if present in tokenised form. # in GW-BASIC, 65530 appears in LIST, 65531 and above are hidden if to_line == None: to_line = max_list_line # sort by positions, not line numbers! listable = sorted([ state.basic_state.line_numbers[num] for num in state.basic_state.line_numbers if num >= from_line and num <= to_line ]) for pos in listable: state.basic_state.bytecode.seek(pos + 1) _, line, _ = tokenise.detokenise_line(state.basic_state.bytecode) if dev == backend.devices['SCRN:']: console.list_line(str(line)) else: dev.write_line(str(line)) dev.close() flow.set_pointer(False)
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])
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])
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])