#help_index "DolDoc"

I64 ParseDocFlagSingle(CCompCtrl *cc, I64 *_de_flags, U32 *_type, Bool turn_on)
{
    I64              res = -1;
    CHashGeneric    *tmph;

    if (cc->token == TK_IDENT && (tmph = HashFind(cc->cur_str, doldoc.hash, DHT_DOC_FLAG)))
    {
        res = tmph->user_data0;
        if (res < 64)
        {
            BEqual(_de_flags, res, turn_on);
            switch (res)
            {
                case DOCEf_BLINK:
                case DOCEf_INVERT:
                case DOCEf_UNDERLINE:
                case DOCEf_SEL:
                    BEqual(_type, res, turn_on);
                    break;
            }
        }
        Lex(cc);        //skip flag
    }

    return res;
}

I64 ParseDocFlags(CCompCtrl *cc, I64 *_de_flags, U32 *_type)
{
    I64  res = -1;
    Bool turn_on;

    while (TRUE)
    {
        if (cc->token == '+')
            turn_on = TRUE;
        else if (cc->token == '-')
            turn_on = FALSE;
        else
            break;
        Lex(cc);
        res = ParseDocFlagSingle(cc, _de_flags, _type, turn_on);
    }

    return res;
}

U8 *Doc2PlainText(CDoc *doc, CDocEntry *doc_e)
{//TODO: break strs
    I64 i, j, attr = doc_e->attr, t1, f1, de_flags, type;
    U8 *buf, *buf2;

    if (doc_e->type_u8 == DOCT_FOREGROUND && doc->flags & DOCF_COLOR_NAMES && 0 <= attr < COLORS_NUM)
    {
        buf = StrNew(DefineSub(attr, "ST_COLORS"));
        attr = DOC_DEFAULT;
    }
    else
        buf = StrNew(DefineSub(doc_e->type_u8, "ST_DOC_CMDS"));
    if (doc_e->type_u8 != DOCT_ERROR)
    {
        f1 = doldoc.default_de_flags[doc_e->type_u8];
        t1 = doc_e->type_u8 | doldoc.default_type_flags[doc_e->type_u8];

        de_flags = doc_e->de_flags & ~(DOCG_BL_IV_UL | DOCEF_SEL | DOCEF_HIGHLIGHT |
                                       DOCEF_WORD_WRAP | DOCEF_SKIP | DOCEF_FILTER_SKIP);

        for (i = 0; i < DOCEf_FLAGS_NUM;i++)
            if (Bt(&f1, i) != Bt(&de_flags, i))
        {
                if (Bt(&de_flags, i))
                {
                    if (!(1 << i & DOCEG_HAS_ARG))
                    {
                        buf2 =MStrPrint("%s+%Z", buf, i, "ST_DOC_FLAGS");
                        Free(buf);
                        buf = buf2;
                    }
                }
                else
                {
                    buf2 = MStrPrint("%s-%Z", buf, i, "ST_DOC_FLAGS");
                    Free(buf);
                    buf = buf2;
                }
            }
        type = doc_e->type & ~DOCET_SEL;
        for (i = DOCEt_BLINK; i <= DOCEt_UNDERLINE; i++)
            if (Bt(&t1, i) != Bt(&type, i))
            {
                if (Bt(&type, i))
                    buf2 = MStrPrint("%s+%Z", buf, i, "ST_DOC_FLAGS");
                else
                    buf2 = MStrPrint("%s-%Z", buf, i, "ST_DOC_FLAGS");
                Free(buf);
                buf = buf2;
            }
        buf2 = MStrPrint("%s,", buf);
        Free(buf);
        buf = buf2;
        switch [doc_e->type_u8]
        {
            case DOCT_HEX_ED:
                buf2 = MStrPrint("%s%d,", buf, doc_e->len);
                Free(buf);
                buf  =buf2;
                buf2 = MStrPrint("%s%d,", buf, doc_e->hex_ed_width);
                Free(buf);
                buf = buf2;
                break;

            case DOCT_FOREGROUND:
            case DOCT_BACKGROUND:
            case DOCT_DEFAULT_FOREGROUND:
            case DOCT_DEFAULT_BACKGROUND:
                if (doc->flags & DOCF_COLOR_NAMES && 0 <= attr < COLORS_NUM)
                {
                    buf2 = MStrPrint("%s%Z,", buf, doc_e->attr, "ST_COLORS");
                    Free(buf);
                    buf = buf2;
                    break;
                }
            case DOCT_PAGE_LEN:
            case DOCT_LEFT_MARGIN:
            case DOCT_RIGHT_MARGIN:
            case DOCT_HEADER:
            case DOCT_FOOTER:
            case DOCT_INDENT:
            case DOCT_WORD_WRAP:
            case DOCT_HIGHLIGHT:
            case DOCT_BLINK:
            case DOCT_INVERT:
            case DOCT_UNDERLINE:
            case DOCT_SHIFTED_X:
            case DOCT_SHIFTED_Y:
                if (attr != DOC_DEFAULT)
                {
                    buf2 = MStrPrint("%s%d,", buf, doc_e->attr);
                    Free(buf);
                    buf = buf2;
                }
            case DOCT_TYPES_NUM - 1: //nobound switch
                break;
        }
        de_flags = doc_e->de_flags & DOCEG_HAS_ARG;
        while (de_flags)
        {
            j = Bsf(de_flags);
            Btr(&de_flags, j);
            switch [j]
            {
                case DOCEf_TAG:
                    if (doc_e->type_u8 == DOCT_DATA || doc_e->type_u8 == DOCT_MACRO &&
                        (doc_e->de_flags & DOCEF_LEFT_MACRO &&
                         !StrCompare(doc_e->tag, doc_e->left_macro) ||
                         doc_e->de_flags & DOCEF_RIGHT_MACRO &&
                         !StrCompare(doc_e->tag, doc_e->right_macro)) ||
                        doc_e->de_flags & DOCEF_LIST && !StrCompare(doc_e->tag, "[]") && doc_e->de_flags & DOCEF_DEFINE)
                    {
                        buf2 = buf;
                        buf = NULL;
                    }
                    else
                    {
                        if (doc_e->type_u8 == DOCT_CHECK_BOX)
                        {
                            if (StrLen(doc_e->tag) >= 4)
                                buf2 = doc_e->tag + 4;
                            else
                                buf2 = "";
                        }
                        else if (doc_e->de_flags & DOCEF_TREE)
                        {
                            if (StrLen(doc_e->tag) >= 3)
                                buf2 = doc_e->tag + 3;
                            else
                                buf2 = "";
                        }
                        else
                            buf2 = doc_e->tag;
                        if (Bt(&doldoc.default_de_flags[doc_e->type_u8], DOCEf_TAG))
                            buf2 = MStrPrint("%s\"%$Q\",", buf, buf2);
                        else
                            buf2 = MStrPrint("%sT=\"%$Q\",", buf, buf2);
                    }
                    break;
                case DOCEf_LEN:
                    buf2 = MStrPrint("%sLEN=%d,", buf, doc_e->len);
                    break;

                case DOCEf_AUX_STR:
                    buf2 = MStrPrint("%sA=\"%$Q\",", buf, doc_e->aux_str);
                    break;

                case DOCEf_DEFINE:
                    buf2 = MStrPrint("%sD=\"%$Q\",", buf, doc_e->define_str);
                    break;

                case DOCEf_HTML_LINK:
                    buf2 = MStrPrint("%sHTML=\"%$Q\",", buf, doc_e->html_link);
                    break;

                case DOCEf_LEFT_EXP:
                    buf2 = MStrPrint("%sLE=%d,", buf, doc_e->left_exp);
                    break;

                case DOCEf_LEFT_MACRO:
                    buf2 = MStrPrint("%sLM=\"%$Q\",", buf, doc_e->left_macro);
                    break;

                case DOCEf_RIGHT_EXP:
                    buf2 = MStrPrint("%sRE=%d,", buf, doc_e->right_exp);
                    break;

                case DOCEf_RIGHT_MACRO:
                    buf2 = MStrPrint("%sRM=\"%$Q\",", buf, doc_e->right_macro);
                    break;

                case DOCEf_HAS_BIN:
                    buf2 = MStrPrint("%sBI=%d,", buf, doc_e->bin_num);
                    break;

                case DOCEf_BIN_PTR_LINK:
                    buf2 = MStrPrint("%sBP=\"%$Q\",", buf, doc_e->bin_ptr_link);
                    break;

                case DOCEf_RAW_TYPE:
                    if (doc_e->type_u8 == DOCT_CHECK_BOX && doc_e->raw_type != RT_I8 ||
                            doc_e->type_u8 != DOCT_CHECK_BOX && doc_e->raw_type != RT_I64)

                        buf2 = MStrPrint("%sRT=%Z,", buf, doc_e->raw_type, "ST_RAW_TYPES");
                    break;

                case DOCEf_SHIFTED_X:
                    j = doc_e->type.u16[1] & 0x1F;
                    if (j & 0x10)
                        j |= 0xFFFFFFF0;
                    buf2 = MStrPrint("%sSX=%d,", buf, j);
                    break;

                case DOCEf_SHIFTED_Y:
                    j = doc_e->type >> 21 & 0x1F;
                    if (j & 0x10)
                        j |= 0xFFFFFFF0;
                    buf2 = MStrPrint("%sSY=%d,", buf, j);
                    break;

                case DOCEf_SCROLLING_X:
                    buf2 = MStrPrint("%sSCX=%d,", buf, doc_e->scroll_len);
                    break;

                case DOCEf_USER_DATA:
                    buf2 = MStrPrint("%sU=0x%X,", buf, doc_e->user_data);
                    break;

                case DOCEf_FLAGS_NUM - 1: //nobound switch
                    break;
            }
            Free(buf);
            buf = buf2;
        }
        buf[StrLen(buf) - 1] = 0;  //Kill last comma
    }
    buf2 = StrNew(buf, doc->mem_task); //exact allocation
    Free(buf);

    return buf2;
}

CDocEntry *ParseDollarCmd(CDoc *doc, U8 *st)
{//Uses Lex() to parse a string and make Doc entries.
    I64              i, j, de_flags, processed_flags, attr = DOC_DEFAULT;
    U8              *ptr, *st2;
    CDocEntry       *doc_e = NULL;
    CHashGeneric    *tmph;
    CCompCtrl       *cc = CompCtrlNew(st, CCF_DONT_FREE_BUF);
    CHashTable      *old_hash_table_list = cc->htc.hash_table_list;

    try
    {
        cc->htc.hash_table_list = NULL;
        if (Lex(cc) == TK_IDENT)
        {
            if (tmph = HashFind(cc->cur_str, doldoc.hash, DHT_DOC_CMD | DHT_COLOR))
            {
                if (tmph->type & DHT_DOC_CMD)
                    i = tmph->user_data0;
                else
                {//DHT_COLOR
                    i = DOCT_FOREGROUND;
                    attr = tmph->user_data0;
                }
            }
            else
                goto pd_err;
            Lex(cc); //skip cmd code
            doc_e = CAlloc(sizeof(CDocEntry), doc->mem_task);
            doc_e->type     =  i;
            doc_e->de_flags =  doldoc.default_de_flags[i];
            doc_e->type     |= doldoc.default_type_flags[i];
            doc_e->raw_type =  RT_I64;
            doc_e->len      =  DOCE_LEN_DEFAULT;
            j=ParseDocFlags(cc, &doc_e->de_flags, &doc_e->type);
            cc->htc.hash_table_list = old_hash_table_list;
            switch [i]
            {
                case DOCT_CHECK_BOX:
                    doc_e->raw_type = RT_I8;
                    break;

                case DOCT_HEX_ED:
                    while (cc->token == ',')
                        Lex(cc);
                    if (cc->token)
                        doc_e->len = LexExpressionI64(cc);
                    else
                        goto pd_err;
                    while (cc->token == ',')
                        Lex(cc);
                    if (cc->token)
                        doc_e->hex_ed_width = LexExpressionI64(cc);
                    else
                        goto pd_err;
                    break;

                case DOCT_PAGE_LEN:
                case DOCT_LEFT_MARGIN:
                case DOCT_RIGHT_MARGIN:
                case DOCT_HEADER:
                case DOCT_FOOTER:
                case DOCT_INDENT:
                case DOCT_FOREGROUND:
                case DOCT_BACKGROUND:
                case DOCT_DEFAULT_FOREGROUND:
                case DOCT_DEFAULT_BACKGROUND:
                case DOCT_WORD_WRAP:
                case DOCT_HIGHLIGHT:
                case DOCT_BLINK:
                case DOCT_INVERT:
                case DOCT_UNDERLINE:
                case DOCT_SHIFTED_X:
                case DOCT_SHIFTED_Y:
                    while (cc->token == ',')
                        Lex(cc);
                    if (cc->token)
                        doc_e->attr = LexExpressionI64(cc);
                    else
                        doc_e->attr = attr;
                    break;
#assert DOCT_ERROR == DOCT_TYPES_NUM - 1

                case DOCT_ERROR:
                    goto pd_err;
            }

            processed_flags = 0;
            while (TRUE)
            {
                cc->htc.hash_table_list = NULL;
                while (cc->token == ',')
                    Lex(cc);
                cc->htc.hash_table_list = old_hash_table_list;
                j=ParseDocFlagSingle(cc, &doc_e->de_flags, &doc_e->type, TRUE);
                if (!(de_flags = ~processed_flags & doc_e->de_flags & DOCEG_HAS_ARG))
                    break;
                if (cc->token == '=')
                    Lex(cc);
                else
                    j = Bsf(de_flags);
                if (j < 0 || Bts(&processed_flags, j))
                    goto pd_err;
                switch [j]
                {//TODO: Might check for expression errors
                    case DOCEf_TAG:
                        if (!doc_e->tag)
                        {
//If a $MA,LM=""$, Tag is filled when the LM is processed.
                            //if doc_e->df_flags&DOCEF_LIST,
                            // Tag is filled when the Define is processed.
                            //(The default_flag1.tag calls this after.)
                            if (cc->token == TK_STR)
                            {
                                st2 = LexExtStr(cc);
                                if (i == DOCT_CHECK_BOX)
                                {
                                    st = MStrPrint("[X] %s", st2);
                                    Free(st2);
                                    doc_e->min_col = 1;
                                }
                                else if (doc_e->de_flags & DOCEF_LIST)
                                {
                                    if (*st2 != '[')
                                    {
                                        st = MStrPrint("[%s]", st2);
                                        Free(st2);
                                    }
                                    else
                                        st = st2;
                                    doc_e->min_col = 1;
                                }
                                else if (doc_e->de_flags & DOCEF_TREE)
                                {
                                    st = MStrPrint("+] %s", st2);
                                    Free(st2);
                                    doc_e->min_col = 1;
                                }
                                else
                                    st = st2;
                                doc_e->tag = StrNew(st, doc->mem_task);
                                Free(st);
                            }
                            else
                                goto pd_err;
                        }
                        break;

                    case DOCEf_LEN:
                        if (cc->token)
                        {
                            doc_e->len      =  LexExpression(cc);
                            doc_e->de_flags &= ~DOCEF_DEFAULT_LEN;
                        }
                        else
                            goto pd_err;
                        break;

                    case DOCEf_AUX_STR:
                        if (cc->token == TK_STR)
                        {
                            st2 = LexExtStr(cc);
                            doc_e->aux_str = StrNew(st2, doc->mem_task);
                            Free(st2);
//Anchor
                            if (i == DOCT_DATA)
                            { //See DocForm()
                                if (ptr = StrMatch(":", doc_e->aux_str))
                                    doc_e->min_col = ptr - doc_e->aux_str + 1;

                                doc_e->tag = MAlloc(doc_e->len + doc_e->min_col + 2, doc->mem_task); //+2 because "_\0"
                            }
                        }
                        else
                            goto pd_err;
                        break;

                    case DOCEf_DEFINE:
                        if (cc->token == TK_STR)
                        {
                            st2 = LexExtStr(cc);
                            doc_e->define_str = StrNew(st2, doc->mem_task);
                            Free(st2);
                            if (doc_e->de_flags & DOCEF_LIST && !doc_e->tag)
                                doc_e->tag = StrNew("[]", doc->mem_task);
                        }
                        else
                            goto pd_err;
                        break;

                    case DOCEf_HTML_LINK:
                        if (cc->token == TK_STR)
                        {
                            st2 = LexExtStr(cc);
                            doc_e->html_link = StrNew(st2, doc->mem_task);
                            Free(st2);
                        }
                        else
                            goto pd_err;
                        break;

                    case DOCEf_LEFT_EXP:
                        if (cc->token)
                            doc_e->left_exp = LexExpression(cc);
                        else
                            goto pd_err;
                        break;

                    case DOCEf_LEFT_MACRO:
                        if (cc->token == TK_STR)
                        {
                            st2 = LexExtStr(cc);
                            doc_e->left_macro = StrNew(st2, doc->mem_task);
                            Free(st2);
                            if (i == DOCT_MACRO && !doc_e->tag)
                                doc_e->tag = StrNew(doc_e->left_macro, doc->mem_task);
                        }
                        else
                            goto pd_err;
                        break;

                    case DOCEf_RIGHT_EXP:
                        if (cc->token)
                            doc_e->right_exp = LexExpression(cc);
                        else
                            goto pd_err;
                        break;

                    case DOCEf_RIGHT_MACRO:
                        if (cc->token == TK_STR)
                        {
                            st2 = LexExtStr(cc);
                            doc_e->right_macro = StrNew(st2, doc->mem_task);
                            Free(st2);
                            if (i == DOCT_MACRO && !doc_e->tag)
                                doc_e->tag = StrNew(doc_e->right_macro, doc->mem_task);
                        }
                        else
                            goto pd_err;
                        break;

                    case DOCEf_HAS_BIN:
                        if (cc->token)
                            doc_e->bin_num = LexExpressionI64(cc);
                        else
                            goto pd_err;
                        break;

                    case DOCEf_BIN_PTR_LINK:
                        if (cc->token == TK_STR)
                        {
                            st2 = LexExtStr(cc);
                            doc_e->bin_ptr_link = StrNew(st2, doc->mem_task);
                            Free(st2);
                            if (!DocBinPtrReset(doc, doc_e))
                                doc_e->type = DOCT_ERROR;
                        }
                        else
                            goto pd_err;
                        break;

                    case DOCEf_RAW_TYPE:
                        if (cc->token == TK_IDENT)
                        {
                            j = DefineMatch(cc->cur_str, "ST_RAW_TYPES");
                            if (j < 0)
                                goto pd_err;
                            doc_e->raw_type =  j;
                            doc_e->de_flags &= ~DOCEF_DEFAULT_RAW_TYPE;
                            Lex(cc);
                        }
                        else
                            goto pd_err;
                        break;

                    case DOCEf_SHIFTED_X:
                        if (cc->token)
                            doc_e->type |= (LexExpressionI64(cc) & 0x1F) << 16;
                        else
                            goto pd_err;
                        break;

                    case DOCEf_SHIFTED_Y:
                        if (cc->token)
                            doc_e->type |= (LexExpressionI64(cc) & 0x1F) << 21;
                        else
                            goto pd_err;
                        break;

                    case DOCEf_SCROLLING_X:
                        if (cc->token)
                            doc_e->scroll_len = LexExpressionI64(cc);
                        else
                            goto pd_err;
                        break;

                    case DOCEf_USER_DATA:
                        if (cc->token)
                            doc_e->user_data = LexExpression(cc);
                        else
                            goto pd_err;
                        break;

                    case DOCEf_FLAGS_NUM - 1: //nobound switch
                        break;
                }
            }
        }
        else
        {
pd_err:
            if (!doc_e)
                doc_e = CAlloc(sizeof(CDocEntry), doc->mem_task);
            doc_e->type     = DOCT_ERROR;
            doc_e->de_flags = 0;
        }
        if (doc_e->de_flags & DOCEF_LIST && (doc_e->de_flags & DOCEF_REMALLOC_DATA || !(doc_e->de_flags & DOCEF_DEREF_DATA)))
        {
            DocDataScan(doc, doc_e);
            DocDataFormat(doc, doc_e);
        }
        CompCtrlDel(cc);
    }
    catch
    {
        Fs->catch_except = TRUE;
        if (!doc_e)
            doc_e = CAlloc(sizeof(CDocEntry), doc->mem_task);
        doc_e->type     = DOCT_ERROR;
        doc_e->de_flags = 0;
    }

    return doc_e;
}

U0 DocEntryToggle(CDoc *doc)
{
    Bool         unlock = DocLock(doc), old_color_names;
    CDocEntry   *doc_ce = doc->cur_entry, *cl1, *doc_ce2;
    U8           ch, *st, *st2;
    I64          i, j, k;

    if (doc_ce != doc && !(doc->flags & (DOCF_PLAIN_TEXT | DOCF_PLAIN_TEXT_TABS)))
    {
        if (doc_ce->type_u8 == DOCT_TEXT &&
            !(doc_ce->de_flags &
             ~(DOCEF_TAG | DOCG_BL_IV_UL | DOCEF_WORD_WRAP | DOCEF_HIGHLIGHT | DOCEF_SKIP | DOCEF_FILTER_SKIP)) &&
            !(doc_ce->type&DOCG_BL_IV_UL))
        {
            doc_ce2 = doc_ce->last;
            for (k = 0; k < 20; k++)
            {
                if (doc_ce2 != doc)
                {
                    cl1 = doc_ce2->last;
                    if (doc_ce2->type_u8 == DOCT_TEXT &&
                        doc_ce->de_flags == doc_ce2->de_flags &&
                        doc_ce->type == doc_ce2->type)
                    {
                        i = StrLen(doc_ce2->tag);
                        j = StrLen(doc_ce->tag);
                        st = MAlloc(i + j + 1, doc->mem_task);
                        MemCopy(st, doc_ce2->tag, i);
                        MemCopy(st + i, doc_ce->tag, j + 1);
                        Free(doc_ce->tag);
                        doc_ce->tag     =  st;
                        doc_ce->max_col =  i + j;
                        doc->cur_col    += i;
                        DocEntryDel(doc, doc_ce2);
                    }
                    else if (doc_ce2->type_u8 == DOCT_SOFT_NEW_LINE)
                        DocEntryDel(doc, doc_ce2);
                    else
                        break;
                    doc_ce2 = cl1;
                }
                else
                    break;
            }
            doc_ce2 = doc_ce->next;
            for (k = 0; k < 20; k++)
            {
                if (doc_ce2 != doc)
                {
                    cl1 = doc_ce2->next;
                    if (doc_ce2->type_u8 == DOCT_TEXT &&
                        doc_ce->de_flags == doc_ce2->de_flags &&
                        doc_ce->type == doc_ce2->type)
                    {
                        i = StrLen(doc_ce->tag);
                        j = StrLen(doc_ce2->tag);
                        st = MAlloc(i + j + 1, doc->mem_task);
                        MemCopy(st, doc_ce->tag, i);
                        MemCopy(st + i, doc_ce2->tag, j + 1);
                        Free(doc_ce->tag);
                        doc_ce->tag     = st;
                        doc_ce->max_col = i + j;
                        DocEntryDel(doc, doc_ce2);
                    }
                    else if (doc_ce2->type_u8 == DOCT_SOFT_NEW_LINE)
                        DocEntryDel(doc, doc_ce2);
                    else
                        break;
                    doc_ce2 = cl1;
                }
                else
                    break;
            }
            i = doc->cur_col;
            while (i > doc_ce->min_col && doc_ce->tag[i] != '$')
                i--;
            j = doc->cur_col + 1;
            while (j < doc_ce->max_col && doc_ce->tag[j] != '$')
                j++;
            if (i < j - 1 && doc_ce->min_col <= i < j < doc_ce->max_col && doc_ce->tag[i] == '$' && doc_ce->tag[j] == '$')
            {
                ch = doc_ce->tag[j + 1];
                doc_ce->tag[j + 1] = 0;
                st = StrNew(doc_ce->tag + i);
                doc_ce->tag[j + 1] = ch;
                StrCopy(doc_ce->tag + i, doc_ce->tag + j + 1);
                doc->cur_col = i;
                st2 = MStrPrint("%q", st);
                if (doc_ce = DocPrint(doc, st2))
                {
                    doc->cur_entry  = doc_ce;
                    doc->cur_col    = doc_ce->min_col;
                }
                Free(st);
                Free(st2);
            }
        }
        else
        {
            old_color_names = LBts(&doc->flags, DOCf_COLOR_NAMES);
            st = Doc2PlainText(doc, doc_ce);
            LBEqual(&doc->flags, DOCf_COLOR_NAMES, old_color_names);
            DocEntryDel(doc, doc_ce);
            DocPrint(doc, "$$%$Q$$", st);
        }
        DocRecalc(doc);
    }
    if (unlock)
        DocUnlock(doc);
}

U0 DocFlagsToggle(CDoc *doc, I64 tog_flags)
{
    Bool         unlock = DocLock(doc);
    I64          size, flags = doc->flags ^ tog_flags;
    U8          *st;
    CDocUndo    *u_next, *u_last;

    doc->flags = doc->flags & ~DOCF_NO_CURSOR | DOCF_COLOR_NAMES;
    st = DocSave(doc, &size);

    u_next = doc->undo_head.next;
    u_last = doc->undo_head.last;
    doc->undo_head.next = doc->undo_head.last = &doc->undo_head;

    DocReset(doc, TRUE);
    doc->undo_head.next = u_next;
    doc->undo_head.last = u_last;
    DocUndoCountSet(doc);
    doc->flags = flags & ~(DOCF_NO_CURSOR | DOCG_BL_IV_UL | DOCF_WORD_WRAP);
    DocLoad(doc, st, size);
    doc->flags |= flags & DOCF_NO_CURSOR;
    DocCenter(doc);
    if (unlock)
        DocUnlock(doc);
    Free(st);
}