/* Search stats from chessprogram */
typedef struct {
- char movelist[MSG_SIZ]; /* Last PV we were sent */
+ char movelist[2*MSG_SIZ]; /* Last PV we were sent */
int depth; /* Current search depth */
int nr_moves; /* Total nr of root moves */
int moves_left; /* Moves remaining to be searched */
} else if ((i = 4, p = StrCaseStr(e, "wild")) ||
(i = 1, p = StrCaseStr(e, "w"))) {
p += i;
- while (*p && (isspace(*p) || *p == '(')) p++;
+ while (*p && (isspace(*p) || *p == '(' || *p == '/')) p++;
if (isdigit(*p)) {
wnum = atoi(p);
} else {
int tkind;
char *p;
+#ifdef WIN32
+ if (appData.debugMode) {
+ if (!error) {
+ fprintf(debugFP, "<ICS: ");
+ show_bytes(debugFP, data, count);
+ fprintf(debugFP, "\n");
+ }
+ }
+#endif
+
if (count > 0) {
/* If last read ended with a partial line that we couldn't parse,
prepend it to the new read and try again. */
}
/* Improved generic start/end-of-game messages */
- if (looking_at(buf, &i, "{Game * (* vs. *) *}*")) {
+ if ((tkind=0, looking_at(buf, &i, "{Game * (* vs. *) *}*")) ||
+ (tkind=1, looking_at(buf, &i, "{Game * (*(*) vs. *(*)) *}*"))){
+ /* If tkind == 0: */
/* star_match[0] is the game number */
/* [1] is the white player's name */
/* [2] is the black player's name */
/* [3] begins with "Creating" or "Continuing" */
/* [4] is " *" or empty (don't care). */
int gamenum = atoi(star_match[0]);
- char *why = star_match[3];
- char *endtoken = star_match[4];
+ char *whitename, *blackname, *why, *endtoken;
ChessMove endtype = (ChessMove) 0;
+ if (tkind == 0) {
+ whitename = star_match[1];
+ blackname = star_match[2];
+ why = star_match[3];
+ endtoken = star_match[4];
+ } else {
+ whitename = star_match[1];
+ blackname = star_match[3];
+ why = star_match[5];
+ endtoken = star_match[6];
+ }
+
/* Game start messages */
if (strncmp(why, "Creating ", 9) == 0 ||
strncmp(why, "Continuing ", 11) == 0) {
strcpy(gs_kind, strchr(why, ' ') + 1);
#if ZIPPY
if (appData.zippyPlay) {
- ZippyGameStart(star_match[1], star_match[2]);
+ ZippyGameStart(whitename, blackname);
}
#endif /*ZIPPY*/
continue;
/* Machine move could not be parsed; ignore it. */
sprintf(buf1, "Illegal move \"%s\" from %s machine",
machineMove, cps->which);
- /*!!if (appData.debugMode)*/ DisplayError(buf1, 0);
+ DisplayError(buf1, 0);
+ if (gameMode == TwoMachinesPlay) {
+ GameEnds(machineWhite ? BlackWins : WhiteWins,
+ "Forfeit due to illegal move", GE_XBOARD);
+ }
return;
}
* Look for communication commands
*/
if (!strncmp(message, "telluser ", 9)) {
- DisplayInformation(message + 9);
+ DisplayNote(message + 9);
return;
}
if (!strncmp(message, "tellusererror ", 14)) {
SendToICS(buf1);
}
} else {
- DisplayInformation(message + 13);
+ DisplayNote(message + 13);
}
return;
}
SendToICS(buf1);
}
} else {
- DisplayInformation(message + 8);
+ DisplayNote(message + 8);
}
return;
}
DisplayError(buf2, 0);
return;
}
- if (StrStr(message, "st")) {
+ if (StrStr(message, "(no matching move)st")) {
+ /* Special kludge for GNU Chess 4 only */
cps->stKludge = TRUE;
SendTimeControl(cps, movesPerSession, timeControl,
timeIncrement, appData.searchDepth,
searchTime);
return;
}
- if (StrStr(message, "sd")) {
+ if (StrStr(message, "(no matching move)sd")) {
+ /* Special kludge for GNU Chess 4 only */
cps->sdKludge = TRUE;
SendTimeControl(cps, movesPerSession, timeControl,
timeIncrement, appData.searchDepth,
if (gameMode == BeginningOfGame || gameMode == EndOfGame ||
gameMode == IcsIdle) return;
if (forwardMostMove <= backwardMostMove) return;
+#if 0
+ /* Following removed: it caused a bug where a real illegal move
+ message in analyze mored would be ignored. */
if (cps == &first && programStats.ok_to_send == 0) {
/* Bogus message from Crafty responding to "." This filtering
can miss some of the bad messages, but fortunately the bug
is fixed in current Crafty versions, so it doesn't matter. */
return;
}
+#endif
if (pausing) PauseEvent();
if (gameMode == PlayFromGameFile) {
/* Stop reading this game file */
programStats.nodes = nodes;
programStats.time = time;
programStats.score = curscore;
- strcpy(programStats.movelist, buf1);
programStats.got_only_move = 0;
+ /* Buffer overflow protection */
+ if (buf1[0] != NULLCHAR) {
+ if (strlen(buf1) >= sizeof(programStats.movelist)
+ && appData.debugMode) {
+ fprintf(debugFP,
+ "PV is too long; using the first %d bytes.\n",
+ sizeof(programStats.movelist) - 1);
+ }
+ strncpy(programStats.movelist, buf1,
+ sizeof(programStats.movelist));
+ programStats.movelist[sizeof(programStats.movelist) - 1]
+ = NULLCHAR;
+ } else {
+ sprintf(programStats.movelist, " no PV\n");
+ }
+
if (programStats.seen_stat) {
programStats.ok_to_send = 1;
}
}
return;
case ElapsedTime:
- if (boardIndex > 0) {
+ if (boardIndex > (blackPlaysFirst ? 1 : 0)) {
strcat(parseList[boardIndex-1], " ");
strcat(parseList[boardIndex-1], yy_text);
}
* A game that starts with one of the latter two patterns
* will also have a move number 1, possibly
* following a position diagram.
+ * 5-4-02: Let's try being more lenient and allowing a game to
+ * start with an unnumbered move. Does that break anything?
*/
cm = lastLoadGameStart = (ChessMove) 0;
- yyskipmoves = TRUE;
while (gn > 0) {
yyboardindex = forwardMostMove;
cm = (ChessMove) yylex();
- yyskipmoves = FALSE;
switch (cm) {
case (ChessMove) 0:
if (cmailMsgLoaded) {
Reset(TRUE, TRUE);
DisplayError("Game not found in file", 0);
}
- yyskipmoves = FALSE;
return FALSE;
case GNUChessGame:
}
break;
+ case NormalMove:
+ /* Only a NormalMove can be at the start of a game
+ * without a position diagram. */
+ if (lastLoadGameStart == (ChessMove) 0) {
+ gn--;
+ lastLoadGameStart = MoveNumberOne;
+ }
+ break;
+
default:
break;
}
}
- yyskipmoves = FALSE;
if (appData.debugMode)
fprintf(debugFP, "Parsed game start '%s' (%d)\n", yy_text, (int) cm);
cm = (ChessMove) yylex();
}
- if (cm == (ChessMove) 0 || cm == WhiteWins || cm == BlackWins ||
+ if ((cm == (ChessMove) 0 && lastLoadGameStart != (ChessMove) 0) ||
+ cm == WhiteWins || cm == BlackWins ||
cm == GameIsDrawn || cm == GameUnfinished) {
DisplayMessage("", "No moves in game");
if (cmailMsgLoaded) {
while (pn > 0) {
/* skip postions before number pn */
if (fgets(line, MSG_SIZ, f) == NULL) {
+ Reset(TRUE, TRUE);
DisplayError("Position not found in file", 0);
return FALSE;
}
ReloadCmailMsgEvent(unregister)
int unregister;
{
+#if !WIN32
static char *inFilename = NULL;
static char *outFilename;
int i;
/* Load first game in the file or popup game menu */
LoadGameFromFile(inFilename, 0, appData.cmailGameName, TRUE);
+#endif /* !WIN32 */
return;
}
void
MailMoveEvent()
{
+#if !WIN32
static char *partCommandString = "cmail -xv%s -remail -game %s 2>&1";
FILE *commandOutput;
char buffer[MSG_SIZ], msg[MSG_SIZ], string[MSG_SIZ];
|| (nCmailMovesRegistered + nCmailResults == nCmailGames)) {
sprintf(string, partCommandString,
appData.debugMode ? " -v" : "", appData.cmailGameName);
- commandOutput = popen(string, "r");
+ commandOutput = popen(string, "rb");
if (commandOutput == NULL) {
DisplayError("Failed to invoke cmail", 0);
}
return;
+#endif /* !WIN32 */
}
char *
CmailMsg()
{
+#if WIN32
+ return NULL;
+#else
int prependComma = 0;
char number[5];
char string[MSG_SIZ]; /* Space for game-list */
}
}
}
-
return cmailMsg;
+#endif /* WIN32 */
}
void
}
void
+CrushCRs(text)
+ char *text;
+{
+ char *p = text;
+ char *q = text;
+ char ch;
+
+ do {
+ ch = *p++;
+ if (ch == '\r') continue;
+ *q++ = ch;
+ } while (ch != '\0');
+}
+
+void
AppendComment(index, text)
int index;
char *text;
int oldlen, len;
char *old;
+ CrushCRs(text);
while (*text == '\n') text++;
len = strlen(text);
while (len > 0 && text[len - 1] == '\n') len--;