#help_index "DolDoc/Output;StdOut/DolDoc"

CDocEntry *DocPutS(CDoc *doc, U8 *st)
{//Don't use this.      Use DocPrint().
//Does not handle partial Doc entries.
//Returns last newly created dollar-sign CDocEntry or NULL.
        U8                      *ptr = st, *ptr2, *st2, *ptr3, *ptr4, *src, *char_bmp;
        Bool             unlock;
        I64                      ch, j;
        CDocEntry       *doc_e = NULL, *res = NULL, *doc_ce;

        if (!st || !doc && !(doc = DocPut) || doc->doc_signature != DOC_SIGNATURE_VAL)
                return NULL;
        unlock = DocLock(doc);
        if (doc->flags & DOCF_PLAIN_TEXT_TABS)
                char_bmp = char_bmp_zero_cr_nl_cursor;
        else if (doc->flags & DOCF_PLAIN_TEXT)
                char_bmp = char_bmp_zero_tab_cr_nl_cursor;
        else
                char_bmp = char_bmp_zero_tab_cr_nl_cursor_dollar;
        doc_ce = doc->cur_entry;
        while (*ptr)
        {
                ptr2 = ptr;
                do ch = *ptr++;
                while (!Bt(char_bmp, ch) || ch == CH_CURSOR && doc->flags & DOCF_NO_CURSOR);
                ptr--;
                if (!ch)
                {
                        if (j = ptr - ptr2)
                        {
                                doc_e = DocEntryNewBase(doc, DOCT_TEXT | doc->settings_head.default_text_attr << 8);
                                if (doc->flags & DOCF_NO_CURSOR)
                                {
                                        src = MAlloc(j + 1);
                                        MemCopy(src, ptr2, j + 1);
                                        StrUtil(src, SUF_REM_CTRL_CHARS);
                                        j = StrLen(src);
                                }
                                else
                                        src = ptr2;
                                doc_e->tag = MAlloc(j + 1, doc->mem_task);
                                MemCopy(doc_e->tag, src, j + 1);
                                doc_e->max_col = j;
                                DocInsEntry(doc, doc_e);
                                if (doc->flags & DOCF_NO_CURSOR)
                                        Free(src);
                        }
                }
                else
                {
                        if (j = ptr - ptr2)
                        {
                                *ptr = 0;
                                doc_e = DocEntryNewBase(doc, DOCT_TEXT | doc->settings_head.default_text_attr << 8);
                                if (doc->flags & DOCF_NO_CURSOR)
                                {
                                        src = MAlloc(j + 1);
                                        MemCopy(src, ptr2, j + 1);
                                        ptr3 = src;
                                        ptr4 = src;
                                        while (*ptr3)
                                                if (*ptr3 != CH_CURSOR)
                                                        *ptr4++ = *ptr3++;
                                                else
                                                        ptr3++;
                                        *ptr4 = 0;
                                        j = ptr4 - src;
                                }
                                else
                                        src = ptr2;
                                doc_e->tag = MAlloc(j + 1, doc->mem_task);
                                MemCopy(doc_e->tag, src, j + 1);
                                doc_e->max_col = j;
                                DocInsEntry(doc, doc_e);
                                if (doc->flags & DOCF_NO_CURSOR)
                                        Free(src);
                                *ptr = ch;
                        }
                        switch (ch)
                        {
                                case CH_CURSOR:
                                        doc_e = DocEntryNewBase(doc, DOCT_CURSOR | doc->settings_head.default_text_attr << 8);
                                        DocInsEntry(doc, doc_e);
                                        ptr++;
                                        break;

                                case '\t':
                                        doc_e = DocEntryNewBase(doc, DOCT_TAB | doc->settings_head.default_text_attr << 8);
                                        DocInsEntry(doc, doc_e);
                                        ptr++;
                                        break;

                                case '$':
                                        ptr++; //skip first dollar
                                        ptr2 = ptr;
                                        while (*ptr && *ptr != '$')
                                                ptr++;
                                        if (*ptr)
                                        {
                                                *ptr = 0; //zero second dollar
                                                if (ptr - 1 == ptr2 && *ptr2 == CH_CURSOR)
                                                {
                                                        doc_e = DocEntryNewBase(doc, DOCT_CURSOR | doc->settings_head.default_text_attr << 8);
                                                        DocInsEntry(doc, doc_e);
                                                        ptr2++;
                                                }
                                                if (ptr == ptr2)
                                                {
                                                        doc_e = DocEntryNewBase(doc, DOCT_TEXT | doc->settings_head.default_text_attr << 8);
                                                        doc_e->max_col = 1;
                                                        if (doc->flags & DOCF_DBL_DOLLARS)
                                                                doc_e->tag = StrNew("$$", doc->mem_task);
                                                        else
                                                                doc_e->tag = StrNew("$", doc->mem_task);
                                                        DocInsEntry(doc, doc_e);
                                                }
                                                else
                                                {
                                                        st2 = MAlloc(ptr-ptr2+1);
                                                        ptr3 = ptr2;
                                                        ptr4 = st2;
                                                        while (ch = *ptr3++)
                                                        {
                                                                if (ch == CH_CURSOR)
                                                                {
                                                                        doc_e = DocEntryNewBase(doc, DOCT_CURSOR | doc->settings_head.default_text_attr << 8);
                                                                        DocInsEntry(doc, doc_e);
                                                                }
                                                                else
                                                                        *ptr4++ = ch;
                                                        }
                                                        *ptr4 = 0;
                                                        if (doc_e = ParseDollarCmd(doc, st2))
                                                        {
                                                                res = doc_e;
                                                                DocInsEntry(doc, doc_e);
                                                        }
                                                        Free(st2);
                                                }
                                                *ptr++ = '$';
                                        }
                                        break;

                                default:
                                        doc_e = DocEntryNewBase(doc, DOCT_NEW_LINE | doc->settings_head.default_text_attr << 8);
                                        DocInsEntry(doc, doc_e);
                                        if (ch == '\r')
                                                while (*ptr == '\r')
                                                        ptr++;
                                        if (*ptr == '\n')
                                                ptr++;
                                        while (*ptr == '\r')
                                                ptr++;
                        }
                }
        }
        if (unlock)
                DocUnlock(doc);

        return res;
}

public CDocEntry *DocPrint(CDoc *doc=NULL, U8 *format, ...)
{//You must not print partial doc cmds.
//Returns last newly created dollar-sign CDocEntry or NULL.
        U8                      *buf = StrPrintJoin(NULL, format, argc, argv);
        CDocEntry       *res = DocPutS(doc, buf);

        Free(buf);

        return res;
}

public U0 DocPrintPartial(CDoc *doc=NULL, U8 *format, ...)
{//Lets you print half a doc cmd,  if you like.
        U8                      *buf, *st, *src, *dst, *ptr, *ptr2;
        Bool             unlock;
        CDocEntry       *doc_ce, *doc_ne;
        I64                      ch, i, j;
        if (!doc && !(doc = DocPut))
                return;
        buf = StrPrintJoin(NULL, format, argc, argv);
        ptr = buf;
        if (doc->user_put_s && (*doc->user_put_s)(doc, doc->user_put_data, buf))
        {
                Free(buf);
                return;
        }
        unlock = DocLock(doc);
        if (doc->cur_entry->type_u8 == DOCT_DATA)
                while (ch = *ptr++)
                        DocPutKey(doc, ch, 0);
        else
                while (ch = *ptr)
                {
                        if (!Bt(char_bmp_safe_dollar, ch) || doc->flags & (DOCF_OVERSTRIKE | DOCF_IN_DOLLAR))
                        {
                                DocPutKey(doc, ch, 0);
                                ptr++;
                        }
                        else
                        {
                                ptr2 = ptr++;
                                while (TRUE)
                                {
                                        ch = *ptr++;
                                        if (!Bt(char_bmp_safe_dollar, ch))
                                                break;
                                }
                                ptr--;
                                *ptr = 0;
                                doc_ce = doc->cur_entry;
                                j = ptr-ptr2;
                                if (IsEditableText(doc_ce))
                                {
                                        dst = st = MAlloc(doc_ce->max_col + j + 1, doc->mem_task);
                                        src = doc_ce->tag;
                                        i = doc->cur_col;
                                        doc->cur_col += j;
                                        doc_ce->max_col += j;
                                        while (i-- > 0)
                                                *dst++ = *src++;
                                        while (j-- > 0)
                                                *dst++ = *ptr2++;
                                        while (*dst++ = *src++);
                                        Free(doc_ce->tag);
                                        doc_ce->tag = st;
                                }
                                else
                                {
                                        doc_ne = DocEntryNewTag(doc, doc_ce, ptr2);
                                        doc_ne->type = DOCT_TEXT | doc->settings_head.default_text_attr << 8;
                                        doc_ne->de_flags = doldoc.default_de_flags[DOCT_TEXT];
                                        QueueInsert(doc_ne, doc_ce->last);
                                        doc->cur_entry = doc_ne;
                                        doc->cur_col = StrLen(ptr2);
                                }
                                *ptr = ch;
                                DocRemSoftNewLines(doc, doc->cur_entry);
                        }
                }
        if (unlock)
                DocUnlock(doc);
        if (!(doc->flags & DOCF_DONT_SWAP_OUT))
                Yield;
        Free(buf);
}

Bool KDDocPutS(U8 *st)
{
        CDoc *doc;

        if (doc = DocPut)
                DocPrintPartial(doc, "%s", st);

        return FALSE;
}

public U0 DocPrintAtomic(CDoc *doc=NULL, U8 *format, ...)
{//Prints multiple whole cmds all-at-once. Might need this when printing trees.
        U8      *buf;
        Bool unlock;
        I64      old_flags;

        if (!doc && !(doc = DocPut))
                return;
        buf = StrPrintJoin(NULL, format, argc, argv);
        unlock = DocLock(doc);
        old_flags = doc->flags;
        doc->flags |= DOCF_NO_CURSOR;
        DocPrint(doc, "%s", buf);
        DocRecalc(doc);
        doc->flags = old_flags;
        if (unlock)
                DocUnlock(doc);
        Free(buf);
}

U0 DocDump(CDoc *doc, I64 uS_delay=0)
{
        U8                      *st;
        CDocEntry       *doc_e, *doc_e2;
        Bool             unlock = DocLock(doc);

        doc_e = doc->head.next;
        while (doc_e != doc)
        {
                st = DocScanLine(doc, doc_e, NULL, &doc_e2);
                "%s", st;
                Free(st);
                doc_e = doc_e2;
                if (doc_e->type_u8 == DOCT_NEW_LINE)
                {
                        '\n';
                        Busy(uS_delay);
                        doc_e = doc_e->next;
                }
        }
        if (unlock)
                DocUnlock(doc);
}

public CDocEntry *DocPutLine(CDoc *doc=NULL, CDocEntry *doc_e)
{//Send line from other doc to StdOut DocPut.
        I64  ch;
        U8  *ptr, *ptr2;
        Bool unlock;

        if (!doc && !(doc = DocPut) || doc->doc_signature != DOC_SIGNATURE_VAL)
                return NULL;
        unlock = DocLock(doc);
        while (doc_e != doc && doc_e->type_u8 != DOCT_NEW_LINE)
        {
                if (doc_e->de_flags & DOCEF_TAG)
                {
                        ptr = doc_e->tag;
                        do
                        {
                                ptr2 = ptr;
                                while (ch = *ptr)
                                        if (ch == '$')
                                                break;
                                        else
                                                ptr++;
                                *ptr = 0;
                                "%s", ptr2;
                                *ptr = ch;
                                if (ch == '$')
                                {
                                        "$$";
                                        ptr++;
                                }
                        }
                        while (ch);
                }
                else if (doc_e->type_u8 == DOCT_TAB)
                        '\t';
                doc_e = doc_e->next;
        }
        '\n';
        if (doc_e != doc)
                doc_e = doc_e->next;
        if (unlock)
                DocUnlock(doc);

        return doc_e;
}

#help_index "Debugging/Dump;DolDoc/Cmd Line (Typically);"\
                        "Cmd Line (Typically);DolDoc/Output;StdOut/DolDoc"
public U0 DocDm(U8 *buf, I64 count=0x80)
{//Dump live chunk of mem showing addresses. Can be edited.
        CDocEntry       *doc_e;
        CDoc            *doc = DocPut;
        Bool             unlock = DocLock(doc);

        doc_e = DocPrint(doc, "$HX-Z,%d,16$", count);
        doc_e->data = buf;
        doc->cur_entry = doc_e->next;
        DocRecalc(doc);
        if (unlock)
                DocUnlock(doc);
}

public U0 DocD(U8 *buf, I64 count=0x80)
{//Dump live chunk of mem showing offsets. Can be edited.
        CDocEntry       *doc_e;
        CDoc            *doc = DocPut;
        Bool             unlock = DocLock(doc);

        doc_e = DocPrint(doc, "$HX,%d,16$", count);
        doc_e->data = buf;
        doc->cur_entry = doc_e->next;
        DocRecalc(doc);
        if (unlock)
                DocUnlock(doc);
}