ASSIGN(*list, tidy+1);
}
-char *insert, *wbOptions; // point in ChessProgramNames were we should insert new engine
+char *insert, *wbOptions, *currentEngine[2]; // point in ChessProgramNames were we should insert new engine
void
Load (ChessProgramState *cps, int i)
{
char *p, *q, buf[MSG_SIZ], command[MSG_SIZ], buf2[MSG_SIZ], buf3[MSG_SIZ], jar;
if(engineLine && engineLine[0]) { // an engine was selected from the combo box
+ ASSIGN(currentEngine[i], engineLine);
snprintf(buf, MSG_SIZ, "-fcp %s", engineLine);
SwapEngines(i); // kludge to parse -f* / -first* like it is -s* / -second*
ParseArgsFromString(resetOptions); appData.pvSAN[0] = FALSE;
q = firstChessProgramNames;
if(nickName[0]) snprintf(buf, MSG_SIZ, "\"%s\" -fcp ", nickName); else buf[0] = NULLCHAR;
quote = strchr(p, '"') ? '\'' : '"'; // use single quotes around engine command if it contains double quotes
- snprintf(buf+strlen(buf), MSG_SIZ-strlen(buf), "%c%s%c -fd \"%s\"%s%s%s%s%s%s%s%s\n",
+ snprintf(buf+strlen(buf), MSG_SIZ-strlen(buf), "%c%s%c -fd \"%s\"%s%s%s%s%s%s%s%s",
quote, p, quote, appData.directory[i],
useNick ? " -fn \"" : "",
useNick ? nickName : "",
isUCI ? (isUCI == TRUE ? " -fUCI" : gameInfo.variant == VariantShogi ? " -fUSI" : " -fUCCI") : "",
storeVariant ? " -variant " : "",
storeVariant ? VariantName(gameInfo.variant) : "");
- if(wbOptions && wbOptions[0]) snprintf(buf+strlen(buf)-1, MSG_SIZ-strlen(buf), " %s\n", wbOptions);
- firstChessProgramNames = malloc(len = strlen(q) + strlen(buf) + 1);
+ if(wbOptions && wbOptions[0]) snprintf(buf+strlen(buf), MSG_SIZ-strlen(buf), " %s", wbOptions);
+ firstChessProgramNames = malloc(len = strlen(q) + strlen(buf) + 2);
if(insert != q) insert[-1] = NULLCHAR;
- snprintf(firstChessProgramNames, len, "%s\n%s%s", q, buf, insert);
+ snprintf(firstChessProgramNames, len, "%s\n%s\n%s", q, buf, insert);
if(q) free(q);
FloatToFront(&appData.recentEngineList, buf);
+ ASSIGN(currentEngine[i], buf);
}
ReplaceEngine(cps, i);
}
}
-void
-ResendOptions (ChessProgramState *cps)
+char *
+ResendOptions (ChessProgramState *cps, int toEngine)
{ // send the stored value of the options
int i;
- char buf[MSG_SIZ];
+ static char buf2[MSG_SIZ*10];
+ char buf[MSG_SIZ], *p = buf2;
Option *opt = cps->option;
+ *p = NULLCHAR;
for(i=0; i<cps->nrOptions; i++, opt++) {
+ *buf = NULLCHAR;
switch(opt->type) {
case Spin:
case Slider:
case CheckBox:
- snprintf(buf, MSG_SIZ, "option %s=%d\n", opt->name, opt->value);
+ if(opt->value != *(int*) (opt->name + MSG_SIZ - 104))
+ snprintf(buf, MSG_SIZ, "%s=%d", opt->name, opt->value);
break;
case ComboBox:
- snprintf(buf, MSG_SIZ, "option %s=%s\n", opt->name, opt->choice[opt->value]);
+ if(opt->value != *(int*) (opt->name + MSG_SIZ - 104))
+ snprintf(buf, MSG_SIZ, "%s=%s", opt->name, opt->choice[opt->value]);
break;
default:
- snprintf(buf, MSG_SIZ, "option %s=%s\n", opt->name, opt->textValue);
+ if(strcmp(opt->textValue, opt->name + MSG_SIZ - 100))
+ snprintf(buf, MSG_SIZ, "%s=%s", opt->name, opt->textValue);
break;
case Button:
case SaveButton:
continue;
}
- SendToProgram(buf, cps);
+ if(*buf) {
+ if(toEngine) {
+ snprintf(buf2, MSG_SIZ, "option %s\n", buf);
+ SendToProgram(buf2, cps);
+ } else {
+ if(p != buf2) *p++ = ',';
+ strncpy(p, buf, 10*MSG_SIZ-1 - (p - buf2));
+ while(*p) p++;
+ }
+ }
}
+ return buf2;
}
void
cps->comboCnt = 0; // and values of combo boxes
}
SendToProgram(buf, cps);
- if(cps->reload) ResendOptions(cps);
+ if(cps->reload) ResendOptions(cps, TRUE);
} else {
SendToProgram("xboard\n", cps);
}
return i;
}
+void
+SaveEngineSettings (int n)
+{
+ int len; char *p, *q, *s, buf[MSG_SIZ], *optionSettings;
+ if(!currentEngine[n] || !currentEngine[n][0]) return; // no engine from list is loaded
+ p = strstr(firstChessProgramNames, currentEngine[n]);
+ if(!p) return; // sanity check; engine could be deleted from list after loading
+ optionSettings = ResendOptions(n ? &second : &first, FALSE);
+ len = strlen(currentEngine[n]);
+ q = p + len; *p = 0; // cut list into head and tail piece
+ s = strstr(currentEngine[n], "firstOptions");
+ if(s && (s[-1] == '-' || s[-1] == '/') && (s[12] == ' ' || s[12] == '=') && (s[13] == '"' || s[13] == '\'')) {
+ char *r = s + 14;
+ while(*r && *r != s[13]) r++;
+ s[14] = 0; // cut currentEngine into head and tail part, removing old settings
+ snprintf(buf, MSG_SIZ, "%s%s%s", currentEngine[n], optionSettings, *r ? r : "\""); // synthesize new engine line
+ } else if(*optionSettings) {
+ snprintf(buf, MSG_SIZ, "%s -firstOptions \"%s\"", currentEngine[n], optionSettings);
+ }
+ ASSIGN(currentEngine[n], buf); // updated engine line
+ len = p - firstChessProgramNames + strlen(q) + strlen(currentEngine[n]) + 1;
+ s = malloc(len);
+ snprintf(s, len, "%s%s%s", firstChessProgramNames, currentEngine[n], q);
+ FREE(firstChessProgramNames); firstChessProgramNames = s; // new list
+}
+
// following implemented as macro to avoid type limitations
#define SWAP(item, temp) temp = appData.item[0]; appData.item[0] = appData.item[n]; appData.item[n] = temp;
void
TwoMachinesEvent P((void))
{
- int i;
+ int i, move = forwardMostMove;
char buf[MSG_SIZ];
ChessProgramState *onmove;
char *bookHit = NULL;
}
}
- ResetClocks();
- if (!first.sendTime || !second.sendTime) {
+ if (!first.sendTime || !second.sendTime || move == 0) { // [HGM] first engine changed sides from Reset, so recalc time odds
+ ResetClocks();
timeRemaining[0][forwardMostMove] = whiteTimeRemaining;
timeRemaining[1][forwardMostMove] = blackTimeRemaining;
}
if (strncmp((*p), name, len) == 0
&& (*p)[len] == '=' && (*p)[len+1] == '\"') {
(*p) += len + 2;
- ASSIGN(*loc, *p); // kludge alert: assign rest of line just to be sure allocation is large enough so that sscanf below always fits
- sscanf(*p, "%[^\"]", *loc);
+ len = strlen(*p) + 1; if(len < MSG_SIZ && !strcmp(name, "option")) len = MSG_SIZ; // make sure string options have enough space to change their value
+ FREE(*loc); *loc = malloc(len);
+ strncpy(*loc, *p, len);
+ sscanf(*p, "%[^\"]", *loc); // should always fit, because we allocated at least strlen(*p)
while (**p && **p != '\"') (*p)++;
if (**p == '\"') (*p)++;
snprintf(buf, MSG_SIZ, "accepted %s\n", name);
strcat(buf, "\n");
SendToProgram(buf, cps);
}
+ *(int*) (opt->name + MSG_SIZ - 104) = opt->value; // hide default values somewhere
+ if(opt->target == &opt->textValue) strncpy(opt->name + MSG_SIZ - 100, opt->textValue, 99);
return TRUE;
}
if (StringFeature(&p, "egt", &cps->egtFormats, cps)) continue;
if (StringFeature(&p, "option", &q, cps)) { // read to freshly allocated temp buffer first
if(cps->reload) { FREE(q); q = NULL; continue; } // we are reloading because of xreuse
+ if(cps->nrOptions == 0) { ASSIGN(cps->option[0].name, _("Make Persistent -save")); ParseOption(&(cps->option[cps->nrOptions++]), cps); }
FREE(cps->option[cps->nrOptions].name);
cps->option[cps->nrOptions].name = q; q = NULL;
if(!ParseOption(&(cps->option[cps->nrOptions++]), cps)) { // [HGM] options: add option feature