(self, impl, iface, exc_type, exc_value, exc_traceback)
return True
Display modal message
Display modal message
Display modal message
def _bluescreen(self, impl, iface, exc_type, exc_value, exc_traceback):
        """Display modal message"""
        if not impl:
            return False
        if iface:
            iface_name = u'%s, %s' % (type(iface._video).__name__, type(iface._audio).__name__)
        else:
            iface_name = u'--'
        # log the standard python error
        stack = traceback.extract_tb(exc_traceback)
        logging.error(''.join(traceback.format_exception(exc_type, exc_value, exc_traceback)))
        # obtain statement being executed
        if impl.interpreter.run_mode:
            codestream = impl.program.bytecode
            bytepos = codestream.tell() - 1
            from_line = impl.program.get_line_number(bytepos)
            try:
                codestream.seek(impl.program.line_numbers[from_line]+1)
                _, output, textpos = impl.lister.detokenise_line(codestream, bytepos)
                code_line = bytes(output)
            except KeyError:
                code_line = b'<could not retrieve line number %d>' % from_line
        else:
            impl.interpreter.direct_line.seek(0)
            code_line = bytes(
                impl.lister.detokenise_compound_statement(impl.interpreter.direct_line)[0]
            )
        # don't risk codepage logic here, use cp437
        code_line = code_line.decode('cp437', 'replace')
        # stop program execution
        impl.interpreter.set_pointer(False)
        # create crash log file
        logname = datetime.now().strftime(LOG_PATTERN)
        logfile = tempfile.NamedTemporaryFile(
            mode='wb', suffix='.log', prefix=logname, dir=self._log_dir, delete=False
        )
        # construct the message
        frozen = getattr(sys, 'frozen', u'') or u''
        message = [
            (0x70, u'FATAL ERROR\n'),
            (0x17, u'version   '),
            (0x1f, LONG_VERSION),
            (0x17, u'\npython    '),
            (0x1f, u'%s [%s] %s' % (
                platform.python_version(), u' '.join(platform.architecture()), frozen
            )),
            (0x17, u'\nplatform  '),
            (0x1f, platform.platform()),
            (0x17, u'\ninterface '),
            (0x1f, iface_name),
            (0x17, u'\nstatement '),
            (0x1f, code_line + u'\n\n'),
        ] + [
            (0x1f, u'{0}:{1}, {2}\n'.format(os.path.split(s[0])[-1], s[1], s[2]))
            for s in stack[-4:]
        ] + [
            (0x1f, u'{0}:'.format(exc_type.__name__)),
            (0x17, u' {0}\n\n'.format(exc_value)),
            (0x70, u'This is a bug in PC-BASIC.\n'),
            (0x17, u'Sorry about that. You can help improve PC-BASIC:\n\n'),
            (0x17, u'- Please file a bug report, including this message and the steps you took\n'),
            (0x17, u'  just before the crash. Go to:\n'),
            (0x17, u'    '),
            (0x1f, u'https://github.com/robhagemans/pcbasic/issues\n\n'),
            (0x17, u'- Please include the full crash log in your report.\n'),
            (0x17, u'  You can paste it from the clipboard or from the file at:\n    '),
            (0x1f, logfile.name),
        ]
        bottom = (0x70,
            u'Thank you! Press a key to close this window.'
        )
        # create crash log
        crashlog = [
            u'PC-BASIC crash log',
            u'=' * 100,
            u''.join(text for _, text in message),
            u''.join(traceback.format_exception(exc_type, exc_value, exc_traceback)),
            u'==== Screen Pages ='.ljust(100, u'='),
            repr(impl.display.text_screen),
            u'==== Scalars ='.ljust(100, u'='),
            repr(impl.scalars),
            u'==== Arrays ='.ljust(100, u'='),
            repr(impl.arrays),
            u'==== Strings ='.ljust(100, u'='),
            repr(impl.strings),
            u'==== Program Buffer ='.ljust(100, u'='),
            repr(impl.program),
        ]
        impl.program.bytecode.seek(1)
        crashlog.append(u'==== Program ='.ljust(100, u'='))
        while True:
            _, line, _ = impl.lister.detokenise_line(impl.program.bytecode)
            if not line:
                break
            crashlog.append(bytes(line).decode('cp437', 'replace'))
        crashlog.append(u'==== Options ='.ljust(100, u'='))
        crashlog.append(repr(self._uargv))
        # clear screen for modal message
        # choose attributes - this should be readable on VGA, MDA, PCjr etc.
        impl.display.screen(0, 0, 0, 0, new_width=80)
        impl.display.set_attr(0x17)
        impl.display.set_border(1)
        impl.display.text_screen.clear()
        # show message on screen
        for attr, text in message:
            impl.display.set_attr(attr)
            impl.console.write(text.encode('cp437', 'replace').replace(b'\n', b'\r'))
        impl.display.set_attr(bottom[0])
        impl.display.text_screen._bottom_row_allowed = True
        impl.display.text_screen.set_pos(25, 1)
        impl.console.write(bottom[1].encode('cp437', 'replace'))
        # write crash log
        crashlog = u'\n'.join(
            line.decode('cp437', 'replace') if isinstance(line, bytes) else line
            for line in crashlog
        )
        with logfile as f:
            f.write(crashlog.encode('utf-8', 'replace'))
        # put on clipboard
        impl.queues.video.put(signals.Event(signals.VIDEO_SET_CLIPBOARD_TEXT, (crashlog,)))
        return True
def _bluescreen ( self , impl , iface , exc_type , exc_value , exc_traceback ) : if not impl : return False if iface : iface_name = u'%s, %s' % ( type ( iface . _video ) . __name__ , type ( iface . _audio ) . __name__ ) else : iface_name = u'--' # log the standard python error stack = traceback . extract_tb ( exc_traceback ) logging . error ( '' . join ( traceback . format_exception ( exc_type , exc_value , exc_traceback ) ) ) # obtain statement being executed if impl . interpreter . run_mode : codestream = impl . program . bytecode bytepos = codestream . tell ( ) - 1 from_line = impl . program . get_line_number ( bytepos ) try : codestream . seek ( impl . program . line_numbers [ from_line ] + 1 ) _ , output , textpos = impl . lister . detokenise_line ( codestream , bytepos ) code_line = bytes ( output ) except KeyError : code_line = b'<could not retrieve line number %d>' % from_line else : impl . interpreter . direct_line . seek ( 0 ) code_line = bytes ( impl . lister . detokenise_compound_statement ( impl . interpreter . direct_line ) [ 0 ] ) # don't risk codepage logic here, use cp437 code_line = code_line . decode ( 'cp437' , 'replace' ) # stop program execution impl . interpreter . set_pointer ( False ) # create crash log file logname = datetime . now ( ) . strftime ( LOG_PATTERN ) logfile = tempfile . NamedTemporaryFile ( mode = 'wb' , suffix = '.log' , prefix = logname , dir = self . _log_dir , delete = False ) # construct the message frozen = getattr ( sys , 'frozen' , u'' ) or u'' message = [ ( 0x70 , u'FATAL ERROR\n' ) , ( 0x17 , u'version   ' ) , ( 0x1f , LONG_VERSION ) , ( 0x17 , u'\npython    ' ) , ( 0x1f , u'%s [%s] %s' % ( platform . python_version ( ) , u' ' . join ( platform . architecture ( ) ) , frozen ) ) , ( 0x17 , u'\nplatform  ' ) , ( 0x1f , platform . platform ( ) ) , ( 0x17 , u'\ninterface ' ) , ( 0x1f , iface_name ) , ( 0x17 , u'\nstatement ' ) , ( 0x1f , code_line + u'\n\n' ) , ] + [ ( 0x1f , u'{0}:{1}, {2}\n' . format ( os . path . split ( s [ 0 ] ) [ - 1 ] , s [ 1 ] , s [ 2 ] ) ) for s in stack [ - 4 : ] ] + [ ( 0x1f , u'{0}:' . format ( exc_type . __name__ ) ) , ( 0x17 , u' {0}\n\n' . format ( exc_value ) ) , ( 0x70 , u'This is a bug in PC-BASIC.\n' ) , ( 0x17 , u'Sorry about that. You can help improve PC-BASIC:\n\n' ) , ( 0x17 , u'- Please file a bug report, including this message and the steps you took\n' ) , ( 0x17 , u'  just before the crash. Go to:\n' ) , ( 0x17 , u'    ' ) , ( 0x1f , u'https://github.com/robhagemans/pcbasic/issues\n\n' ) , ( 0x17 , u'- Please include the full crash log in your report.\n' ) , ( 0x17 , u'  You can paste it from the clipboard or from the file at:\n    ' ) , ( 0x1f , logfile . name ) , ] bottom = ( 0x70 , u'Thank you! Press a key to close this window.' ) # create crash log crashlog = [ u'PC-BASIC crash log' , u'=' * 100 , u'' . join ( text for _ , text in message ) , u'' . join ( traceback . format_exception ( exc_type , exc_value , exc_traceback ) ) , u'==== Screen Pages =' . ljust ( 100 , u'=' ) , repr ( impl . display . text_screen ) , u'==== Scalars =' . ljust ( 100 , u'=' ) , repr ( impl . scalars ) , u'==== Arrays =' . ljust ( 100 , u'=' ) , repr ( impl . arrays ) , u'==== Strings =' . ljust ( 100 , u'=' ) , repr ( impl . strings ) , u'==== Program Buffer =' . ljust ( 100 , u'=' ) , repr ( impl . program ) , ] impl . program . bytecode . seek ( 1 ) crashlog . append ( u'==== Program =' . ljust ( 100 , u'=' ) ) while True : _ , line , _ = impl . lister . detokenise_line ( impl . program . bytecode ) if not line : break crashlog . append ( bytes ( line ) . decode ( 'cp437' , 'replace' ) ) crashlog . append ( u'==== Options =' . ljust ( 100 , u'=' ) ) crashlog . append ( repr ( self . _uargv ) ) # clear screen for modal message # choose attributes - this should be readable on VGA, MDA, PCjr etc. impl . display . screen ( 0 , 0 , 0 , 0 , new_width = 80 ) impl . display . set_attr ( 0x17 ) impl . display . set_border ( 1 ) impl . display . text_screen . clear ( ) # show message on screen for attr , text in message : impl . display . set_attr ( attr ) impl . console . write ( text . encode ( 'cp437' , 'replace' ) . replace ( b'\n' , b'\r' ) ) impl . display . set_attr ( bottom [ 0 ] ) impl . display . text_screen . _bottom_row_allowed = True impl . display . text_screen . set_pos ( 25 , 1 ) impl . console . write ( bottom [ 1 ] . encode ( 'cp437' , 'replace' ) ) # write crash log crashlog = u'\n' . join ( line . decode ( 'cp437' , 'replace' ) if isinstance ( line , bytes ) else line for line in crashlog ) with logfile as f : f . write ( crashlog . encode ( 'utf-8' , 'replace' ) ) # put on clipboard impl . queues . video . put ( signals . Event ( signals . VIDEO_SET_CLIPBOARD_TEXT , ( crashlog , ) ) ) return True