def open_file_or_device(number, name, mode='I', access='R', lock='', reclen=128, defext=''):
    """ Open a file or device specified by name. """
    if (not name) or (number < 0) or (number > max_files):
        # bad file number; also for name='', for some reason
        raise error.RunError(52)
    if number in state.io_state.files:
        # file already open
        raise error.RunError(55)
    name, mode = str(name), mode.upper()
    inst = None
    split_colon = name.upper().split(':')
    if len(split_colon) > 1: # : found
        dev_name = split_colon[0] + ':'
        dev_param = split_colon[1] 
        try:
            inst = device_open(dev_name, number, mode, access, lock, reclen, dev_param)
        except KeyError:    
            if len(dev_name) > 2:
                # devname could be A:, B:, C:, etc.. but anything longer is an error (bad file number, for some reason).
                raise error.RunError(52)   
    if not inst:
        # translate the file name to something DOS-ish if necessary
        if mode in ('O', 'A'):
            # don't open output or append files more than once
            check_file_not_open(name)
        if mode in ('I', 'L'):
            name = oslayer.native_path(name, defext)
        else:    
            # random files: try to open matching file
            # if it doesn't exist, create an all-caps 8.3 file name
            name = oslayer.native_path(name, defext, make_new=True)
        # obtain a lock
        request_lock(name, lock, access)
        # open the file
        fhandle = oslayer.open_file(name, mode, access)
        # apply the BASIC file wrapper
        if mode in ('S', 'L'): # save, load
            inst = BaseFile(fhandle, name, number, mode, access, lock)
        elif mode in ('I', 'O', 'A'):
            inst = TextFile(fhandle, name, number, mode, access, lock)
        else:
            inst = RandomFile(fhandle, name, number, mode, access, lock, reclen)
    return inst    
def check_file_not_open(path):
    """ Raise an error if the file is open. """
    for f in state.io_state.files:
        if oslayer.native_path(path) == state.io_state.files[f].name:
            raise error.RunError(55)