/* CLI Presenter; controls the transcript and edit windows */!!

inherit(AutomaticMenu, #CliPresenterWindow, #(hEdit  /* handle for edit window */
hTrans /* handle for transcript window */
hPrompt /* handle for prompt window */
hSplit /* handle for split window */
logFile  /* log file handle */
logFileName /* log file name */
logging  /* true if logging */
historySize /* number of history cmds saved */
cliServer  /* cli server object */
promptString /* prompt string */
initComplete /* true if init has completed */
debugText /* debug text collection */
promptBorder /* prompt / edit window border */
editWindowHeight /* height of edit window */
screenPainted /* true if first screen painted */
focusWindow /* 0:transcript, 1:edit */
showCommand /* show entered command? */
showResults /* show results? */
terminating  /* true if terminating */
exitFlag  /* set if exit command executed */
appendToLog /* T if append, F if overwriting */
closePending /* T if close deferred to non-critical region of code */), 2, nil)!!

now(class(CliPresenterWindow))!!

/* start presenter; use saved size, or system system default size */
Def open(self | tmp)
{
  ^openWithPositionAndState(self,
     getPos(PreLauncher, "TheShellPresenter"),
     getShowState(PreLauncher, "TheShellPresenter"));
} 
!!

/* start server if necessary, then start presenter with specific position */
Def openWithPosition(self, sizeRect | tempServer, tempPresenter)
{
  ^openWithPosAndState(self, sizeRect, SW_SHOWNORMAL);
} 
!!

/* start server if necessary, then start presenter with specific position */
Def openWithPosAndState(self sizeRect showVal| tempServer tempPresenter)
{
  /* start server if it isn't already running */
  if (not(getCliServerObject(CliServer)))
    tempServer := defaultNew(CliServer, "Don't Display");
  endif;
  
  /* start presenter */
  tempPresenter := newStyle(CliPresenterWindow, nil, nil,
                "Shell", sizeRect, nil,
                WS_OVERLAPPEDWINDOW);
  initialize(tempPresenter);
  show(tempPresenter, showVal);

  ^tempPresenter
}
!!




Def wndClass(self)
{ ^"CliPresenter"
}!!

/* return name of cli icon */
Def wndIcon(self)
{ ^"CLI" }!!

now(CliPresenterWindow)!!

/* 10/4/1993 17:50 */
Def processStartupFile(self | fileName commandTextCol)
{
  if not(fileName := (startupFileNameGet(PreLauncher)))
    ^0;
  endif;

  /* clear startup file name so we don't try to do it again */
  startupFileNameClear(PreLauncher);
  
  commandTextCol := new(TextCollection, 1);
  add(commandTextCol, "include " + quote(CLIUtilities, fileName) + ";");
  executingCommandSet(hEdit);  /* show that we're running so we don't abort */
  processCommand(self, commandTextCol);
}
!!

/* set close pending (currently in critical section; must defer close). */
Def closePendingProcess(self)
{
  if closePending?(self)
    close(self);
  endif;
}
!!

/* set close pending (currently in critical section; must defer close). */
Def closePendingSet(self)
{
  closePending := 0;
}
!!

/* return true if close pending (in critical section when exit request made).
*/
Def closePending?(self)
{
  ^closePending;
}
!!

/* Menu selection Options/Overwrite. */
Def menuOptionsOverwrite(self)
{
  setAppendOff(self);
}!!

/* Menu selection Options/Append. */
Def menuOptionsAppend(self)
{
  setAppendOn(self);
}!!

/* set append on. */
Def setAppendOn(self)
{
  if append(self)
    ^0;
  endif;
  
  appendOn(self);
  unCheckMenuItem(self, "&Overwrite Log File");
  checkMenuItem(self, "&Append To Log File");
}!!

/* set append off. */
Def setAppendOff(self)
{
  if not(append(self))
    ^0;
  endif;
  
  appendOff(self);
  unCheckMenuItem(self, "&Append To Log File");
  checkMenuItem(self, "&Overwrite Log File");
}!!

/* return append */
Def append(self)
{
  ^appendToLog;
}
!!

/* set append on */
Def appendOn(self)
{
  ^appendToLog := 0;
}
!!

/* set append off */
Def appendOff(self)
{
  ^appendToLog := nil;
}
!!

/* call addHistoryCommand */
Def addHistoryCommand(self, command)
{
  ^addHistoryCommand(hEdit, command);
}
!!

/* check error code after a file operation; display error message or box */
Def checkFileError(self, file, operation, fileText, windowed |
      errorCode errorID errorText)
{
  if ((errorCode := getError(file)) = 0) then
    ^0;
  endif;

  select
    case errorCode = -1 is errorID := ER_CLI_FILE_ARG;    endCase;
    case errorCode =  2 is errorID := ER_CLI_FILE_NOT_FOUND;    endCase;
    case errorCode =  3 is errorID := ER_CLI_FILE_PATH;    endCase;
    case errorCode =  4 is errorID := ER_CLI_FILE_TOO_MANY;    endCase;
    case errorCode =  5 is errorID := ER_CLI_FILE_ACCESS;    endCase;
    case errorCode =  6 is errorID := ER_CLI_FILE_HANDLE;    endCase;
    case errorCode = 12 is errorID := ER_CLI_FILE_CODE;    endCase;
    case errorCode = 17 is errorID := ER_CLI_FILE_DEVICE;    endCase;
    default                errorID := ER_CLI_FILE_NUMBER;
                           errorText := asStringRadix(errorCode, 10);
  endSelect;

  reportFileError(self, errorID, asString(operation), asString(fileText),
     errorText, windowed);
  ^nil;
}
!!

/* clear transcript window */
Def clearTranscript(self)
{
  ^clearTranscript(hTrans);
}
!!

Def cliServer(self)
{
  ^cliServer;
}
!!

/* termination processing */
Def close(self)
{
  if not(shouldClose(self))
    ^nil;
  endif;
  
  terminating := 0;
  clearCliActive(CLIULibraryClass$Inst);
  unregisterCliPresenter(cliServer, self);
  cliServer := nil;  /* this shows we are no longer registered w/ server */
  setLoggingOff(self, nil);
  editGotFocus(self);
  close(hEdit);
  close(hTrans);
  close(hPrompt);
  hEdit := nil;
  hTrans := nil;
  hPrompt := nil;
  TheShellPresenter := nil;
  ^close(self:ancestor);
}!!

/* enable the cut and paste menu items. */
Def cutPasteEnable(self)
{ 
  enableMenuItem(self, "Cu&t");
  enableMenuItem(self, "&Paste");
  ^0;
}!!

/* gray the cut and paste menu items. */
Def cutPasteGray(self)
{ 
  grayMenuItem(self, "Cu&t");
  grayMenuItem(self, "&Paste");
  ^0;
}!!

/* Edit window has focus. */
Def editGotFocus(self)
{
  if terminating
    ^0;
  endif;
  focusWindow := 1;
  presenterGotFocus(self);
  cutPasteEnable(self);
  ^0;
}!!

/* Edit window has focus. */
Def editLostFocus(self)
{
  presenterLostFocus(self);
  focusWindow := nil;
}!!

/* 10/22/1992 8:47 */
Def exitFlag?(self)
{
  ^exitFlag;
}
!!

/* 10/22/1992 8:47 */
Def exitFlagClear(self)
{
  exitFlag := nil;
  ^0;
}
!!

/* 10/22/1992 8:47 */
Def exitFlagSet(self)
{
  exitFlag := 0;
  ^0;
}
!!

/* nil if presenter doesn't have focus; 0:transcript, 1:edit */
Def focusWindow(self)
{
  ^focusWindow;
}
!!

/* return location rectangle. */
Def getCliRect(self)
{
  ^locRect
}
!!

/* retrieve getHistoryCommand */
Def getHistoryCommand(self, index)
{
  ^getHistoryCommand(hEdit, index);
}
!!

/* retrieve getHistorySize */
Def getHistorySize(self)
{
  ^getHistorySize(hEdit);
}
!!

/* retrieve getMaxHistorySize */
Def getMaxHistorySize(self)
{
  ^getMaxHistorySize(hEdit);
}
!!

/* regained focus */
Def gotFocus(self, hWndPrev)
{
  if terminating
    ^0;
  endif;
  sizeKids(self, nil);
  presenterGotFocus(self);
}!!

/* return edit window handle */
Def hEdit(self)
{
  ^hEdit;
}!!

/* return transcript window handle */
Def hTrans(self)
{
  ^hTrans;
}!!

/* call initHistoryCommands */
Def initHistoryCommands(self)
{
  ^initHistoryCommands(hEdit);
}
!!

/* initialize two children */
Def initialize(self)
{
  terminating := nil;
  closePending := nil;
  cliServer := getCliServerObject(CliServer);
  registerCliPresenter(cliServer, self);
  logFileName := "shell.log";
  loggingOff(self);
  logFile := new(OrderedCollection, 10);
  appendOff(self);
  historySize := 0;
  promptString := ">";
  editWindowHeight := 54;  /* gives 2 lines for command entry */
  hEdit := newStyle(CliWorkspace, self, nil, "child", nil, 0,
     WS_CHILD bitOr WS_BORDER bitOr WS_VSCROLL bitOr WS_HSCROLL);
  hPrompt := newStyle(TextWindow, self, nil, "child", nil, 0,
     WS_CHILD);
  hTrans := newStyle(CliNewTranscript, self, nil, "child", nil, 0,
     WS_CHILD bitOr WS_VSCROLL bitOr WS_HSCROLL);
  hSplit := new(SplitRegion, self, nil, "split area", nil);
  
  init(hEdit);
  init(hTrans);
  init(hPrompt);
  initMenus(self);
  sizeKids(self, nil);
  show(hEdit, 1);
  show(hTrans, 1);
  show(hPrompt, 1);
  show(hSplit, 1);
  focusWindow := 1; /* hEdit */
  editGotFocus(self);
  activateWindow(hEdit);
 
  /* prepare to handle read startup file message */
  if not(UserMessages)
    UserMessages := new(Dictionary, 10);
  endif;
}!!

/* Initialize the menus. */
Def initMenus(self | aMenu)
{ 
  aMenu := new(OrderedCollection, 4);
  initMenu(self);
  add(aMenu, tuple("&File", tuple(
                 tuple("E&xit", #menuFileExit))));
  add(aMenu, tuple("&Edit", tuple(
                 tuple("Cu&t", #menuEditCut),
                 tuple("&Copy", #menuEditCopy),
                 tuple("&Paste", #menuEditPaste))));
  add(aMenu, tuple("&View", tuple(
                 tuple("&Echo Command", #menuViewCommand),
                 tuple("Show &Results", #menuViewResults),
                 tuple(nil, nil),
                 tuple("&Clear Transcript", #menuViewClear)
                 )));
  add(aMenu, tuple("&Options", tuple(
                 tuple("&Log Results", #menuOptionsLogging),
                 tuple("Log &File Name...", #menuOptionsLog),
                 tuple(nil, nil),
                 tuple("&Append To Log File", #menuOptionsAppend),
                 tuple("&Overwrite Log File", #menuOptionsOverwrite),
                 tuple(nil, nil),
                 tuple("Set &History Size...", #menuOptionsHistory))));
  
  attachMenuChoices(self,aMenu);  /* attach auto menu selections */
  
  addWindowAndHelp(self, "&Shell", HELP_ENTRY_SHELL);  /* add "Windows" and "Help" */
  registerF1Help(CLIULibraryClass$Inst, HI_ENTRY_SHELL,
     getHWnd(self), HELP_ENTRY_SHELL);
  
  if logging(self)
    checkMenuItem(self, "&Logging");
  endif;
  if append(self)
    checkMenuItem(self, "&Append To Log File");
  else
    checkMenuItem(self, "&Overwrite Log File");
  endif;
  /* initialize for interactive use */
  setResultsOn(self);
  setCommandOn(self);
  drawMenu(self);
}!!

/* Transcript window has focus. */
Def isTranscriptFocused(self)
{
  if (focusWindow = 0)
  then
    ^0;
  else
    ^nil;
  endif;
}!!

/* retrieve logFileName */
Def logFileName(self)
{
  ^logFileName;
}
!!

/* retrieve logging */
Def logging(self)
{
  ^logging;
}
!!

/* set logging off */
Def loggingOff(self)
{
  ^logging := nil;
}
!!

/* set logging on */
Def loggingOn(self)
{
  logging := 0;
}
!!

/* Write to the file. */
Def logWrite(self, text)
{
  if not(logging(self))
    ^0;
  endif;
  
  write(logFile, text);
  
  if (checkFileError(self, logFile, "write", "log file", nil) <> 0)
    setLoggingOff(self, nil);
    ^0;
  endif;
}!!

/* Menu selection edit/copy. */
Def menuEditCopy(self | value)
{
  if isTranscriptFocused(self)
  then
    value := xCopy(hTrans);
  else
    value := xCopy(hEdit);
  endif;
}!!

/* Menu selection edit/cut. */
Def menuEditCut(self)
{
  if isTranscriptFocused(self)
  then
    xCopy(hTrans);
  else
    editCut(hEdit);
  endif;
}!!

/* Menu selection edit/paste. */
Def menuEditPaste(self)
{
  if isTranscriptFocused(self)
  then
    ^0;
  else
    xPaste(hEdit);
  endif;
}!!

/* Menu selection file/exit. */
Def menuFileExit(self)
{
  close(self);
}!!

/* Menu selection Options/History. */
Def menuOptionsHistory(self | dlg inputstr count)
{ 
  loop
  while 0
  begin
    dlg := open(DlgHistory);

    setUp(dlg, asString(getMaxHistorySize(hEdit)));

    if (runModal(dlg, DLG_SHELL_HISTORY, ThePort) <> IDOK) then 
      ^GOOD;
    endif;

    /* get value */
    inputstr := getText(dlg);

    if (inputstr <> nil)
    then
      count := string2int(inputstr);
      if (count <> nil) cand setMaxHistorySize(self, count, 0)
        ^0;  /* this is the only way out */
      endif;
      
      /* bad input; cycle through again */
    endif;
  endLoop;
}
!!

/* Menu selection Options/Log. */
Def menuOptionsLog(self | inputdlg)
{
  inputdlg := new(SaveFileDialog, "*.log");
  setHelpEntry(inputdlg, HE_DLGF_LOGFILE);
  if (runModal(inputdlg, FILE_BOX, ThePort) = IDOK)
    setLogFileName(self, loadFile(inputdlg), 0);
  
    /* turn logging on */
    if not(logging(self))
      setLoggingOn(self, 0);
    endif;
  endif;
}!!

/* Menu selection Options/Logging. */
Def menuOptionsLogging(self)
{
  if logging(self)
  then
    ^setLoggingOff(self, 0);
  else
    ^setLoggingOn(self, 0);
  endif;
}!!

/* clear the transcript menu entry */
Def menuViewClear(self)
{
  ^clearTranscript(self)
}
!!

/* Menu selection View/Command. */
Def menuViewCommand(self)
{
  if showCommand(self)
  then
    setCommandOff(self);
  else
    setCommandOn(self);
  endif;
}!!

/* Menu selection View/Results. */
Def menuViewResults(self)
{
  if showResults(self)
  then
    setResultsOff(self);
  else
    setResultsOn(self);
  endif;
}!!

/* PRIVATE */
Def menuWindows(self)
{ ^menuWindows(PreLauncher) }
!!

/* a new window split received. */
Def newSplit(self, ypos)
{
  sizeKids(self, ypos);
}
!!

/* Process a single line. */
Def outputCommand(self, text)
{
  if showCommand(self)
  then
    outputLine(self, text);
  endif;
  ^0;
}!!

/* Process a single line. */
Def outputExplicit(self, text)
{
  outputLine(self, "// "+text);
  ^0;
}!!

/* PRIVATE; called through outputResults, or outputCommand */
Def outputLine(self, text)
{
  transcriptLine(self, text);
  transcriptEol(self);
  ^0;
}!!

/* Process a single line. */
Def outputResults(self, text)
{
  if showResults(self)
  then
    outputLine(self, "// "+text);
    /* Judy 3/31/97 */
    if postfix then
       put(globalVariableTable, text, "data_"+asString(postfix));
       if postfix > 1000 then
          postfix :=0;
       else
          postfix :=postfix+1;
       endif;
    endif;
    /* Judy */
  endif;
  ^0;
}!!

/* presenter window has focus. */
Def presenterGotFocus(self)
{
  /* mark CLI as active */
  if CLIULibraryClass$Inst
    setCliActive(CLIULibraryClass$Inst);
  endif;
  ^0;
}!!

/* presenter window lost focus. */
Def presenterLostFocus(self)
{ 
  focusWindow := nil;
  
  /* if not processing a command, mark CLI as inactive */
  if CLIULibraryClass$Inst cand not(executingCommand(hEdit))
    clearCliActive(CLIULibraryClass$Inst);
  endif;
  
  ^0;
}!!

/* process the completed command from the CLI Edit Window */
Def processCommand(self, command | status newCommand)
{
  deactivateWindow(hEdit);

  /* remove blank lines (there is at least one). */
  newCommand := new(TextCollection, 4);
  do(size(command),
    {using(index)
      if command[index] <> ""
      then
        add(newCommand, command[index]);
      endif;
    });
  status := processCliCommand(cliServer, self, newCommand);
  /* cli server writes to transcript */
  if not(terminating)
  then
    processCommandCleanup(self);
  endif;
}!!

/* prepare for next command */
Def processCommandCleanup(self)
{
  /* results have been printed by now */
  if eolNeeded(hTrans)
    transcriptEol(self);
  endif;
  
  serverCallFlagClear(cliServer);
  executingCommandClear(hEdit);
  cliNotBusy(cliServer);
  pendingAbortClear(cliServer);
  
  /* see if its time to exit */
  if exitFlag?(self)
    close(self);
    ^nil;
  endif;
  
  activateWindow(hEdit);
}!!


/* Make prompt invisible in prompt window */
Def promptInvisible(self)
{
  cls(hPrompt);
}
!!

/* Make prompt visible in prompt window */
Def promptVisible(self)
{
  cls(hPrompt);
  drawString(hPrompt, promptString);
}
!!

/* perform reinitialization after command processing resulted in an error. */
Def reInit(self)
{
  processCommandCleanup(self);
}
!!

/* check error code after a file operation; display error message or box */
Def reportFileError(self, errorID, operation, fileText, errorText, windowed | 
   errorMessage)
{
  if windowed then
    beep();
    displayFormattedError(ErrorTextLibClass$Inst, 
       errorID, FORCE_POPUP, operation, fileText, errorText);
  else
    errorMessage := getFormattedError(ErrorTextLibClass$Inst, 
       errorID, operation, fileText, errorText);
    if (cliServer)
      syntaxError(cliServer, nil, errorMessage);
    endif;
  endif;
  ^0;
}
!!

/* reSize just resizes the kids! */
Def reSize(self, lP, wP)
{
  sizeKids(self, nil);
}!!

/* restore settings. */
Def restoreSetup(self, filename, windowed |
      aFile temp settings index maxIndex)
{
  aFile := new(TextFile);
  setDelimiter(aFile, CR_LF);
  setName(aFile, filename);
  open(aFile, 0);
  if (checkFileError(self, aFile, "open", "restore file", windowed) <> 0) then
    ^0;
  endif;
  /* verify file marker */
  temp := readLine(aFile);
  if (checkFileError(self, aFile, "read", "restore file", windowed) <> 0) then
    ^0;
  endif;
  if temp <> CLI_SAVE_FILE_MARKER
    reportFileError(self, "bad restore file", windowed);
    ^0;
  endif;

  /* note: code got too big, and had to be split up */
  /* read settings from file */
  settings := restoreSetupRead(self, aFile, windowed);
  close(aFile);
  if (checkFileError(self, aFile, "close", "restore file", windowed) <> 0) then
    ^0;
  endif;
  /* set settings */
  if settings
    restoreSetupSettings(self, settings, windowed);
  endif;

  /* force repaint */
  sizeKids(self, nil);
  ^0;
}
!!

/* read settings from file */
Def restoreSetupRead(self, aFile, windowed | settings temp coll)
{
  settings := new(OrderedCollection, 10);
  /* 0: restore split percentage */
  temp := asInt(readLine(aFile), 10);
  if (checkFileError(self, aFile, "read", "restore file", windowed) <> 0)
    ^nil;
  endif;
  add(settings, temp);
  /* 1: log file name */
  temp := readLine(aFile);
  if (checkFileError(self, aFile, "read", "restore file", windowed) <> 0)
  then
    ^nil;
  endif;
  add(settings, temp);
  /* 2: log file: 1 = on, 0 = off */
  temp := asInt(readLine(aFile), 10);
  if (checkFileError(self, aFile, "read", "restore file", windowed) <> 0)
  then
    ^nil;
  endif;
  add(settings, temp);
  /* 3: command: 1 = on, 0 = off */
  temp := asInt(readLine(aFile), 10);
  if (checkFileError(self, aFile, "read", "restore file", windowed) <> 0)
  then
    ^nil;
  endif;
  add(settings, temp);
  /* 4: results: 1 = on, 0 = off */
  temp := asInt(readLine(aFile), 10);
  if (checkFileError(self, aFile, "read", "restore file", windowed) <> 0)
  then
    ^nil;
  endif;
  add(settings, temp);
  /* 5: max history commands */
  temp := asInt(readLine(aFile), 10);
  if (checkFileError(self, aFile, "read", "restore file", windowed) <> 0)
  then
    ^nil;
  endif;
  add(settings, temp);
  /* 6: window location left */
  temp := asInt(readLine(aFile), 10);
  if (checkFileError(self, aFile, "read", "restore file", windowed) <> 0)
  then
    ^nil;
  endif;
  add(settings, temp);
  /* 7: window location top */
  temp := asInt(readLine(aFile), 10);
  if (checkFileError(self, aFile, "read", "restore file", windowed) <> 0)
  then
    ^nil;
  endif;
  add(settings, temp);
  /* 8: window location right */
  temp := asInt(readLine(aFile), 10);
  if (checkFileError(self, aFile, "read", "restore file", windowed) <> 0)
  then
    ^nil;
  endif;
  add(settings, temp);
  /* 9: window location bottom */
  temp := asInt(readLine(aFile), 10);
  if (checkFileError(self, aFile, "read", "restore file", windowed) <> 0)
  then
    ^nil;
  endif;
  add(settings, temp);
  /* 10 on: history cmds - each cmd may be multiple lines, separated by ":" */
  coll := new(TextCollection, 4);
  loop
  while not(atEnd(aFile))
  begin
    temp := readLine(aFile);
    if (checkFileError(self, aFile, "read", "restore file", windowed) <> 0)
    then
      ^nil;
    endif;
    if atEnd(aFile) cor temp = ":"
    then
      if size(coll) > 0
      then
        add(settings, coll);
        coll := new(TextCollection, 4);
      endif;
    else
      add(coll, temp);
    endif;
  endLoop;
  ^settings;
}
!!

/* restore settings */
Def restoreSetupSettings(self, settings, windowed | index maxIndex)
{
  /* file operations successful; restore profile */
  /* 0: restore split percentage */
  setTranscriptPercent(self, settings[0]);
  /* 1: log file name */
  setLogFileName(self, settings[1], windowed);
  /* 2: log file: 1 = on, 0 = off */
  if (settings[2] = 1)
  then
    setLoggingOn(self, windowed);
  else
    setLoggingOff(self, windowed);
  endif;
  /* 3: command: 1 = on, 0 = off */
  if (settings[3] = 1)
  then
    setCommandOn(self);
  else
    setCommandOff(self);
  endif;
  /* 4: results: 1 = on, 0 = off */
  if (settings[4] = 1)
  then
    setResultsOn(self);
  else
    setResultsOff(self);
  endif;
  /* 5: max history commands */
  initHistoryCommands(self);
  setMaxHistorySize(self, settings[5], windowed);
  /* 6, 7, 8, 9: window location left, top, right, bottom */
  setCRect(self, rect(settings[6], settings[7], settings[8], settings[9]));
  moveWindow(self);
  /* 10 on: history cmds */
  index := 10;
  maxIndex := size(settings) - 1;
  loop
  while index <= maxIndex
  begin
    addHistoryCommand(self, settings[index]);
    index := index + 1;
  endLoop;
}!!

/* save setup. */
Def saveSetup(self, filename, windowed |
      inputdlg aFile t1 t2 command commands temp)
{
  aFile := new(TextFile);
  setDelimiter(aFile, CR_LF);
  setName(aFile, filename);
  create(aFile);
  if (checkFileError(self, aFile, "open", "save file", windowed) <> 0)
    ^0;
  endif;

  /* write file marker */
  writeLine(aFile, CLI_SAVE_FILE_MARKER);
  if (checkFileError(self, aFile, "write", "save file", windowed) <> 0)
    ^0;
  endif;
  /* 1: log file name */
  if not(t1 := logFileName(self))
  then
    writeLine(aFile, "");
  else
    writeLine(aFile, t1);
  endif;
  if (checkFileError(self, aFile, "write", "save file", windowed) <> 0)
    ^0;
  endif;
  /* 2: logging: 1 = on, 0 = 0ff */
  if (logging(self))
  then
    writeLine(aFile, "1");
  else
    writeLine(aFile, "0");
  endif;
  if (checkFileError(self, aFile, "write", "save file", windowed) <> 0)
    ^0;
  endif;
  /* 3: show command: 1 = on, 0 = 0ff */
  if (showCommand(self))
  then
    writeLine(aFile, "1");
  else
    writeLine(aFile, "0");
  endif;
  if (checkFileError(self, aFile, "write", "save file", windowed) <> 0)
    ^0;
  endif;
  /* 4: show results: 1 = on, 0 = 0ff */
  if (showResults(self))
  then
    writeLine(aFile, "1");
  else
    writeLine(aFile, "0");
  endif;
  if (checkFileError(self, aFile, "write", "save file", windowed) <> 0)
    ^0;
  endif;
  /* 5: max history commands */
  writeLine(aFile, asString(getMaxHistorySize(self)));
  if (checkFileError(self, aFile, "write", "save file", windowed) <> 0)
    ^0;
  endif;
  /* 6, 7, 8, 9: window location left, top, right, bottom */
  writeLine(aFile, asString(left(locRect)));
  if (checkFileError(self, aFile, "write", "save file", windowed) <> 0)
    ^0;
  endif;
  writeLine(aFile, asString(top(locRect)));
  if (checkFileError(self, aFile, "write", "save file", windowed) <> 0)
    ^0;
  endif;
  writeLine(aFile, asString(right(locRect)));
  if (checkFileError(self, aFile, "write", "save file", windowed) <> 0)
    ^0;
  endif;
  writeLine(aFile, asString(bottom(locRect)));
  if (checkFileError(self, aFile, "write", "save file", windowed) <> 0)
    ^0;
  endif;
  /* 10 on: history commands */
  commands := getHistorySize(self);
  t1 := 0;
  /* write out each history command */
  loop
  while t1 < commands
  begin
    command := getHistoryCommand(self, t1);
    t2 := 0;
    /* write out each line in the command */
    loop
    while t2 < size(command)
    begin
      writeLine(aFile, command[t2]);
      t2 := t2 + 1;
    endLoop;
    /* separate each command with a ":" line */
    writeLine(aFile, ":");
    t1 := t1 + 1;
  endLoop;
  close(aFile);
}!!

/* comment */
Def screenPainted(self)
{
  ^screenPainted;
}
!!

/* set command Off. */
Def setCommandOff(self)
{
  showCommand := nil;
  unCheckMenuItem(self, "&Echo Command");
}!!

/* set command On. */
Def setCommandOn(self)
{
  showCommand := 0;
  checkMenuItem(self, "&Echo Command");
}!!

/* set log file name */
Def setLogFileName(self, filename, windowed)
{
  /* ignore if name didn't change */
  if logFileName = filename
    ^0;
  endif;
  
  /* get new name */
  logFileName := filename;
  
  /* if logging on, close old log file, start new log file */
  if logging(self)
    setLoggingOn(self, windowed);
  endif;
  ^0;
}
!!

/* set logging off. */
Def setLoggingOff(self, windowed)
{
  if not (logging(self))
  then
    ^0;
  endif;
  write(logFile, CR_LF+"// ----- "+dateStr()+" "+timeStr()+" log file closed -----"+CR_LF);
  if (checkFileError(self, logFile, "write", "log file", windowed) <> 0)
  then
    ^0;
  endif;
  close(logFile);  /* close file */
  if (checkFileError(self, logFile, "close", "log file", windowed) <> 0)
  then
    ^0;
  endif;
  loggingOff(self);
  unCheckMenuItem(self, "&Log Results");
}!!

/* set logging on. */
Def setLoggingOn(self, windowed | error text logPathName)
{
  setLoggingOff(self, windowed);
  logFile := new(TextFile);
  logPathName :=
    applyWorkDir(getExecutionEngine(CLIExecEngine), logFileName);
  setName(logFile, logPathName);
  
  if append(self)
    /* open for read/write */
    open(logFile, 2);
    if getError(logFile) = 0
      /* file exists; go to end of file */
      lseek(logFile, 0, 2);
      if (checkFileError(self, logFile, "seek", "log file", windowed) <> 0)
        ^0;
      endif;
    else
      /* file doesn't exist; create it */
      create(logFile);
      if (checkFileError(self, logFile, "open", "log file", windowed) <> 0)
        ^0;
      endif;
    endif;
  else
    /* open for write */
    create(logFile);
    if (checkFileError(self, logFile, "open", "log file", windowed) <> 0)
      ^0;
    endif;
  endif;
  
  write(logFile, CR_LF+"// ----- "+dateStr()+" "+timeStr()+" log file opened -----"+CR_LF);
  if (checkFileError(self, logFile, "write", "log file", windowed) <> 0)
    ^0;
  endif;
  loggingOn(self);
  checkMenuItem(self, "&Log Results");
  ^0;
}!!

/* set history size. */
Def setMaxHistorySize(self, hSize, windowed | text)
{
  if ((hSize >= 0) and (hSize <= 100))
  then
    setMaxHistorySize(hEdit, hSize);
    ^0; /* exit with change to history size */
  endif;
  
  /* put up appropriate message */
  if windowed then
    displayFormattedError(ErrorTextLibClass$Inst, 
       ER_CLI_HISTORY_SIZE, FORCE_POPUP, nil, nil, nil);
  else
    text := getFormattedError(ErrorTextLibClass$Inst, 
       ER_CLI_HISTORY_SIZE, nil, nil, nil);
    syntaxError(cliServer, nil, text);
  endif;
  ^nil;
}
!!

/* set show results off. */
Def setResultsOff(self)
{
  showResults := nil;
  unCheckMenuItem(self, "Show &Results");
}!!

/* set results On. */
Def setResultsOn(self)
{
  showResults := 0;
  checkMenuItem(self, "Show &Results"); 
}!!

/* termination processing */
Def shouldClose(self)
{
  if terminating
    ^0;
  endif;
  
  /* don't close if in critical region of output */
  if checkMessageLock?(cliServer)
    closePendingSet(self);
    ^nil;
  endif;
  
  /* if server still there, let it decide; otherwise, ok to quit */
  if cliServer
    ^shouldClose(cliServer);
  endif;
  ^0;
}!!

Def showCommand(self)
{
  ^showCommand;
}
!!

Def showResults(self)
{
  ^showResults;
}
!!

/* resize child windows */
Def sizeKids(self, newMiddle | topOfMiddle bottomOfMiddle midpoint
      pRect left right middle top bottom promptBorder windowHeight handle)
{
  if terminating cor not(hTrans) cor not(hEdit)
    ^0
  endif;
  pRect := clientRect(self);  /* get parent's rect */
  
  /* get individual coordinates */
  bottom := bottom(pRect);
  top := top(pRect);
  left := left(pRect);
  right := right(pRect);
  windowHeight := abs(bottom - top);
  
  if (newMiddle)
    /* split window provides new middle */
    middle := max(newMiddle, 6);  /* make sure not too small */
    middle := min(middle, bottom - 6);  /* make sure not too large */
  else
    /* parent resize */
    middle := bottom-editWindowHeight;
    midpoint := (top + bottom) / 2;
  endif;
  
  /* don't change editWindowHeight unless it is a good value */
  editWindowHeight := bottom - middle;
  if midpoint cand (midpoint > middle)
    middle := midpoint;
  endif;
  
  topOfMiddle := middle - 3;     /* leave room for split window */
  bottomOfMiddle := middle + 3;  /* leave room for split window */
  
  /* set border between prompt window and edit window */
  promptBorder := left + (2 * getTextWidth(hEdit));
  
  /* set transcript window */
  setCRect(hTrans, rect(left, top, right, topOfMiddle));
  moveWindow(hTrans);
  
  /* set prompt window */
  setCRect(hPrompt, rect(left, bottomOfMiddle, promptBorder, bottom));
  moveWindow(hPrompt);
  
  /* set edit window */
  setCRect(hEdit, rect(promptBorder, bottomOfMiddle, right, bottom));
  moveWindow(hEdit);
  
  /* set split window */
  setCRect(hSplit, rect(right-17, topOfMiddle, right, bottomOfMiddle));
  setYadjust(hSplit, topOfMiddle);
  moveWindow(hSplit);
  
  /* fix caret */
  if isTranscriptFocused(self)
    handle := hTrans;
  else
    handle := hEdit;
  endif;
  
  invalidate(self);
  setFocus(handle);
  hideCaret(handle);
  moveCaret(handle);
  showCaret(handle);
  screenPainted := 1;
}!!

/* print an eol to the transcript */
Def transcriptEol(self)
{
  /* log write must occur before screen write because addText lets all
     of the other events in, causing log lines to be jammed together. */
  logWrite(self, CR_LF);
  newLine(hTrans);
  ^0;
}!!

/* Transcript window has focus. */
Def transcriptGotFocus(self)
{
  if terminating
    ^0;
  endif;
  focusWindow := 0;
  presenterGotFocus(self);
  cutPasteGray(self);
  ^0;
}!!

/* Print a line to the transcript. */
Def transcriptLine(self, string | startIndex, stringSize, crIndex)
{
  /* log write must occur before screen write because addText lets all
     of the other events in, causing log lines to be jammed together. */
  logWrite(self, string);
  addText(hTrans, string);
}!!

/* Transcript window has lost the focus. */
Def transcriptLostFocus(self)
{
  focusWindow := nil;
  presenterLostFocus(self);
}!!

/* Print a line to the transcript; break compound lines at the CR. */
Def transcriptPrint(self, string | startIndex, stringSize, crIndex)
{
  startIndex := 0;
  stringSize := size(string);
  /* as long as there are CR's, print the line up to the CR, print a
     line break, and then advance past the CR */
  loop
  while ((startIndex < stringSize) and 
    (crIndex := indexOf(string, asChar(10), startIndex)))
  begin
    transcriptLine(self, subString(string, startIndex, crIndex));
    transcriptEol(self);
    startIndex := crIndex + 1;
  endLoop;
  if startIndex < stringSize
  then
    transcriptLine(self, subString(string, startIndex, stringSize));
  endif;
}!!

/* WM_INITMENU */
Def WM_INITMENU(self, wp, lp)
{
  ^WM_INITMENU(PreLauncher, wp, lp);
}!!
