def read_value(ftype, prompt, default=None, minval=None, maxval=None,
               allowed_single_chars=None, question_mark=True):
    result = None
    if question_mark:
        cquestion_mark = ' ? '
    else:
        cquestion_mark = ''
    if minval is not None:
        try:
            iminval = ftype(minval)
        except ValueError:
            raise ValueError("'" + str(minval) + "' cannot " +
                             "be used as an minval in readi()")
    else:
        iminval = None
    if maxval is not None:
        try:
            imaxval = ftype(maxval)
        except ValueError:
            raise ValueError("'" + str(maxval) + "' cannot " +
                             "be used as an maxval in readi()")
    else:
        imaxval = None
    if minval is None and maxval is None:
        cminmax = ''
    elif minval is None:
        cminmax = ' (number <= ' + str(imaxval) + ')'
    elif maxval is None:
        cminmax = ' (number >= ' + str(iminval) + ')'
    else:
        cminmax = ' (' + str(minval) + ' <= number <= ' + str(maxval) + ')'
    loop = True
    while loop:
        if default is None:
            print(prompt + cminmax + cquestion_mark, end='')
            sys.stdout.flush()
        else:
            print(prompt + cminmax + ' [' + str(default) + ']' +
                  cquestion_mark, end='')
            sys.stdout.flush()
        cresult = sys.stdin.readline().strip()
        if cresult == '' and default is not None:
            cresult = str(default)
        if len(cresult) == 1:
            if allowed_single_chars is not None:
                if cresult in allowed_single_chars:
                    return cresult
        try:
            result = ftype(cresult)
        except ValueError:
            print("*** Error: invalid " + str(ftype) + " value. Try again!")
        else:
            if minval is None and maxval is None:
                loop = False
            elif minval is None:
                if result <= imaxval:
                    loop = False
                else:
                    print("*** Error: number out of range. Try again!")
            elif maxval is None:
                if result >= iminval:
                    loop = False
                else:
                    print("*** Error: number out of range. Try again!")
            else:
                if iminval <= result <= imaxval:
                    loop = False
                else:
                    print("*** Error: number out of range. Try again!")
    return result