#define DoSleep( n ) if( (n) != 0 ) Sleep( (n) );
+int flock(int f, int code);
+#define LOCK_EX 2
+
#else
#define DoSleep( n ) if( (n) >= 0) sleep(n)
extern int chatCount;
int chattingPartner;
char marker[BOARD_RANKS][BOARD_FILES]; /* [HGM] marks for target squares */
+char lastMsg[MSG_SIZ];
ChessSquare pieceSweep = EmptySquare;
ChessSquare promoSweep = EmptySquare, defaultPromoChoice;
int promoDefaultAltered;
{
dst[ count-1 ] = '\0'; // make sure incomplete copy still null-terminated
if(appData.debugMode)
- fprintf(debugFP, "safeStrCpy: copying %s into %s didn't work, not enough space %d\n",src,dst,count);
+ fprintf(debugFP, "safeStrCpy: copying %s into %s didn't work, not enough space %d\n",src,dst, (int)count);
}
return dst;
InitEngineUCI( installDir, cps ); // [HGM] moved here from winboard.c, to make available in xboard
}
+ChessProgramState *savCps;
+
+void
+LoadEngine()
+{
+ int i;
+ if(WaitForEngine(savCps, LoadEngine)) return;
+ CommonEngineInit(); // recalculate time odds
+ if(gameInfo.variant != StringToVariant(appData.variant)) {
+ // we changed variant when loading the engine; this forces us to reset
+ Reset(TRUE, savCps != &first);
+ EditGameEvent(); // for consistency with other path, as Reset changes mode
+ }
+ InitChessProgram(savCps, FALSE);
+ SendToProgram("force\n", savCps);
+ DisplayMessage("", "");
+ if (startedFromSetupPosition) SendBoard(savCps, backwardMostMove);
+ for (i = backwardMostMove; i < forwardMostMove; i++) SendMoveToProgram(i, savCps);
+ ThawUI();
+ SetGNUMode();
+}
+
+void
+ReplaceEngine(ChessProgramState *cps, int n)
+{
+ EditGameEvent();
+ UnloadEngine(cps);
+ appData.noChessProgram = False;
+ appData.clockMode = True;
+ InitEngine(cps, n);
+ if(n) return; // only startup first engine immediately; second can wait
+ savCps = cps; // parameter to LoadEngine passed as globals, to allow scheduled calling :-(
+ LoadEngine();
+}
+
void
InitBackEnd1()
{
DisplayMessage("", "");
if (StrCaseCmp(appData.initialMode, "") == 0) {
initialMode = BeginningOfGame;
+ if(!appData.icsActive && appData.noChessProgram) { // [HGM] could be fall-back
+ gameMode = MachinePlaysBlack; // "Machine Black" might have been implicitly highlighted
+ ModeHighlight(); // make sure XBoard knows it is highlighted, so it will un-highlight it
+ gameMode = BeginningOfGame; // in case BeginningOfGame now means "Edit Position"
+ ModeHighlight();
+ }
} else if (StrCaseCmp(appData.initialMode, "TwoMachines") == 0) {
initialMode = TwoMachinesPlay;
} else if (StrCaseCmp(appData.initialMode, "AnalyzeFile") == 0) {
}
} // [HGM] chat: end of patch
+ backup = i;
if (appData.zippyTalk || appData.zippyPlay) {
/* [DM] Backup address for color zippy lines */
- backup = i;
#if ZIPPY
if (loggedOn == TRUE)
if (ZippyControl(buf, &backup) || ZippyConverse(buf, &backup) ||
continue;
}
+ if(i < backup) { i = backup; continue; } // [HGM] for if ZippyControl matches, but the colorie code doesn't
+
if (looking_at(buf, &i, "\\ ")) {
if (prevColor != ColorNormal) {
if (oldi > next_out) {
snprintf(buf1, sizeof(buf1), _("Failed to start %s chess program %s on %s: %s\n"),
_(cps->which), cps->program, cps->host, message);
RemoveInputSource(cps->isr);
- DisplayFatalError(buf1, 0, 1);
+ if(appData.icsActive) DisplayFatalError(buf1, 0, 1); else {
+ if(cps == &first) appData.noChessProgram = TRUE;
+ DisplayError(buf1, 0);
+ }
return;
}
{
FILE *f;
char buf[MSG_SIZ];
+ int result;
if (strcmp(filename, "-") == 0) {
return SaveGame(stdout, 0, NULL);
DisplayError(buf, errno);
return FALSE;
} else {
- return SaveGame(f, 0, NULL);
+ safeStrCpy(buf, lastMsg, MSG_SIZ);
+ DisplayMessage(_("Waiting for access to save file"), "");
+ flock(fileno(f), LOCK_EX); // [HGM] lock: lock file while we are writing
+ DisplayMessage(_("Saving game"), "");
+ if(lseek(fileno(f), 0, SEEK_END) == -1) DisplayError("Bad Seek", errno); // better safe than sorry...
+ result = SaveGame(f, 0, NULL);
+ DisplayMessage(buf, "");
+ return result;
}
}
}
DisplayError(buf, errno);
return FALSE;
} else {
+ safeStrCpy(buf, lastMsg, MSG_SIZ);
+ DisplayMessage(_("Waiting for access to save file"), "");
+ flock(fileno(f), LOCK_EX); // [HGM] lock
+ DisplayMessage(_("Saving position"), "");
+ lseek(fileno(f), 0, SEEK_END); // better safe than sorry...
SavePosition(f, 0, NULL);
+ DisplayMessage(buf, "");
return TRUE;
}
}
outCount = OutputToProcess(cps->pr, message, count, &error);
if (outCount < count && !exiting
&& !endingGame) { /* [HGM] crash: to not hang GameEnds() writing to deceased engines */
+ if(!cps->initDone) return; // [HGM] should not generate fatal error during engine load
snprintf(buf, MSG_SIZ, _("Error writing to %s chess program"), _(cps->which));
if(gameInfo.resultDetails==NULL) { /* [HGM] crash: if game in progress, give reason for abort */
if((signed char)boards[forwardMostMove][EP_STATUS] <= EP_DRAWS) {
DelayedEventCallback cb = GetDelayedEvent();
if ((cb == InitBackEnd3 && cps == &first) ||
(cb == SettingsMenuIfReady && cps == &second) ||
+ (cb == LoadEngine) ||
(cb == TwoMachinesEventIfReady && cps == &second)) {
CancelDelayedEvent();
ScheduleDelayedEvent(cb, val ? 1 : 3600000);