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;
}