#include "chess.h" command_t *commands; size_t numCmds; void addCommand(char *name, int (*handler)(const char *buf), bitfield_t flags) { command_t newCmd; newCmd.name = name; newCmd.handler = handler; newCmd.flags = flags; numCmds++; commands = realloc(commands, numCmds * sizeof(command_t)); commands[numCmds - 1] = newCmd; } void logCommand(const char *buf) { moveHistory_t *history; if(!logging) return; if((history = moveHistory)) { moveHistory_t *undo; while(history->undo) history = history->undo; undo = history; while(history->next) history = history->next; history = history->next = undo->undo = malloc(sizeof(moveHistory_t)); } else history = moveHistory = malloc(sizeof(moveHistory_t)); if(!history) { strncpy(out, "WARNING: memory allocation failed, logging disabled", sizeof(out)); /* don't try again */ logging = false; while((history = moveHistory)) { moveHistory = moveHistory->next; free(history); } return; } memset(history, 0, sizeof(moveHistory_t)); strncpy(history->inHistory, buf, sizeof(history->inHistory)); } int cmd_argc(const char *args) { int argc = 1; while(*args) if(*args++ == ' ') { while(*args && *args == ' ') args++; argc++; } return argc; } const char *cmd_argv(const char *args, int id, char *buf, size_t len) { int i; while(id-- > 0) { while(*args && *args++ != ' '); while(*args && *args == ' ') args++; } if(buf && len) { for(i = 0; i < len && args[i] != ' '; buf[i] = args[i], i++); if(i == len) buf[len - 1] = '\0'; else buf[i] = '\0'; } return args; } /* free the movehistory linked list */ int cmd_clear(const char *buf) { moveHistory_t *history; while((history = moveHistory)) { moveHistory = moveHistory->next; free(history); } strncpy(out, "Move history cleared", sizeof(out)); return 1; } int cmd_draw(const char *buf) { char response[8]; snprintf(out, sizeof out, "%s: \"accept\" or \"reject\" this draw offer", names[3 - nextMove]); while(true) { input(response, sizeof response); if(strncmp(response, "accept", 6) == 0) { conclusion = DRAW; strncpy(out, "Draw agreed", sizeof out); playing = false; return 1; } else if(strncmp(response, "reject", 6) == 0) { moveMessage(); return 1; } else { snprintf(out, sizeof out, "%s: \"accept\" or \"reject\" this draw " "offer", names[3 - nextMove]); output(); } } } /* for examining and debugging the logger: this outputs the entire history and * then dies */ int cmd_dump(const char *buf) { moveHistory_t *history; while((history = moveHistory)) { puts(moveHistory->inHistory); moveHistory = moveHistory->next; free(history); } exit(QUIT); } int cmd_new(const char *buf) { newGame(); return 1; } /* hacky way of geting instant playback */ int cmd_open(const char *buf) { FILE *f, *oldstream; oldstream = inputstream; if(!(inputstream = fopen(cmd_argv(buf, 1, NULL, 0), "r"))) { snprintf(out, sizeof out, "%s: %s", cmd_argv(buf, 1, NULL, 0), strerror(errno)); inputstream = stdin; return 1; } else { while(!feof(inputstream)) { char cmd[128]; memset(cmd, 0 , sizeof cmd); input(cmd, sizeof cmd); f = inputstream; inputstream = stdin; move(cmd); inputstream = f; } fclose(inputstream); inputstream = oldstream; output(); return 1; } } int cmd_playername(const char *buf) { team_t targteam; switch(buf[6]) { case '1': targteam = TEAM_WHITE; break; case '2': targteam = TEAM_BLACK; break; case 's': //TODO default: return 0; } snprintf(out, sizeof out, "%s renamed to ", names[targteam]); strncpy(names[targteam], buf + 8, 32); strncat(out, names[targteam], sizeof(out) - strlen(names[targteam])); return 1; } int cmd_quit(const char *buf) { return 0; } int cmd_replay(const char *buf) { if(!(inputstream = fopen(cmd_argv(buf, 1, NULL, 0), "r"))) { snprintf(out, sizeof out, "%s: %s", cmd_argv(buf, 1, NULL, 0), strerror(errno)); inputstream = stdin; return 1; } else { snprintf(out, sizeof out, "Opening file %s for reading", cmd_argv(buf, 1, NULL, 0)); return 1; } } int cmd_resign(const char *buf) { snprintf(out, sizeof out, "Victory for %s!", names[3 - nextMove]); conclusion = nextMove; playing = false; return 1; } /* save the current log to a file */ int cmd_save(const char *buf) { FILE *f; moveHistory_t *history; if(!logging || !moveHistory) { strncpy(out, "No log found", sizeof(out)); return 1; } f = fopen(buf + 5, "r"); if(f) { char decision[2]; strncpy(out, "File already exists, overwrite? [y/N]", sizeof(out)); output(); input(decision, sizeof(decision)); if(*decision == 'y' || *decision == 'Y') f = freopen(NULL, "w", f); } else f = fopen(buf + 5, "w"); if(!f) { strerror_r(errno, out, sizeof(out)); return 1; } while((history = moveHistory)) { fprintf(f, "%s\n", moveHistory->inHistory); moveHistory = moveHistory->next; free(history); } snprintf(out, sizeof(out), "%s saved", buf + 5); fclose(f); return 1; } int cmd_undo(const char *buf) { moveHistory_t *history; if(!logging) { strncpy(out, "Logging is disabled, can't undo", sizeof(out)); return 1; } history = moveHistory; if(history->undo && history->undo->undo) { while(history->undo->undo->undo) /* ouch */ history = history->undo; history->undo = NULL; } else if(history->undo) { newGame(); return 1; } else { strncpy(out, "undo: nothing to undo", sizeof(out)); return 1; } newGame(); updateBoard(); history = moveHistory; logging = false; while(history) { if(strncmp(history->inHistory, "undo", 4)) move(history->inHistory); updateBoard(); history = history->undo; } logging = true; return 1; }