xeij/DebugConsole.java
//========================================================================================
//  DebugConsole.java
//    en:Debug console -- An interactive debugger
//    ja:デバッグコンソール -- 対話型デバッガ
//  Copyright (C) 2003-2025 Makoto Kamada
//
//  This file is part of the XEiJ (X68000 Emulator in Java).
//  You can use, modify and redistribute the XEiJ if the conditions are met.
//  Read the XEiJ License for more details.
//  https://stdkmd.net/xeij/
//========================================================================================

package xeij;

import java.awt.*;  //BasicStroke,BorderLayout,BoxLayout,Color,Component,Container,Cursor,Desktop,Dimension,Font,FlowLayout,Frame,Graphics,Graphics2D,GraphicsDevice,GraphicsEnvironment,GridLayout,Image,Insets,Paint,Point,Rectangle,RenderingHints,Robot,Shape,Stroke,TexturePaint,Toolkit
import java.awt.datatransfer.*;  //Clipboard,DataFlavor,FlavorEvent,FlavorListener,Transferable,UnsupportedFlavorException
import java.awt.event.*;  //ActionEvent,ActionListener,ComponentAdapter,ComponentEvent,ComponentListener,FocusAdapter,FocusEvent,FocusListener,InputEvent,KeyAdapter,KeyEvent,KeyListener,MouseAdapter,MouseEvent,MouseListener,MouseMotionAdapter,MouseWheelEvent,WindowAdapter,WindowEvent,WindowListener,WindowStateListener
import java.lang.*;  //Boolean,Character,Class,Comparable,Double,Exception,Float,IllegalArgumentException,Integer,Long,Math,Number,Object,Runnable,SecurityException,String,StringBuilder,System
import java.util.*;  //ArrayList,Arrays,Calendar,GregorianCalendar,HashMap,Map,Map.Entry,LinkedList,TimeZone,Timer,TimerTask,TreeMap
import javax.swing.*;  //AbstractButton,AbstractSpinnerModel,Box,ButtonGroup,DefaultListModel,ImageIcon,JApplet,JButton,JCheckBox,JCheckBoxMenuItem,JComponent,JDialog,JFileChooser,JFrame,JLabel,JList,JMenu,JMenuBar,JMenuItem,JPanel,JRadioButton,JScrollPane,JSpinner,JTextArea,JTextField,JTextPane,JViewport,ScrollPaneConstants,SpinnerListModel,SpinnerNumberModel,SwingConstants,SwingUtilities,UIManager,UIDefaults,UnsupportedLookAndFeelException
import javax.swing.event.*;  //CaretEvent,CaretListener,ChangeEvent,ChangeListener,DocumentEvent,DocumentListener,ListSelectionListener

public class DebugConsole {

  public static final int DGT_MAX_OUTPUT_LENGTH = 1024 * 1024;  //出力の上限を1MBとする
  public static final int DGT_CUT_OUTPUT_LENGTH = DGT_MAX_OUTPUT_LENGTH + 1024 * 64;  //出力が上限よりも64KB以上長くなったら上限でカットする

  //入力モード
  public static final int DGT_INPUT_MODE_COMMAND   = 1;  //コマンドモード
  public static final int DGT_INPUT_MODE_PAGE      = 2;  //ページモード
  public static final int DGT_INPUT_MODE_ASSEMBLER = 3;  //アセンブラモード
  public static int dgtInputMode;  //入力モード
  public static LinkedList<String> dgtPageList;

  //プロンプト
  public static final String DGT_COMMAND_PROMPT = "> ";
  public static final String DGT_PAGE_PROMPT = "-- more -- [y/n] ";
  public static String dgtCurrentPrompt;  //現在のプロンプト

  //コンポーネント
  public static JFrame dgtFrame;  //ウインドウ
  public static ScrollTextArea dgtBoard;  //テキストエリア
  public static JPopupMenu dgtPopupMenu;  //ポップアップメニュー
  public static JMenuItem dgtPopupCutMenuItem;  //切り取り
  public static JMenuItem dgtPopupCopyMenuItem;  //コピー
  public static JMenuItem dgtPopupPasteMenuItem;  //貼り付け
  public static JMenuItem dgtPopupSelectAllMenuItem;  //すべて選択
  public static int dgtOutputEnd;  //出力された文字列の末尾。リターンキーが押されたらこれ以降に書かれた文字列をまとめて入力する

  //コアが停止したときコンソールに何を表示するか
  //  bit0  整数レジスタを表示する
  //  bit1  浮動小数点レジスタを表示する
  //  bit2  プロンプトを表示する。レジスタの表示を繰り返すときは最終回だけセットする
  public static volatile int dgtRequestRegs;

  //アセンブル
  public static int dgtAssemblePC;  //次にアセンブルするアドレス
  public static int dgtAssembleFC;  //次にアセンブルするファンクションコード

  //逆アセンブル
  public static int dgtDisassembleLastTail;  //前回逆アセンブルした範囲の終了アドレス
  public static int dgtDisassemblePC;  //前回逆アセンブルした範囲の直後のアドレス。0=PCを使う
  public static int dgtDisassembleFC;  //前回逆アセンブルした範囲のファンクションコード

  //ダンプ
  public static int dgtDumpAddress;  //次回のダンプ開始アドレス
  public static int dgtDumpFunctionCode;  //ファンクションコード
  public static int dgtDumpStraddleChar;  //2行に跨る文字

  //dgtInit ()
  //  デバッグコンソールを初期化する
  public static void dgtInit () {
    dgtInputMode = DGT_INPUT_MODE_COMMAND;
    dgtPageList = null;
    dgtCurrentPrompt = DGT_COMMAND_PROMPT;
    dgtFrame = null;
    dgtBoard = null;
    dgtPopupMenu = null;
    dgtPopupCutMenuItem = null;
    dgtPopupCopyMenuItem = null;
    dgtPopupPasteMenuItem = null;
    dgtPopupSelectAllMenuItem = null;
    dgtOutputEnd = dgtCurrentPrompt.length ();
    dgtRequestRegs = 0;
    dgtAssemblePC = 0;
    dgtAssembleFC = 6;
    dgtDisassembleLastTail = 0;
    dgtDisassemblePC = 0;
    dgtDisassembleFC = 6;
    dgtDumpAddress = 0;
    dgtDumpFunctionCode = 5;
    dgtDumpStraddleChar = 0;
  }  //dgtInit()

  //dgtMake ()
  //  デバッグコンソールを作る
  //  ここでは開かない
  public static void dgtMake () {

    //テキストエリア
    String initialText = (Multilingual.mlnJapanese ?
                          "[ h で使用法を表示]\n" :
                          "[enter h to display usage]\n") + dgtCurrentPrompt;
    dgtOutputEnd = initialText.length ();
    dgtBoard = ComponentFactory.createScrollTextArea (initialText, 500, 600, true);
    dgtBoard.setUnderlineCursorOn (true);
    dgtBoard.setLineWrap (true);  //行を折り返す
    dgtBoard.addDocumentListener (new DocumentListener () {
      @Override public void changedUpdate (DocumentEvent de) {
      }
      @Override public void insertUpdate (DocumentEvent de) {
        if (de.getOffset () < dgtOutputEnd) {
          dgtOutputEnd += de.getLength ();  //出力された文字列の末尾を調整する
        }
      }
      @Override public void removeUpdate (DocumentEvent de) {
        if (de.getOffset () < dgtOutputEnd) {
          dgtOutputEnd -= Math.min (de.getLength (), dgtOutputEnd - de.getOffset ());  //出力された文字列の末尾を調整する
        }
      }
    });
    dgtBoard.addKeyListener (new KeyAdapter () {
      @Override public void keyPressed (KeyEvent ke) {
        int code = ke.getKeyCode ();
        int modifiersEx = ke.getModifiersEx ();
        if (code == KeyEvent.VK_ENTER &&  //Enterキーが押された
            (modifiersEx & (InputEvent.ALT_DOWN_MASK |
                            InputEvent.CTRL_DOWN_MASK |
                            InputEvent.META_DOWN_MASK)) == 0) {  //Altキー,Ctrlキー,Metaキーが押されていない
          if ((modifiersEx & InputEvent.SHIFT_DOWN_MASK) == 0) {  //Shiftキーが押されていない
            ke.consume ();  //Enterキーをキャンセルする
            //Enterキーを処理する
            dgtEnter ();
          } else {  //Shiftキーが押されている
            ke.consume ();  //Enterキーをキャンセルする。デフォルトのShift+Enterの機能を無効化する
            //改行を挿入する
            dgtBoard.replaceRange ("\n", dgtBoard.getSelectionStart (), dgtBoard.getSelectionEnd ());
          }
        }
      }
    });

    //ポップアップメニュー
    ActionListener popupActionListener = new ActionListener () {
      @Override public void actionPerformed (ActionEvent ae) {
        switch (ae.getActionCommand ()) {
        case "Cut":
          dgtCut ();
          break;
        case "Copy":
          dgtCopy ();
          break;
        case "Paste":
          dgtPaste ();
          break;
        case "Select All":
          dgtSelectAll ();
          break;
        }
      }
    };
    dgtPopupMenu = ComponentFactory.createPopupMenu (
      dgtPopupCutMenuItem = Multilingual.mlnText (ComponentFactory.createMenuItem ("Cut", 'T', popupActionListener), "ja", "切り取り"),
      dgtPopupCopyMenuItem = Multilingual.mlnText (ComponentFactory.createMenuItem ("Copy", 'C', popupActionListener), "ja", "コピー"),
      dgtPopupPasteMenuItem = Multilingual.mlnText (ComponentFactory.createMenuItem ("Paste", 'P', popupActionListener), "ja", "貼り付け"),
      ComponentFactory.createHorizontalSeparator (),
      dgtPopupSelectAllMenuItem = Multilingual.mlnText (ComponentFactory.createMenuItem ("Select All", 'A', popupActionListener), "ja", "すべて選択")
      );
    dgtBoard.addMouseListener (new MouseAdapter () {
      @Override public void mousePressed (MouseEvent me) {
        dgtShowPopup (me);
      }
      @Override public void mouseReleased (MouseEvent me) {
        dgtShowPopup (me);
      }
    });

    //ウインドウ
    dgtFrame = Multilingual.mlnTitle (
      ComponentFactory.createRestorableSubFrame (
        Settings.SGS_DGT_FRAME_KEY,
        "Console",
        null,
        dgtBoard
        ),
      "ja", "コンソール");

    dgtBoard.setCaretPosition (dgtOutputEnd);

  }  //dgtMake()

  //dgtShowPopup (me)
  //  ポップアップメニューを表示する
  //  テキストエリアのマウスリスナーが呼び出す
  public static void dgtShowPopup (MouseEvent me) {
    if (me.isPopupTrigger ()) {
      //選択範囲があれば切り取りとコピーが有効
      boolean enableCutAndCopy = XEiJ.clpClipboard != null && dgtBoard.getSelectionStart () != dgtBoard.getSelectionEnd ();
      ComponentFactory.setEnabled (dgtPopupCutMenuItem, enableCutAndCopy);
      ComponentFactory.setEnabled (dgtPopupCopyMenuItem, enableCutAndCopy);
      //クリップボードに文字列があれば貼り付けが有効
      ComponentFactory.setEnabled (dgtPopupPasteMenuItem, XEiJ.clpClipboard != null && XEiJ.clpClipboard.isDataFlavorAvailable (DataFlavor.stringFlavor));
      //クリップボードがあればすべて選択が有効
      ComponentFactory.setEnabled (dgtPopupSelectAllMenuItem, XEiJ.clpClipboard != null);
      //ポップアップメニューを表示する
      dgtPopupMenu.show (me.getComponent (), me.getX (), me.getY ());
    }
  }  //dgtShowPopup(MouseEvent)

  //dgtCut ()
  //  切り取り
  public static void dgtCut () {
    if (XEiJ.clpClipboard != null) {
      //選択範囲の文字列をコピーする
      XEiJ.clpClipboardString = dgtBoard.getSelectedText ();
      try {
        XEiJ.clpClipboard.setContents (XEiJ.clpStringContents, XEiJ.clpClipboardOwner);
        XEiJ.clpIsClipboardOwner = true;  //自分がコピーした
      } catch (Exception e) {
        return;
      }
      //選択範囲の文字列を削除する
      dgtBoard.replaceRange ("", dgtBoard.getSelectionStart (), dgtBoard.getSelectionEnd ());
    }
  }  //dgtCut()

  //dgtCopy ()
  //  コピー
  public static void dgtCopy () {
    if (XEiJ.clpClipboard != null) {
      //選択範囲の文字列をコピーする
      String selectedText = dgtBoard.getSelectedText ();
      if (selectedText != null) {
        XEiJ.clpClipboardString = selectedText;
        try {
          XEiJ.clpClipboard.setContents (XEiJ.clpStringContents, XEiJ.clpClipboardOwner);
          XEiJ.clpIsClipboardOwner = true;  //自分がコピーした
        } catch (Exception e) {
          return;
        }
      }
    }
  }  //dgtCopy()

  //dgtPaste ()
  //  貼り付け
  public static void dgtPaste () {
    if (XEiJ.clpClipboard != null) {
      //クリップボードから文字列を取り出す
      String string = null;
      try {
        string = (String) XEiJ.clpClipboard.getData (DataFlavor.stringFlavor);
      } catch (Exception e) {
        return;
      }
      //選択範囲の文字列を置換する
      dgtBoard.replaceRange (string, dgtBoard.getSelectionStart (), dgtBoard.getSelectionEnd ());
    }
  }  //dgtPaste()

  //dgtSelectAll ()
  //  すべて選択
  public static void dgtSelectAll () {
    if (XEiJ.clpClipboard != null) {
      //すべて選択する
      dgtBoard.selectAll ();
    }
  }  //dgtSelectAll()

  //dgtStart ()
  public static void dgtStart () {
    if (RestorableFrame.rfmGetOpened (Settings.SGS_DGT_FRAME_KEY)) {
      dgtOpen ();
    }
  }  //dgtStart()

  //dgtOpen ()
  //  デバッグコンソールを開く
  public static void dgtOpen () {
    if (dgtFrame == null) {
      dgtMake ();
    }
    XEiJ.pnlExitFullScreen (false);
    dgtFrame.setVisible (true);
  }  //dgtOpen()

  //dgtPrintChar (c)
  //  末尾に1文字追加する
  public static void dgtPrintChar (int c) {
    if (c == 0x08) {  //バックスペース
      if (0 < dgtOutputEnd) {
        if (dgtBoard != null) {
          dgtBoard.replaceRange ("", dgtOutputEnd - 1, dgtOutputEnd);  //1文字削除
          dgtOutputEnd--;
          dgtBoard.setCaretPosition (dgtOutputEnd);
        }
      }
    } else if (0x20 <= c && c != 0x7f || c == 0x09 || c == 0x0a) {  //タブと改行以外の制御コードを除く
      if (dgtBoard != null) {
        dgtBoard.insert (String.valueOf ((char) c), dgtOutputEnd);  //1文字追加
        dgtOutputEnd++;
        if (DGT_CUT_OUTPUT_LENGTH <= dgtOutputEnd) {
          dgtBoard.replaceRange ("", 0, dgtOutputEnd - DGT_MAX_OUTPUT_LENGTH);  //先頭を削って短くする
          dgtOutputEnd = DGT_MAX_OUTPUT_LENGTH;
        }
        dgtBoard.setCaretPosition (dgtOutputEnd);
      }
    }
  }  //dgtPrintChar(int)

  //dgtPrint (s)
  //  末尾に文字列を追加する
  //  制御コードを処理しないのでタブと改行以外の制御コードを含めないこと
  public static void dgtPrint (String s) {
    if (s == null) {
      return;
    }
    if (dgtFrame != null) {
      dgtBoard.insert (s, dgtOutputEnd);  //文字列追加
      dgtOutputEnd += s.length ();
      if (DGT_CUT_OUTPUT_LENGTH <= dgtOutputEnd) {
        dgtBoard.replaceRange ("", 0, dgtOutputEnd - DGT_MAX_OUTPUT_LENGTH);  //先頭を削って短くする
        dgtOutputEnd = DGT_MAX_OUTPUT_LENGTH;
      }
      dgtBoard.setCaretPosition (dgtOutputEnd);
    }
  }  //dgtPrint(String)

  //dgtPrintln (s)
  //  末尾に文字列と改行を追加する
  //  制御コードを処理しないのでタブと改行以外の制御コードを含めないこと
  public static void dgtPrintln (String s) {
    dgtPrint (s);
    dgtPrintChar ('\n');
  }  //dgtPrintln(String)

  //dgtEnter ()
  //  Enterキーを処理する
  public static void dgtEnter () {
    String text = dgtBoard.getText ();  //テキスト全体
    int length = text.length ();  //テキスト全体の長さ
    int outputLineStart = text.lastIndexOf ('\n', dgtOutputEnd - 1) + 1;  //出力の末尾の行の先頭。プロンプトの先頭
    int caretLineStart = text.lastIndexOf ('\n', dgtBoard.getCaretPosition () - 1) + 1;  //キャレットがある行の先頭
    if (outputLineStart <= caretLineStart) {  //出力の末尾の行の先頭以降でEnterキーが押された
      dgtBoard.replaceRange ("", dgtOutputEnd, length);  //入力された文字列を一旦削除する
      dgtSend (text.substring (dgtOutputEnd, length));  //入力された文字列を送信する
    } else if (outputLineStart < dgtOutputEnd) {  //出力の末尾の行の先頭よりも手前でEnterキーが押されて、出力の末尾の行にプロンプトがあるとき
      String prompt = text.substring (outputLineStart, dgtOutputEnd);  //出力の末尾の行のプロンプト
      int caretLineEnd = text.indexOf ('\n', caretLineStart);  //キャレットがある行の末尾
      if (caretLineEnd == -1) {
        caretLineEnd = length;
      }
      String line = text.substring (caretLineStart, caretLineEnd);  //キャレットがある行
      int start = line.indexOf (prompt);  //キャレットがある行のプロンプトの先頭
      if (0 <= start) {  //キャレットがある行にプロンプトがあるとき
        dgtOutputEnd = length;  //入力された文字列を無効化する
        if (text.charAt (dgtOutputEnd - 1) != '\n' && !text.endsWith ("\n" + prompt)) {  //改行または改行+プロンプトで終わっていないとき
          dgtBoard.insert ("\n", dgtOutputEnd);  //末尾に改行を追加する
          dgtOutputEnd++;
          if (DGT_CUT_OUTPUT_LENGTH <= dgtOutputEnd) {
            dgtBoard.replaceRange ("", 0, dgtOutputEnd - DGT_MAX_OUTPUT_LENGTH);  //先頭を削って短くする
            dgtOutputEnd = DGT_MAX_OUTPUT_LENGTH;
          }
        }
        dgtBoard.setCaretPosition (dgtOutputEnd);
        dgtSend (line.substring (start + prompt.length ()));  //プロンプトの後ろから行の末尾までを送信する
      }
    }
  }  //dgtEnter()

  //dgtSend (s)
  //  入力された文字列を処理する
  public static void dgtSend (String s) {
    dgtPrintln (s);
    if (dgtInputMode == DGT_INPUT_MODE_COMMAND) {  //コマンドモード
      ExpressionEvaluator.ExpressionElement nodeTree = XEiJ.fpuBox.evxParse (s, ExpressionEvaluator.EVM_COMMAND);
      if (nodeTree != null) {
        nodeTree.exlEval (ExpressionEvaluator.EVM_COMMAND);
        if (nodeTree.exlValueType == ExpressionEvaluator.ElementType.ETY_FLOAT) {
          dgtPrintln (nodeTree.exlFloatValue.toString ());
        } else if (nodeTree.exlValueType == ExpressionEvaluator.ElementType.ETY_STRING) {
          dgtPrintln (nodeTree.exlStringValue);
        }
      }
    } else if (dgtInputMode == DGT_INPUT_MODE_PAGE) {  //ページモード
      if (!(s.equals ("") ||
            s.toLowerCase ().startsWith (" ") ||
            s.toLowerCase ().startsWith ("y"))) {
        dgtPageList = null;
      }
      dgtPrintPage ();
    } else if (dgtInputMode == DGT_INPUT_MODE_ASSEMBLER) {  //アセンブラモード
      if (s.equals (".")) {  //コマンドモードに戻る
        dgtInputMode = DGT_INPUT_MODE_COMMAND;
        dgtCurrentPrompt = DGT_COMMAND_PROMPT;
      } else {  //アセンブルする
        byte[] binary = Assembler.asmAssemble (dgtAssemblePC, s);
        if (binary != null && 0 < binary.length) {  //バイナリがある
          for (int i = 0; i < binary.length; i++) {
            MC68060.mmuPokeByte (dgtAssemblePC + i, binary[i], dgtAssembleFC);
          }
          //逆アセンブルする
          int itemAddress = dgtAssemblePC;
          dgtAssemblePC += binary.length;
          dgtMakeAssemblerPrompt ();
          int supervisor = DebugConsole.dgtAssembleFC & 4;
          StringBuilder sb = new StringBuilder ();
          while (itemAddress < dgtAssemblePC) {
            String code = Disassembler.disDisassemble (new StringBuilder (), itemAddress, supervisor).toString ();
            int itemEndAddress = Disassembler.disPC;
            if (dgtAssemblePC < itemEndAddress) {  //アセンブルした範囲からはみ出すときdc.wに置き換える
              itemEndAddress = dgtAssemblePC;
              StringBuilder sb2 = new StringBuilder ();
              sb2.append ("dc.w    ");
              for (int a = itemAddress; a < itemEndAddress; a += 2) {
                if (itemAddress < a) {
                  sb2.append (',');
                }
                XEiJ.fmtHex4 (sb2.append ('$'), MC68060.mmuPeekWordZeroCode (a, supervisor));
              }
              code = sb2.toString ();
            }
            //1行目
            int lineAddress = itemAddress;  //行の開始アドレス
            int lineEndAddress = Math.min (lineAddress + 10, itemEndAddress);  //行の終了アドレス
            //アドレス
            XEiJ.fmtHex8 (sb, lineAddress).append ("  ");
            //データ
            for (int a = lineAddress; a < lineEndAddress; a += 2) {
              XEiJ.fmtHex4 (sb, MC68060.mmuPeekWordZeroCode (a, supervisor));
            }
            sb.append (XEiJ.DBG_SPACES, 0, 2 * Math.max (0, lineAddress + 10 - lineEndAddress) + 2);
            //逆アセンブル結果
            sb.append (code).append ('\n');
            //2行目以降
            while (lineEndAddress < itemEndAddress) {
              lineAddress = lineEndAddress;  //行の開始アドレス
              lineEndAddress = Math.min (lineAddress + 10, itemEndAddress);  //行の終了アドレス
              //アドレス
              XEiJ.fmtHex8 (sb, lineAddress).append ("  ");
              //データ
              for (int a = lineAddress; a < lineEndAddress; a += 2) {
                XEiJ.fmtHex4 (sb, MC68060.mmuPeekWordZeroCode (a, supervisor));
              }
              sb.append ('\n');
            }  //while
            itemAddress = itemEndAddress;
          }  //while itemAddress<dgtAssemblePC
          dgtPrint (sb.toString ());
        }  //if バイナリがある
      }  //if コマンドモードに戻る/アセンブルする
    }  //if コマンドモード/ページモード/アセンブラモード
    if (dgtRequestRegs == 0) {
      dgtPrintPrompt ();
    }
  }  //dgtSend(String)

  //dgtMakeAssemblerPrompt ()
  //  アセンブラモードのプロンプトを作る
  public static void dgtMakeAssemblerPrompt () {
    StringBuilder sb = XEiJ.fmtHex8 (new StringBuilder (), dgtAssemblePC);
    if (Model.MPU_MC68LC040 <= XEiJ.currentMPU) {
      sb.append ('@').append (dgtAssembleFC);
    }
    dgtCurrentPrompt = sb.append ("  ").toString ();
  }  //dgtMakeAssemblerPrompt()

  //dgtPrintPrompt (s)
  //  プロンプトを表示する
  //  既に表示されているときは何もしない
  public static void dgtPrintPrompt () {
    String text = dgtBoard.getText ();  //テキスト全体
    if (!text.substring (text.lastIndexOf ('\n', dgtOutputEnd - 1) + 1, dgtOutputEnd).equals (dgtCurrentPrompt)) {  //プロンプトが表示されていない
      dgtPrint (text.endsWith ("\n") ? dgtCurrentPrompt : "\n" + dgtCurrentPrompt);
    }
  }  //dgtPrintPrompt()

  //dgtPrintPage ()
  //  ページを表示する
  public static void dgtPrintPage () {
    if (dgtPageList != null && !dgtPageList.isEmpty ()) {  //ページがある
      dgtPrint (dgtPageList.pollFirst ());
      if (!dgtPageList.isEmpty ()) {  //次のページがある
        //ページモードに移行する
        DebugConsole.dgtInputMode = DebugConsole.DGT_INPUT_MODE_PAGE;
        dgtCurrentPrompt = DGT_PAGE_PROMPT;
      }
    }
    if (dgtPageList == null || dgtPageList.isEmpty ()) {  //ページがない
      dgtPageList = null;
      //コマンドモードに戻る
      dgtInputMode = DGT_INPUT_MODE_COMMAND;
      dgtCurrentPrompt = DGT_COMMAND_PROMPT;
    }
    dgtPrintPrompt ();
  }  //dgtPrintPage()

}  //class DebugConsole