extern U0 BgtRegen();

Bool BgtPutKey(CDoc *doc, U8 *, I64 ch, I64 sc)
{//ch=ASCII; sc=scan_code
    no_warn sc;

    CBgtEntry       *tmpb, *tmpb1;
    CBgtTemplate    *tmpt, *tmpt1;
    CDocEntry       *doc_ce;
    U8              *st;

    switch (ch)
    {
        case '\n':
            if ((doc_ce = doc->cur_entry) && doc_ce != doc && doc_ce->type_u8 == DOCT_MENU_VAL)
            {
                tmpb = doc_ce->user_data;
                if (tmpt = tmpb->template)
                {
                    if (tmpt1 = BgtTemplatePrompt(tmpt))
                    {
                        QueueRemove(tmpt);
                        BgtTemplatePurge(tmpt);
                        BgtEntryDel2(&tmpt->b);
                        Free(tmpt);
                        QueueInsert(tmpt1, t_head.last);
                        BgtTemplateExpand(tmpt1);
                        BgtRegen;
                    }
                }
                else
                {
                    if (tmpb1=BgtEntryPrompt(tmpb))
                    {
                        QueueRemove(tmpb);
                        BgtEntryDel(tmpb);
                        BgtIns(tmpb1);
                        BgtRegen;
                    }
                }
            }
            return TRUE;

        case CH_CTRLY:
            if ((doc_ce = doc->cur_entry) && doc_ce != doc && doc_ce->type_u8 == DOCT_MENU_VAL)
            {
                tmpb = doc_ce->user_data;
                if (tmpt = tmpb->template)
                {
                    QueueRemove(tmpt);
                    BgtTemplateDel(tmpt);
                }
                else
                {
                    QueueRemove(tmpb);
                    BgtEntryDel(tmpb);
                }
                BgtRegen;
            }
            return TRUE;

        case 'a':
            PopUpOk("Set the name and color of your accounts.\n"
                    "To delete accounts, manually edit\n"
                    "$GREEN$~/Budget/Accts.DD$FG$.");
            if (PopUpEd(bgt_accts_file, Fs))
            {
                BgtAcctsRead;
                BgtRegen;
            }
            return TRUE;

        case 'v':
            if ((st = BgtPopUpAcct("View Acct\n\n", view_acct)) >= 0)
            {
                StrCopy(view_acct, st);
                BgtRegen;
            }
            return TRUE;

        case 'n':
            if (tmpb1 = BgtEntryPrompt)
            {
                BgtIns(tmpb1);
                BgtRegen;
            }
            return TRUE;

        case 't':
            if (tmpt1 = BgtTemplatePrompt)
            {
                QueueInsert(tmpt1, t_head.last);
                BgtTemplateExpand(tmpt1);
                BgtRegen;
            }
            return TRUE;

        case 'c':
            if ((doc_ce = doc->cur_entry) && doc_ce != doc && doc_ce->type_u8 == DOCT_MENU_VAL)
                tmpb = doc_ce->user_data;
            else
                tmpb = NULL;
            if (tmpb1 = BgtEntryPrompt(tmpb))
            {
                BgtIns(tmpb1);
                BgtRegen;
            }
            return TRUE;

        case 'p':
            if ((doc_ce = doc->cur_entry) && doc_ce != doc && doc_ce->type_u8 == DOCT_MENU_VAL)
            {
                tmpb = doc_ce->user_data;
                if (tmpt1=BgtTemplatePrompt(, tmpb))
                {
                    BgtTemplateExpand(tmpt1, TRUE);
                    BgtTemplateDel(tmpt1);
                    BgtRegen;
                }
            }
            return TRUE;
    }

    return FALSE;
}

U0 BgtRegen()
{
    I64          timeout_jiffy, c, color = COLOR_INVALID;
    F64          balance = 0;
    CDoc        *doc, *pdoc, *ddoc;
    CDocEntry   *doc_ce;
    CBgtEntry   *tmpb = b_head.next, *tmpb_ce;

    doc = DocNew;
    doc->flags |= DOCF_FORM;
    while (tmpb != &b_head)
    {
        if (!StrCompare(view_acct, tmpb->credit))
            balance -= tmpb->amount;
        if (!StrCompare(view_acct, tmpb->debit))
            balance += tmpb->amount;
        c=BgtAcctColor(tmpb->credit);
        if (c != color)
        {
            color = c;
            DocPrint(doc, "$FG,%d$", color);
        }
        tmpb->doc_e = DocPrint(doc, "$MU-UL,\"%D %8ts %8ts:%8.2f %8.2f:%$Q\",U=0x%X$\n", 
                                tmpb->date, tmpb->credit, tmpb->debit, balance, tmpb->amount, tmpb->desc, tmpb);
        tmpb = tmpb->next;
    }
    DocRecalc(doc);

    if (pdoc = Fs->put_doc)
    {
        DocLock(pdoc);
        //Now, we want to preserve old position in doc, using ugly brute force.
        //It's tricky -- can't use old line num because of editor filters.

        //The price we pay for using the standard document editor is this kludge.
        //When Terry originally wrote the budget program, he did not have separate budget
        //and line entries, so we never had to resync.

        doc_ce = pdoc->cur_entry;
        timeout_jiffy = counts.jiffies + JIFFY_FREQ; //Max one second.
        while (doc_ce != pdoc && counts.jiffies < timeout_jiffy)
        {
            while (doc_ce->type_u8 != DOCT_MENU_VAL || !(tmpb_ce = doc_ce->user_data))
            {
                doc_ce = doc_ce->next;
                if (doc_ce == pdoc)
                    goto br_cont;
            }
            tmpb = b_head.next;
            while (tmpb != &b_head)
            {
                if (tmpb == tmpb_ce)
                {
                    doc->cur_entry = tmpb->doc_e;
                    doc->cur_col = 0;
                    DocCenter(doc);
                    goto br_cont;
                }
                tmpb = tmpb->next;
            }
            doc_ce = doc_ce->next;
        }
    }

    br_cont:
    ddoc = Fs->display_doc;
    Fs->put_doc      =doc;
    Fs->display_doc=doc;
    DocDel(pdoc);
    if (pdoc != ddoc)
        DocDel(ddoc);
    doc->user_put_key = &BgtPutKey;
}

U0 Budget(U8 *dirname="~/Budget")
{
    CDoc *pdoc, *ddoc, *old_put, *old_display;

    Cd(dirname);
    bgt_string_file = FileNameAbs("Strs.DD");
    bgt_accts_file  = FileNameAbs("Accts.DD");
    bgt_data_file   = FileNameAbs("Bgt.DATA");

    BgtAcctsRead;
    BgtDataRead;
    CBgtTemplatesExpand;
    SettingsPush; //See SettingsPush
    AutoComplete;
    WinBorder;
    WinMax;
    MenuPush(   "File {"
                "  Abort(,CH_SHIFT_ESC);"
                "  Exit(,CH_ESC);"
                "}"
                "Edit {"
                "  NewEntry(,'n');"
                "  CopyEntry(,'c');"
                "  PeriodicEntry(,'p');"
                "  EditEntry(,'\n');"
                "  DeleteEntry(,CH_CTRLY);"
                "  NewTemplate(,'t');"
                "  AcctsFile(,'a');"
                "}"
                "View {"
                "  ViewAcct(,'v');"
                "}"
                );
    StrCopy(view_acct, "BANK");
    DocMax;
    old_put     = Fs->put_doc;
    old_display = Fs->display_doc;
    Fs->put_doc = NULL;
    Fs->display_doc = NULL;
    BgtRegen;
    try
        if (View)
        {
            BgtDataWrite;
            BgtAcctsWrite;
        }
    catch
        PutExcept;

    pdoc = Fs->put_doc;
    ddoc = Fs->display_doc;
    Fs->put_doc     = old_put;
    Fs->display_doc = old_display;
    DocDel(pdoc);
    if (pdoc != ddoc)
        DocDel(ddoc);

    SettingsPop;
    BgtDel;
    MenuPop;
}