#help_index "DolDoc"

U0 EdUndoFilter(CDoc *doc)
{
        Bool             unlock = DocLock(doc);
        CDocEntry       *doc_ce = doc->head.next;

        while (doc_ce != doc)
        {
                doc_ce->de_flags &= ~DOCEF_FILTER_SKIP;
                doc_ce = doc_ce->next;
        }
        doc->find_replace->filter_lines = 0;
        if (unlock)
                DocUnlock(doc);
}

public I64 DocKeyGet(I64 *_sc=NULL)
{//Called by View. You probably don't need this.
        I64  ch, sc;
        Bool cont, old_key_desc;

        do
        {
                old_key_desc = LBtr(&Fs->win_inhibit, WIf_SELF_KEY_DESC);
                do ch = KeyGet(&sc, TRUE);
                while (sc & SCF_KEY_DESC);
                LBEqual(&Fs->win_inhibit, WIf_SELF_KEY_DESC, old_key_desc);

                DocRecalc(DocPut);
                cont = FALSE;
                if ((ch == CH_ESC || ch == CH_SHIFT_ESC) && //Check for exit filter mode
                        DocPut && DocPut->find_replace->filter_lines)
                {
                        EdUndoFilter(DocPut);
                        cont = TRUE;
                }
        }
        while (cont);

        if (_sc)
                *_sc = sc;

        return ch;
}

#help_index "DolDoc/Input;StdIn/DolDoc"
public U8 *DocScanLine(CDoc *doc, CDocEntry *doc_e, I64 *cur_col=NULL, CDocEntry **_do_e_end=NULL)
{//Start at entry in doc,make and return one line as str.
        CDocEntry       *doc_e2 = doc_e;
        Bool             unlock = DocLock(doc);
        U8                      *dst, *src, *start,*res;
        I64                      i = 0;

        if (cur_col)
                *cur_col = -1;
        while (doc_e2 != doc && doc_e2->type_u8 != DOCT_NEW_LINE)
        {
                if (doc_e2->de_flags & DOCEF_TAG && doc_e2->tag)
                {
                        src = doc_e2->tag;
                        i += StrLen(src);
                }
                else if (doc_e2->type_u8 == DOCT_TAB)
                        i++;
                else if (doc_e2->type_u8 == DOCT_SHIFTED_X || doc_e2->type_u8 == DOCT_SHIFTED_Y)
                {
                        if (doc_e2->attr < 0)
                                i++;
                        i += 6; //$SY,3$
                }
                doc_e2 = doc_e2->next;
        }
        res = MAlloc(i + 1);
        dst = res;
        while (doc_e != doc && doc_e->type_u8 != DOCT_NEW_LINE)
        {
                start = dst;
                if (doc_e->de_flags & DOCEF_TAG && doc_e->tag)
                {
                        src = doc_e->tag;
                        while (*src)
                                *dst++ = *src++;
                }
                else if (doc_e->type_u8 == DOCT_TAB)
                        *dst++ = '\t';
                else if (doc_e->type_u8 == DOCT_SHIFTED_Y)
                {
                        *dst(U32 *)++ = '$SY,';
                        if (doc_e->attr < 0)
                                *dst++ = '-';
                        *dst++ = '0' + AbsI64(doc_e->attr); //Supposedly -7 to 7 (single digit)
                        *dst++ = '$';
                }
                else if (doc_e->type_u8 == DOCT_SHIFTED_X)
                {
                        *dst(U32 *)++ = '$SX,';
                        if (doc_e->attr < 0)
                                *dst++ = '-';
                        *dst++ = '0' + AbsI64(doc_e->attr); //Supposedly -7 to 7 (single digit)
                        *dst++ = '$';
                }
                if (doc_e == doc->cur_entry && cur_col)
                        *cur_col = start - res + doc->cur_col;
                doc_e = doc_e->next;
        }
        if (_do_e_end)
                *_do_e_end=doc_e;
        *dst = 0;
        if (doc_e == doc->cur_entry && cur_col && !doc->cur_col)
                *cur_col = dst - res;
        if (unlock)
                DocUnlock(doc);

        return res;
}

U8 *DocGetStr2(I64 flags=0)
{//Flags
        CDoc            *doc;
        CDocEntry       *doc_e, *doc_e_end;
        U8                      *st, *st2, *res;
        I64                      ch, sc;

        "$PT$";
        do
        {
                ch = DocKeyGet(&sc);
                if (ch == CH_ESC)
                {
                        if (doc = DocPut)
                        {
                                DocLock(doc);
                                if (doc->doc_signature == DOC_SIGNATURE_VAL && doc->cur_entry != doc)
                                {
                                        doc_e = DocEntryCopy(doc, doc->cur_entry);
                                        DocBottom(doc);
                                        DocEntryRun(doc, doc_e, TRUE);
                                        DocEntryDel(doc, doc_e);
                                }
                                DocUnlock(doc);
                        }
                        if (flags & SGF_WITH_NEW_LINE)
                                break;
                }
                if (ch == CH_SHIFT_ESC)
                {
                        if (flags & SGF_SHIFT_ESC_EXIT)
                                Exit;
                        else
                        {
                                res = StrNew("");
                                goto gs_done;
                        }
                }
//<CTRL-SHIFT-ENTER> is a blank line without entry
        }
        while (flags & SGF_WITH_NEW_LINE || ch != '\n' || sc & SCF_CTRL && sc & SCF_SHIFT);

        doc = DocPut;
        DocLock(doc);
        if (flags & SGF_WITH_NEW_LINE)
        {
                doc_e = doc->cur_entry;
                do doc_e = doc_e->last;
                while (doc_e != doc && doc_e->type_u8 != DOCT_PROMPT);
                doc_e = doc_e->next;
                if (res = DocScanLine(doc, doc_e, NULL, &doc_e_end))
                {
                        while (doc_e_end != doc && doc_e_end->type_u8 == DOCT_NEW_LINE)
                        {
                                st2 = MStrPrint("%s\n", res);
                                Free(res);
                                res = st2;
                                if (st = DocScanLine(doc, doc_e_end->next, NULL, &doc_e_end))
                                {
                                        st2 = MStrPrint("%s%s", res, st);
                                        Free(st);
                                        Free(res);
                                        res=st2;
                                }
                        }
                }
        }
        else
        {
                doc_e = doc->cur_entry;
                do doc_e = doc_e->last;
                while (doc_e != doc && doc_e->type_u8 != DOCT_NEW_LINE && doc_e->type_u8 != DOCT_PROMPT);
                if (doc_e != doc && doc_e->type_u8 != DOCT_PROMPT)
                {
                        do doc_e = doc_e->last;
                        while (doc_e != doc && doc_e->type_u8 != DOCT_NEW_LINE && doc_e->type_u8 != DOCT_PROMPT);
                }
                doc_e = doc_e->next;
                res = DocScanLine(doc, doc_e, NULL);
        }
        DocUnlock(doc);
gs_done:
        "$PT$$FG$$BG$";

        return res;
}

#help_index "Keyboard Devices;Char/Input;StdIn"
public I64 I64Get(U8 *message=NULL, I64 default=0, I64 lo=I64_MIN, I64 hi=I64_MAX)
{//Prompt user for I64 expression.
        Bool okay;
        U8      *st;
        I64  res;

        while (TRUE)
        {
                if (message)
                        "" message, default;
                st = StrGet;
                if (!*st)
                {
                        Free(st);
                        return default;
                }
                try
                {
                        res = ExePrint2("ToI64(%s);", st);
                        okay = TRUE;
                }
                catch
                {
                        Fs->catch_except = TRUE;
                        okay = FALSE;
                }
                Free(st);
                if (okay && lo <= res <= hi)
                        return res;
        }
}

public F64 F64Get(U8 *message=NULL, F64 default=0, F64 lo=F64_MIN, F64 hi=F64_MAX)
{//Prompt user for F64 expression.
        Bool okay;
        U8      *st;
        F64  res;

        while (TRUE)
        {
                if (message)
                        "" message, default;
                st = StrGet;
                if (!*st)
                {
                        Free(st);
                        return default;
                }
                try
                {
                        res = ExePrint2("ToF64(%s);", st)(F64);
                        okay = TRUE;
                }
                catch
                {
                        Fs->catch_except = TRUE;
                        okay = FALSE;
                }
                Free(st);
                if (okay && lo <= res <= hi)
                        return res;
        }
}

public CDate DateGet(U8 *message=NULL, CDate default=I64_MIN, CDate lo=I64_MIN, CDate hi=I64_MAX)
{//Prompt user for date expression. (Use Now() if you want current time.)
        U8       *st;
        CDate res;

        if (default == I64_MIN)
                default = Now;
        while (TRUE)
        {
                if (message)
                        "" message, default, default;
                st = StrGet;
                if (!*st)
                {
                        Free(st);
                        return default;
                }
                res = Str2Date(st);
                Free(st);
                if (res >= lo && res <= hi)
                        return res;
        }
}