From 2987ec348b8b2cbf38ba9a6a0793652a6b238ae8 Mon Sep 17 00:00:00 2001 From: H.G.Muller Date: Mon, 15 Sep 2014 15:30:40 +0200 Subject: [PATCH] Implement -autoInstall option When -autoInstall is a non-empty string, XBoard will scan the system's plugin specs directories for UCI and WB protocol, to see if new engines were added since the last settings save. If so, they are added to the list of installed engines. The variants listed in the plugin-spec files are currently ignored, but the option is already configured to install engines for all variants. --- args.h | 1 + common.h | 1 + menus.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ xboard.conf.in | 1 + xboard.texi | 11 +++++++ 5 files changed, 103 insertions(+), 0 deletions(-) diff --git a/args.h b/args.h index 91de0bf..9ce2b47 100644 --- a/args.h +++ b/args.h @@ -609,6 +609,7 @@ ArgDescriptor argDescriptors[] = { { "border", ArgFilename, (void *) &appData.border, TRUE, (ArgIniType) "" }, { "finger", ArgFilename, (void *) &appData.finger, FALSE, (ArgIniType) "" }, { "inscriptions", ArgString, (void *) &appData.inscriptions, XBOARD, (ArgIniType) "" }, + { "autoInstall", ArgString, (void *) &appData.autoInstall, XBOARD, (ArgIniType) "" }, // [HGM] tournament options { "tourneyFile", ArgFilename, (void *) &appData.tourneyFile, FALSE, (ArgIniType) "" }, diff --git a/common.h b/common.h index e6c3b20..24b7ce0 100644 --- a/common.h +++ b/common.h @@ -508,6 +508,7 @@ typedef struct { char *loadGameFile; int loadGameIndex; /* game # within file */ char *saveGameFile; + char *autoInstall; Boolean autoSaveGames; Boolean onlyOwn; /* [HGM] suppress auto-saving of observed games */ char *loadPositionFile; diff --git a/menus.c b/menus.c index b79c90a..4934a3c 100644 --- a/menus.c +++ b/menus.c @@ -1160,6 +1160,92 @@ ModeToWidgetName (GameMode mode) } } +static void +InstallNewEngine (char *command, char *dir, char *variants, char *protocol) +{ // install the given engine in XBoard's -firstChessProgramNames + char buf[MSG_SIZ], *quote = ""; + if(strchr(command, ' ')) { // quoting needed + if(!strchr(command, '"')) quote = "\""; else + if(!strchr(command, '\'')) quote = "'"; else { + printf("Could not auto-install %s\n", command); // too complex + } + } + // construct engine line, with optional -fd and -fUCI arguments + snprintf(buf, MSG_SIZ, "%s%s%s", quote, command, quote); + if(strcmp(dir, "") && strcmp(dir, ".")) + snprintf(buf + strlen(buf), MSG_SIZ - strlen(buf), " -fd %s", dir); + if(!strcmp(protocol, "uci")) + snprintf(buf + strlen(buf), MSG_SIZ - strlen(buf), " -fUCI"); + // append line + quote = malloc(strlen(firstChessProgramNames) + strlen(buf) + 2); + sprintf(quote, "%s%s\n", firstChessProgramNames, buf); + FREE(firstChessProgramNames); firstChessProgramNames = quote; +} + +#ifdef HAVE_DIRENT_H +#include +#else +#include +#define dirent direct +#endif + +static void +InstallFromDir (char *dirName, char *protocol, char *settingsFile) +{ // scan system for new plugin specs in given directory + DIR *dir; + struct dirent *dp; + struct stat statBuf; + time_t lastSaved = 0; + char buf[1024]; + + if(!stat(settingsFile, &statBuf)) lastSaved = statBuf.st_mtime; + snprintf(buf, 1024, "%s/%s", dirName, protocol); + + if(!(dir = opendir(buf))) return; + while( (dp = readdir(dir))) { + time_t installed = 0; + if(!strstr(dp->d_name, ".eng")) continue; // to suppress . and .. + snprintf(buf, 1024, "%s/%s/%s", dirName, protocol, dp->d_name); + if(!stat(buf, &statBuf)) installed = statBuf.st_mtime; + if(lastSaved == 0 || (int) (installed - lastSaved) > 0) { // first time we see it + FILE *f = fopen(buf, "r"); + if(f) { // read the plugin-specs + char engineCommand[1024], engineDir[1024], variants[1024]; + char bad=0, dummy, *engineCom = engineCommand; + int major, minor; + if(fscanf(f, "plugin spec %d.%d%c", &major, &minor, &dummy) != 3 || + fscanf(f, "%[^\n]%c", engineCommand, &dummy) != 2 || + fscanf(f, "%[^\n]%c", variants, &dummy) != 2) bad = 1; + fclose(f); + if(bad) continue; + // uncomment following two lines for chess-only installs +// if(!(p = strstr(variants, "chess")) || +// p != variants && p[-1] != ',' || p[5] && p[5] != ',') continue; + // split off engine working directory (if any) + strcpy(engineDir, ""); + if(sscanf(engineCommand, "cd %[^;];%c", engineDir, &dummy) == 2) + engineCom = engineCommand + strlen(engineDir) + 4; + InstallNewEngine(engineCom, engineDir, variants, protocol); + } + } + } + closedir(dir); +} + +static void +AutoInstallProtocol (char *settingsFile, char *protocol) +{ // install new engines for given protocol (both from package and source) + InstallFromDir("/usr/local/share/games/plugins", protocol, settingsFile); + InstallFromDir("/usr/share/games/plugins", protocol, settingsFile); +} + +void +AutoInstall (char *settingsFile) +{ // install all new XBoard and UCI engines + AutoInstallProtocol(settingsFile, "xboard"); + AutoInstallProtocol(settingsFile, "uci"); +} + void InitMenuMarkers() { @@ -1234,4 +1320,7 @@ InitMenuMarkers() MarkMenuItem("Options.SaveSettingsonExit", True); } EnableNamedMenuItem("File.SaveSelected", False); + + // all XBoard builds get here, but not WinBoard... + if(*appData.autoInstall) AutoInstall(settingsFileName); } diff --git a/xboard.conf.in b/xboard.conf.in index 8ac0122..f76a443 100644 --- a/xboard.conf.in +++ b/xboard.conf.in @@ -60,6 +60,7 @@ -variations true -appendPV true -memoHeaders true +-autoInstall "ALL" ; ; PGN format & Game List ; diff --git a/xboard.texi b/xboard.texi index 56fa338..8703fc3 100644 --- a/xboard.texi +++ b/xboard.texi @@ -2906,6 +2906,17 @@ the last one is discarded. Changes in the list will only become visible the next session, provided you saved the settings. Default: 6. +@item -autoInstall list +@cindex autoInstall, option +When the list is set to a non-empty string, XBoard will scan the +operating system's plugin directory for engines supporting UCI +and XBoard protocol at startup. +When it finds an engine that was installed after it last saved +its settings, a line to launch that engine (as per specs in +the plugin file) is appended to the -firstChessProgramNames +list of installed engines. +In the future it will be possible to use the list to limit +this automatic adding of engines to a certain types of variants. @item -oneClickMove true/false @cindex oneClickMove, option When set, this option allows you to enter moves by only clicking the to- -- 1.7.0.4