Redo Game List Options with generic popup
[xboard.git] / args.h
diff --git a/args.h b/args.h
index fe9c7bc..a08d49b 100644 (file)
--- a/args.h
+++ b/args.h
@@ -5,7 +5,7 @@
  * Massachusetts.
  *
  * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
- * 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+ * 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
  *
  * Enhancements Copyright 2005 Alessandro Scotti
  *
@@ -60,7 +60,7 @@
 typedef enum {
   ArgString, ArgInt, ArgFloat, ArgBoolean, ArgTrue, ArgFalse, ArgNone,
   ArgColor, ArgAttribs, ArgFilename, ArgBoardSize, ArgFont, ArgCommSettings,
-  ArgSettingsFilename,
+  ArgSettingsFilename, ArgTwo,
   ArgX, ArgY, ArgZ // [HGM] placement: for window-placement options stored relative to main window
 } ArgType;
 
@@ -102,6 +102,8 @@ typedef struct {
 IcsTextMenuEntry icsTextMenuEntry[ICS_TEXT_MENU_SIZE];
 
 int junk;
+Boolean singleList;
+char *homeDir;
 
 void EnsureOnScreen(int *x, int *y, int minX, int minY);
 char StringGet(void *getClosure);
@@ -121,8 +123,6 @@ void SaveColor(FILE *f, ArgDescriptor *ad);
 void SaveBoardSize(FILE *f, char *name, void *addr);
 void PrintCommPortSettings(FILE *f, char *name);
 void GetWindowCoords();
-int  MySearchPath(char *installDir, char *name, char *fullname);
-int  MyGetFullPathName(char *name, char *fullname);
 int  MainWindowUp();
 void PopUpStartupDialog();
 typedef char GetFunc(void *getClosure);
@@ -156,8 +156,8 @@ ArgDescriptor argDescriptors[] = {
   { "phc", ArgColor, (void *) 5, FALSE, INVALID },
   { "movesPerSession", ArgInt, (void *) &appData.movesPerSession, TRUE, (ArgIniType) MOVES_PER_SESSION },
   { "mps", ArgInt, (void *) &appData.movesPerSession, FALSE, INVALID },
-  { "initString", ArgString, (void *) &appData.initString, FALSE, INVALID },
-  { "firstInitString", ArgString, (void *) &appData.initString, FALSE, (ArgIniType) INIT_STRING },
+  { "initString", ArgString, (void *) &appData.firstInitString, FALSE, INVALID },
+  { "firstInitString", ArgString, (void *) &appData.firstInitString, FALSE, (ArgIniType) INIT_STRING },
   { "secondInitString", ArgString, (void *) &appData.secondInitString, FALSE, (ArgIniType) INIT_STRING },
   { "firstComputerString", ArgString, (void *) &appData.firstComputerString,
     FALSE, (ArgIniType) COMPUTER_STRING },
@@ -206,13 +206,16 @@ ArgDescriptor argDescriptors[] = {
   { "pixmap", ArgFilename, (void *) &appData.pixmapDirectory, FALSE, INVALID },
   { "bitmapDirectory", ArgFilename, (void *) &appData.bitmapDirectory, XBOARD, (ArgIniType) "" },
   { "bm", ArgFilename, (void *) &appData.bitmapDirectory, FALSE, INVALID },
+  { "soundDirectory", ArgFilename, (void *) &appData.soundDirectory, XBOARD, (ArgIniType) "" },
   { "msLoginDelay", ArgInt, (void *) &appData.msLoginDelay, XBOARD, (ArgIniType) MS_LOGIN_DELAY },
   { "pasteSelection", ArgBoolean, (void *) &appData.pasteSelection, XBOARD, (ArgIniType) FALSE },
 
   { "dropMenu", ArgBoolean, (void *) &appData.dropMenu, TRUE, (ArgIniType) FALSE },
+  { "pieceMenu", ArgBoolean, (void *) &appData.pieceMenu, TRUE, (ArgIniType) TRUE },
+  { "sweepPromotions", ArgBoolean, (void *) &appData.sweepSelect, TRUE, (ArgIniType) FALSE },
   { "remoteShell", ArgFilename, (void *) &appData.remoteShell, FALSE, (ArgIniType) REMOTE_SHELL },
   { "rsh", ArgFilename, (void *) &appData.remoteShell, FALSE, INVALID },
-  { "remoteUser", ArgString, (void *) &appData.remoteUser, FALSE, INVALID },
+  { "remoteUser", ArgString, (void *) &appData.remoteUser, FALSE, (ArgIniType) "" },
   { "ruser", ArgString, (void *) &appData.remoteUser, FALSE, INVALID },
   { "timeDelay", ArgFloat, (void *) &appData.timeDelay, TRUE, INVALID },
   { "td", ArgFloat, (void *) &appData.timeDelay, FALSE, INVALID },
@@ -311,13 +314,14 @@ ArgDescriptor argDescriptors[] = {
   { "popUpErrors", ArgBoolean, (void *) &appData.popupMoveErrors,
     FALSE, INVALID }, /* only so that old WinBoard.ini files from betas can be read */
   { "clockFont", ArgFont, (void *) CLOCK_FONT, TRUE, INVALID },
-  { "messageFont", ArgFont, (void *) MESSAGE_FONT, !XBOARD, INVALID },
-  { "font", ArgFont, (void *) MESSAGE_FONT, XBOARD, INVALID },
+  { "messageFont", ArgFont, (void *) MESSAGE_FONT, TRUE, INVALID },
+  { "font", ArgFont, (void *) MESSAGE_FONT, FALSE, INVALID }, /* only so that old .xboardrc files will parse. -font does not work from the command line because it is captured by the X libraries. */
   { "coordFont", ArgFont, (void *) COORD_FONT, TRUE, INVALID },
   { "tagsFont", ArgFont, (void *) EDITTAGS_FONT, TRUE, INVALID },
   { "commentFont", ArgFont, (void *) COMMENT_FONT, TRUE, INVALID },
   { "icsFont", ArgFont, (void *) CONSOLE_FONT, TRUE, INVALID },
   { "moveHistoryFont", ArgFont, (void *) MOVEHISTORY_FONT, TRUE, INVALID }, /* [AS] */
+  { "gameListFont", ArgFont, (void *) GAMELIST_FONT, TRUE, INVALID }, /* [HGM] */
   { "boardSize", ArgBoardSize, (void *) &boardSize,
     TRUE, (ArgIniType) -1 }, /* must come after all fonts */
   { "size", ArgBoardSize, (void *) &boardSize, FALSE, INVALID },
@@ -417,7 +421,7 @@ ArgDescriptor argDescriptors[] = {
   { "xhighlight", ArgFalse, (void *) &appData.highlightLastMove, FALSE, INVALID },
   { "-highlight", ArgFalse, (void *) &appData.highlightLastMove, FALSE, INVALID },
   { "highlightDragging", ArgBoolean,
-    (void *) &appData.highlightDragging, TRUE, INVALID },
+    (void *) &appData.highlightDragging, !XBOARD, (ArgIniType) TRUE },
   { "highdrag", ArgTrue, (void *) &appData.highlightDragging, FALSE, INVALID },
   { "xhighdrag", ArgFalse, (void *) &appData.highlightDragging, FALSE, INVALID },
   { "-highdrag", ArgFalse, (void *) &appData.highlightDragging, FALSE, INVALID },
@@ -468,6 +472,8 @@ ArgDescriptor argDescriptors[] = {
   { "comPortSettings", ArgCommSettings, (void *) /*&dcb*/ 0, TRUE, INVALID },
   { "settingsFile", ArgSettingsFilename, (void *) &settingsFileName, FALSE, (ArgIniType) SETTINGS_FILE },
   { "ini", ArgSettingsFilename, (void *) &settingsFileName, FALSE, INVALID },
+  { "at", ArgSettingsFilename, (void *) NULL, FALSE, INVALID },
+  { "opt", ArgSettingsFilename, (void *) NULL, FALSE, INVALID },
   { "saveSettingsFile", ArgFilename, (void *) &settingsFileName, FALSE, INVALID },
   { "saveSettingsOnExit", ArgBoolean, (void *) &saveSettingsOnExit, TRUE, (ArgIniType) TRUE },
   { "chessProgram", ArgBoolean, (void *) &chessProgram, FALSE, (ArgIniType) FALSE },
@@ -476,10 +482,13 @@ ArgDescriptor argDescriptors[] = {
   { "-cp", ArgFalse, (void *) &chessProgram, FALSE, INVALID },
   { "icsMenu", ArgString, (void *) &icsTextMenuString, TRUE, (ArgIniType) ICS_TEXT_MENU_DEFAULT },
   { "icsNames", ArgString, (void *) &icsNames, TRUE, (ArgIniType) ICS_NAMES },
+  { "singleEngineList", ArgBoolean, (void *) &singleList, !XBOARD, (ArgIniType) FALSE },
+  { "recentEngines", ArgInt, (void *) &appData.recentEngines, TRUE, (ArgIniType) 6 },
+  { "recentEngineList", ArgString, (void *) &appData.recentEngineList, TRUE, (ArgIniType) "" },
   { "firstChessProgramNames", ArgString, (void *) &firstChessProgramNames,
     TRUE, (ArgIniType) FCP_NAMES },
   { "secondChessProgramNames", ArgString, (void *) &secondChessProgramNames,
-    TRUE, (ArgIniType) SCP_NAMES },
+    !XBOARD, (ArgIniType) SCP_NAMES },
   { "initialMode", ArgString, (void *) &appData.initialMode, FALSE, (ArgIniType) "" },
   { "mode", ArgString, (void *) &appData.initialMode, FALSE, INVALID },
   { "variant", ArgString, (void *) &appData.variant, FALSE, (ArgIniType) "normal" },
@@ -531,6 +540,10 @@ ArgDescriptor argDescriptors[] = {
   { "firstUCI", ArgTrue, (void *) &appData.firstIsUCI, FALSE, INVALID },
   { "secondIsUCI", ArgBoolean, (void *) &appData.secondIsUCI, FALSE, (ArgIniType) FALSE },
   { "sUCI", ArgTrue, (void *) &appData.secondIsUCI, FALSE, INVALID },
+  { "fUCCI", ArgTwo, (void *) &appData.firstIsUCI, FALSE, INVALID },
+  { "sUCCI", ArgTwo, (void *) &appData.secondIsUCI, FALSE, INVALID },
+  { "fUSI", ArgTwo, (void *) &appData.firstIsUCI, FALSE, INVALID },
+  { "sUSI", ArgTwo, (void *) &appData.secondIsUCI, FALSE, INVALID },
   { "secondUCI", ArgTrue, (void *) &appData.secondIsUCI, FALSE, INVALID },
   { "firstHasOwnBookUCI", ArgBoolean, (void *) &appData.firstHasOwnBookUCI, FALSE, (ArgIniType) TRUE },
   { "fNoOwnBookUCI", ArgFalse, (void *) &appData.firstHasOwnBookUCI, FALSE, INVALID },
@@ -539,15 +552,36 @@ ArgDescriptor argDescriptors[] = {
   { "sNoOwnBookUCI", ArgFalse, (void *) &appData.secondHasOwnBookUCI, FALSE, INVALID },
   { "secondXBook", ArgFalse, (void *) &appData.secondHasOwnBookUCI, FALSE, INVALID },
   { "adapterCommand", ArgFilename, (void *) &appData.adapterCommand, TRUE, (ArgIniType) "polyglot -noini -ec \"%fcp\" -ed \"%fd\"" },
+  { "uxiAdapter", ArgFilename, (void *) &appData.ucciAdapter, TRUE, (ArgIniType) "" },
   { "polyglotDir", ArgFilename, (void *) &appData.polyglotDir, TRUE, (ArgIniType) "" },
   { "usePolyglotBook", ArgBoolean, (void *) &appData.usePolyglotBook, TRUE, (ArgIniType) FALSE },
   { "polyglotBook", ArgFilename, (void *) &appData.polyglotBook, TRUE, (ArgIniType) "" },
   { "bookDepth", ArgInt, (void *) &appData.bookDepth, TRUE, (ArgIniType) 12 },
   { "bookVariation", ArgInt, (void *) &appData.bookStrength, TRUE, (ArgIniType) 50 },
+  { "discourageOwnBooks", ArgBoolean, (void *) &appData.defNoBook, TRUE, (ArgIniType) FALSE },
   { "defaultHashSize", ArgInt, (void *) &appData.defaultHashSize, TRUE, (ArgIniType) 64 },
   { "defaultCacheSizeEGTB", ArgInt, (void *) &appData.defaultCacheSizeEGTB, TRUE, (ArgIniType) 4 },
   { "defaultPathEGTB", ArgFilename, (void *) &appData.defaultPathEGTB, TRUE, (ArgIniType) "c:\\egtb" },
   { "language", ArgFilename, (void *) &appData.language, TRUE, (ArgIniType) "" },
+  { "userFileDirectory", ArgFilename, (void *) &homeDir, FALSE, (ArgIniType) installDir },
+  { "usePieceFont", ArgBoolean, (void *) &appData.useFont, TRUE, (ArgIniType) FALSE },
+  { "useBoardTexture", ArgBoolean, (void *) &appData.useBitmaps, TRUE, (ArgIniType) FALSE },
+
+  // [HGM] tournament options
+  { "tourneyFile", ArgFilename, (void *) &appData.tourneyFile, FALSE, (ArgIniType) "" },
+  { "tf", ArgFilename, (void *) &appData.tourneyFile, FALSE, INVALID },
+  { "participants", ArgString, (void *) &appData.participants, FALSE, (ArgIniType) "" },
+  { "tourneyType", ArgInt, (void *) &appData.tourneyType, FALSE, (ArgIniType) 0 },
+  { "tt", ArgInt, (void *) &appData.tourneyType, FALSE, INVALID },
+  { "tourneyCycles", ArgInt, (void *) &appData.tourneyCycles, FALSE, (ArgIniType) 1 },
+  { "cy", ArgInt, (void *) &appData.tourneyCycles, FALSE, INVALID },
+  { "results", ArgString, (void *) &appData.results, FALSE, (ArgIniType) "" },
+  { "syncAfterRound", ArgBoolean, (void *) &appData.roundSync, FALSE, (ArgIniType) FALSE },
+  { "syncAfterCycle", ArgBoolean, (void *) &appData.cycleSync, FALSE, (ArgIniType) TRUE },
+  { "seedBase", ArgInt, (void *) &appData.seedBase, FALSE, (ArgIniType) 1 },
+  { "pgnNumberTag", ArgBoolean, (void *) &appData.numberTag, TRUE, (ArgIniType) FALSE },
+  { "afterGame", ArgString, (void *) &appData.afterGame, FALSE, INVALID },
+  { "afterTourney", ArgString, (void *) &appData.afterTourney, FALSE, INVALID },
 
   /* [HGM] board-size, adjudication and misc. options */
   { "oneClickMove", ArgBoolean, (void *) &appData.oneClick, TRUE, (ArgIniType) FALSE },
@@ -559,8 +593,8 @@ ArgDescriptor argDescriptors[] = {
   { "pieceToCharTable", ArgString, (void *) &appData.pieceToCharTable, FALSE, INVALID },
   { "pieceNickNames", ArgString, (void *) &appData.pieceNickNames, FALSE, INVALID },
   { "colorNickNames", ArgString, (void *) &appData.colorNickNames, FALSE, INVALID },
-  { "flipBlack", ArgBoolean, (void *) &appData.upsideDown, TRUE, (ArgIniType) FALSE },
-  { "allWhite", ArgBoolean, (void *) &appData.allWhite, TRUE, (ArgIniType) FALSE },
+  { "flipBlack", ArgBoolean, (void *) &appData.upsideDown, FALSE, (ArgIniType) FALSE },
+  { "allWhite", ArgBoolean, (void *) &appData.allWhite, FALSE, (ArgIniType) FALSE },
   { "alphaRank", ArgBoolean, (void *) &appData.alphaRank, FALSE, (ArgIniType) FALSE },
   { "firstAlphaRank", ArgBoolean, (void *) &first.alphaRank, FALSE, (ArgIniType) FALSE },
   { "secondAlphaRank", ArgBoolean, (void *) &second.alphaRank, FALSE, (ArgIniType) FALSE },
@@ -580,17 +614,45 @@ ArgDescriptor argDescriptors[] = {
   { "smpCores", ArgInt, (void *) &appData.smpCores, TRUE, (ArgIniType) 1 },
   { "egtFormats", ArgString, (void *) &appData.egtFormats, TRUE, (ArgIniType) "" },
   { "niceEngines", ArgInt, (void *) &appData.niceEngines, TRUE, INVALID },
-  { "firstLogo", ArgFilename, (void *) &appData.firstLogo, FALSE, INVALID },
-  { "secondLogo", ArgFilename, (void *) &appData.secondLogo, FALSE, INVALID },
+  { "firstLogo", ArgFilename, (void *) &appData.firstLogo, FALSE, (ArgIniType) "" },
+  { "secondLogo", ArgFilename, (void *) &appData.secondLogo, FALSE, (ArgIniType) "" },
   { "autoLogo", ArgBoolean, (void *) &appData.autoLogo, TRUE, INVALID },
   { "firstOptions", ArgString, (void *) &appData.firstOptions, FALSE, (ArgIniType) "" },
   { "secondOptions", ArgString, (void *) &appData.secondOptions, FALSE, (ArgIniType) "" },
+  { "firstFeatures", ArgString, (void *) &appData.features[0], FALSE, (ArgIniType) "" },
+  { "secondFeatures", ArgString, (void *) &appData.features[1], FALSE, (ArgIniType) "" },
+  { "featureDefaults", ArgString, (void *) &appData.featureDefaults, TRUE, (ArgIniType) "" },
   { "firstNeedsNoncompliantFEN", ArgString, (void *) &appData.fenOverride1, FALSE, (ArgIniType) NULL },
   { "secondNeedsNoncompliantFEN", ArgString, (void *) &appData.fenOverride2, FALSE, (ArgIniType) NULL },
   { "keepAlive", ArgInt, (void *) &appData.keepAlive, FALSE, INVALID },
   { "icstype", ArgInt, (void *) &ics_type, FALSE, INVALID },
   { "forceIllegalMoves", ArgTrue, (void *) &appData.forceIllegal, FALSE, INVALID },
-  { "showTargetSquares", ArgBoolean, (void *) &appData.markers, TRUE, FALSE },
+  { "showTargetSquares", ArgBoolean, (void *) &appData.markers, TRUE, (ArgIniType) FALSE },
+  { "firstPgnName", ArgString, (void *) &appData.pgnName[0], FALSE, (ArgIniType) "" },
+  { "fn", ArgString, (void *) &appData.pgnName[0], FALSE, INVALID },
+  { "secondPgnName", ArgString, (void *) &appData.pgnName[1], FALSE, (ArgIniType) "" },
+  { "sn", ArgString, (void *) &appData.pgnName[1], FALSE, INVALID },
+  { "absoluteAnalysisScores", ArgBoolean, (void *) &appData.whitePOV, TRUE, FALSE },
+  { "scoreWhite", ArgBoolean, (void *) &appData.scoreWhite, TRUE, FALSE },
+  { "evalZoom", ArgInt, (void *) &appData.zoom, TRUE, (ArgIniType) 1 },
+  { "evalThreshold", ArgInt, (void *) &appData.evalThreshold, TRUE, (ArgIniType) 25 },
+  { "fSAN", ArgTrue, (void *) &appData.pvSAN[0], FALSE, FALSE },
+  { "sSAN", ArgTrue, (void *) &appData.pvSAN[1], FALSE, FALSE },
+  { "pairingEngine", ArgFilename, (void *) &appData.pairingEngine, TRUE, "" },
+  { "defaultTourneyName", ArgFilename, (void *) &appData.defName, TRUE, "" },
+  { "eloThresholdAny", ArgInt, (void *) &appData.eloThreshold1, FALSE, (ArgIniType) 0 },
+  { "eloThresholdBoth", ArgInt, (void *) &appData.eloThreshold2, FALSE, (ArgIniType) 0 },
+  { "dateThreshold", ArgInt, (void *) &appData.dateThreshold, FALSE, (ArgIniType) 0 },
+  { "searchMode", ArgInt, (void *) &appData.searchMode, FALSE, (ArgIniType) 1 },
+  { "stretch", ArgInt, (void *) &appData.stretch, FALSE, (ArgIniType) 1 },
+  { "ignoreColors", ArgBoolean, (void *) &appData.ignoreColors, FALSE, FALSE },
+  { "findMirrorImage", ArgBoolean, (void *) &appData.findMirror, FALSE, FALSE },
+  { "viewer", ArgTrue, (void *) &appData.viewer, FALSE, FALSE },
+  { "viewerOptions", ArgString, (void *) &appData.viewerOptions, TRUE, (ArgIniType) "-ncp -engineOutputUp false -saveSettingsOnExit false" },
+  { "autoCopyPV", ArgBoolean, (void *) &appData.autoCopyPV, TRUE, FALSE },
+  { "topLevel", ArgBoolean, (void *) &appData.topLevel, XBOARD, (ArgIniType) TOPLEVEL },
+  { "dialogColor", ArgString, (void *) &appData.dialogColor, XBOARD, (ArgIniType) "" },
+  { "buttonColor", ArgString, (void *) &appData.buttonColor, XBOARD, (ArgIniType) "" },
 
 #if ZIPPY
   { "zippyTalk", ArgBoolean, (void *) &appData.zippyTalk, FALSE, (ArgIniType) ZIPPY_TALK },
@@ -638,6 +700,7 @@ ArgDescriptor argDescriptors[] = {
   /* [HGM] options for broadcasting and time odds */
   { "chatBoxes", ArgString, (void *) &appData.chatBoxes, !XBOARD, (ArgIniType) NULL },
   { "serverMoves", ArgString, (void *) &appData.serverMovesName, FALSE, (ArgIniType) NULL },
+  { "serverFile", ArgString, (void *) &appData.serverFileName, FALSE, (ArgIniType) NULL },
   { "suppressLoadMoves", ArgBoolean, (void *) &appData.suppressLoadMoves, FALSE, (ArgIniType) FALSE },
   { "serverPause", ArgInt, (void *) &appData.serverPause, FALSE, (ArgIniType) 15 },
   { "firstTimeOdds", ArgInt, (void *) &appData.firstTimeOdds, FALSE, (ArgIniType) 1 },
@@ -651,9 +714,10 @@ ArgDescriptor argDescriptors[] = {
   { "keepLineBreaksICS", ArgBoolean, (void *) &appData.noJoin, TRUE, INVALID },
   { "wrapContinuationSequence", ArgString, (void *) &appData.wrapContSeq, FALSE, INVALID },
   { "useInternalWrap", ArgTrue, (void *) &appData.useInternalWrap, FALSE, INVALID }, /* noJoin usurps this if set */
+  { "openCommand", ArgString, (void *) &appData.sysOpen, FALSE, "xdg-open" },
 
   // [HGM] placement: put all window layouts last in ini file, but man X,Y before all others
-  { "minX", ArgZ, (void *) &minX, FALSE, INVALID }, // [HGM] placement: to make suer auxialary windows can be placed
+  { "minX", ArgZ, (void *) &minX, FALSE, INVALID }, // [HGM] placement: to make sure auxiliary windows can be placed
   { "minY", ArgZ, (void *) &minY, FALSE, INVALID },
   { "winWidth",  ArgInt, (void *) &wpMain.width,  TRUE, INVALID }, // [HGM] placement: dummies to remember right & bottom
   { "winHeight", ArgInt, (void *) &wpMain.height, TRUE, INVALID }, //       for attaching auxiliary windows to them
@@ -708,15 +772,16 @@ ArgDescriptor argDescriptorIndirection =
 { "", ArgSettingsFilename, (void *) NULL, FALSE };
 
 void
-ExitArgError(char *msg, char *badArg)
+ExitArgError(char *msg, char *badArg, Boolean quit)
 {
   char buf[MSG_SIZ];
   int len;
 
-  len = snprintf(buf,MSG_SIZ, "%s %s", msg, badArg);
-  if( (len > MSG_SIZ) && appData.debugMode )
+  len = snprintf(buf, MSG_SIZ, msg, badArg);
+  if( (len >= MSG_SIZ) && appData.debugMode )
     fprintf(debugFP, "ExitArgError: buffer truncated. Input: msg=%s badArg=%s\n", msg, badArg);
 
+  if(!quit) { printf(_("%s in settings file\n"), buf); return; } // DisplayError does not work yet at this stage...
   DisplayFatalError(buf, 0, 2);
   exit(2);
 }
@@ -726,7 +791,7 @@ ValidateInt(char *s)
 {
   char *p = s;
   if(*p == '-' || *p == '+') p++;
-  while(*p) if(!isdigit(*p++)) ExitArgError("Bad integer value", s);
+  while(*p) if(!isdigit(*p++)) ExitArgError(_("Bad integer value %s"), s, TRUE);
   return atoi(s);
 }
 
@@ -765,7 +830,7 @@ ParseSettingsFile(char *name, char **addr)
   if(!ok && strchr(name, '.') == NULL)
     { // append default file-name extension '.ini' when needed
       len = snprintf(buf,MSG_SIZ, "%s.ini", name);
-      if( (len > MSG_SIZ) && appData.debugMode )
+      if( (len >= MSG_SIZ) && appData.debugMode )
        fprintf(debugFP, "ParseSettingsFile: buffer truncated. Input: name=%s \n",name);
 
       ok = MySearchPath(installDir, buf, fullname);
@@ -774,7 +839,7 @@ ParseSettingsFile(char *name, char **addr)
     f = fopen(fullname, "r");
     if (f != NULL) {
       if (addr != NULL) {
-           *addr = strdup(fullname);
+           ASSIGN(*addr, fullname);
       }
       ParseArgs(FileGet, f);
       fclose(f);
@@ -814,13 +879,13 @@ ParseArgs(GetFunc get, void *cl)
        ch = get(cl);
       }
       *q = NULLCHAR;
-
       for (ad = argDescriptors; ad->argName != NULL; ad++)
        if (strcmp(ad->argName, argName + 1) == 0) break;
-
-      if (ad->argName == NULL)
-       ExitArgError("Unrecognized argument", argName);
-
+      if (ad->argName == NULL) {
+       ExitArgError(_("Unrecognized argument %s"), argName, get != &FileGet); // [HGM] make unknown argument non-fatal
+       while (ch != '\n' && ch != NULLCHAR) ch = get(cl); // but skip rest of line it is on
+       continue; // so that when it is in a settings file, it is the only setting that will be purged from it
+      }
     } else if (ch == '@') {
       /* Indirection file */
       ad = &argDescriptorIndirection;
@@ -831,6 +896,10 @@ ParseArgs(GetFunc get, void *cl)
       strncpy(argName, ad->argName,sizeof(argName)/sizeof(argName[0]));
     }
 
+    if (ad->argType == ArgTwo) { // [HGM] kludgey arg type, not suitable for saving
+      *(Boolean *) ad->argLoc = 2;
+      continue;
+    }
     if (ad->argType == ArgTrue) {
       *(Boolean *) ad->argLoc = TRUE;
       continue;
@@ -842,7 +911,7 @@ ParseArgs(GetFunc get, void *cl)
 
     while (ch == ' ' || ch == '=' || ch == ':' || ch == '\t') ch = get(cl);
     if (ch == NULLCHAR || ch == '\n') {
-      ExitArgError("No value provided for argument", argName);
+      ExitArgError(_("No value provided for argument %s"), argName, TRUE);
     }
     q = argValue;
     if (ch == '{') {
@@ -902,7 +971,7 @@ ParseArgs(GetFunc get, void *cl)
          ch = get(cl);
          switch (ch) {
          case NULLCHAR:
-           ExitArgError("Incomplete \\ escape in value for", argName);
+           ExitArgError(_("Incomplete \\ escape in value for %s"), argName, TRUE);
            break;
          case 'n':
            *q++ = '\n';
@@ -977,7 +1046,7 @@ ParseArgs(GetFunc get, void *cl)
 
     case ArgString:
     case ArgFilename:
-      *(char **) ad->argLoc = strdup(argValue);
+      ASSIGN(*(char **) ad->argLoc, argValue);
       break;
 
     case ArgSettingsFilename:
@@ -986,7 +1055,7 @@ ParseArgs(GetFunc get, void *cl)
        } else {
          if (ad->argLoc != NULL) {
          } else {
-           ExitArgError("Failed to open indirection file", argValue);
+           ExitArgError(_("Failed to open indirection file %s"), argValue, TRUE);
          }
        }
       }
@@ -1003,13 +1072,13 @@ ParseArgs(GetFunc get, void *cl)
        *(Boolean *) ad->argLoc = FALSE;
        break;
       default:
-       ExitArgError("Unrecognized boolean argument value", argValue);
+       ExitArgError(_("Unrecognized boolean argument value %s"), argValue, TRUE);
        break;
       }
       break;
 
     case ArgColor:
-      ParseColor((int)ad->argLoc, argValue);
+      ParseColor((int)(intptr_t)ad->argLoc, argValue);
       break;
 
     case ArgAttribs: {
@@ -1023,7 +1092,7 @@ ParseArgs(GetFunc get, void *cl)
       break;
 
     case ArgFont:
-      ParseFont(argValue, (int)ad->argLoc);
+      ParseFont(argValue, (int)(intptr_t)ad->argLoc);
       break;
 
     case ArgCommSettings:
@@ -1031,14 +1100,27 @@ ParseArgs(GetFunc get, void *cl)
       break;
 
     case ArgNone:
-      ExitArgError("Unrecognized argument", argValue);
+      ExitArgError(_("Unrecognized argument %s"), argValue, TRUE);
       break;
+    case ArgTwo:
     case ArgTrue:
     case ArgFalse: ;
     }
   }
 }
 
+void
+ParseArgsFromString(char *p)
+{
+    ParseArgs(StringGet, &p);
+}
+
+void
+ParseArgsFromFile(FILE *f)
+{
+    ParseArgs(FileGet, f);
+}
+
 void
 ParseIcsTextMenu(char *icsTextMenuString)
 {
@@ -1117,26 +1199,28 @@ SetDefaultsFromList()
     if(argDescriptors[i].defaultValue != INVALID)
       switch(argDescriptors[i].argType) {
         case ArgBoolean:
+        case ArgTwo:
         case ArgTrue:
         case ArgFalse:
-          *(Boolean *) argDescriptors[i].argLoc = (int)argDescriptors[i].defaultValue;
+          *(Boolean *) argDescriptors[i].argLoc = (int)(intptr_t)argDescriptors[i].defaultValue;
           break;
         case ArgInt:
         case ArgX:
         case ArgY:
         case ArgZ:
-          *(int *) argDescriptors[i].argLoc = (int)argDescriptors[i].defaultValue;
+          *(int *) argDescriptors[i].argLoc = (int)(intptr_t)argDescriptors[i].defaultValue;
           break;
         case ArgString:
         case ArgFilename:
         case ArgSettingsFilename:
-          *(char **) argDescriptors[i].argLoc = (char *)argDescriptors[i].defaultValue;
+          if((char *)argDescriptors[i].defaultValue)
+          *(char **) argDescriptors[i].argLoc = strdup((char *)argDescriptors[i].defaultValue);
           break;
         case ArgBoardSize:
-          *(int *) argDescriptors[i].argLoc = (int)argDescriptors[i].defaultValue;
+          *(int *) argDescriptors[i].argLoc = (int)(intptr_t)argDescriptors[i].defaultValue;
           break;
         case ArgColor:
-          ParseColor((int)argDescriptors[i].argLoc, (char*)argDescriptors[i].defaultValue);
+          ParseColor((int)(intptr_t)argDescriptors[i].argLoc, (char*)argDescriptors[i].defaultValue);
           break;
         case ArgFloat: // floats cannot be casted to int without precision loss
         default: ; // some arg types cannot be initialized through table
@@ -1173,6 +1257,8 @@ InitAppData(char *lpCmdLine)
   /* Parse command line */
   ParseArgs(StringGet, &lpCmdLine);
 
+  if(appData.viewer && appData.viewerOptions[0]) ParseArgsFromString(appData.viewerOptions);
+
   /* [HGM] make sure board size is acceptable */
   if(appData.NrFiles > BOARD_FILES ||
      appData.NrRanks > BOARD_RANKS   )
@@ -1193,7 +1279,7 @@ InitAppData(char *lpCmdLine)
       if(p != NULL)
        { // engine command line contains WinBoard options
           len = snprintf(buf, MSG_SIZ, p+6, f, f, f, f, f, f, f, f, f, f); // replace %s in them by "first"
-         if( (len > MSG_SIZ) && appData.debugMode )
+         if( (len >= MSG_SIZ) && appData.debugMode )
            fprintf(debugFP, "InitAppData: buffer truncated.\n");
 
           ParseArgs(StringGet, &q);
@@ -1210,7 +1296,7 @@ InitAppData(char *lpCmdLine)
       if(p != NULL)
        { // engine command line contains WinBoard options
           len = snprintf(buf,MSG_SIZ, p+6, s, s, s, s, s, s, s, s, s, s); // replace %s in them by "first"
-         if( (len > MSG_SIZ) && appData.debugMode )
+         if( (len >= MSG_SIZ) && appData.debugMode )
            fprintf(debugFP, "InitAppData: buffer truncated.\n");
 
           ParseArgs(StringGet, &q);
@@ -1381,6 +1467,7 @@ SaveSettings(char* name)
       break;
     case ArgCommSettings:
       PrintCommPortSettings(f, ad->argName);
+    case ArgTwo:
     case ArgNone:
     case ArgSettingsFilename: ;
     }
@@ -1408,13 +1495,13 @@ GetArgValue(char *name)
       return TRUE;
     case ArgInt:
       len = snprintf(name, MSG_SIZ, "%d", *(int*) ad->argLoc);
-      if( (len > MSG_SIZ) && appData.debugMode )
+      if( (len >= MSG_SIZ) && appData.debugMode )
        fprintf(debugFP, "GetArgValue: buffer truncated.\n");
 
       return TRUE;
     case ArgBoolean:
       len = snprintf(name, MSG_SIZ, "%s", *(Boolean*) ad->argLoc ? "true" : "false");
-      if( (len > MSG_SIZ) && appData.debugMode )
+      if( (len >= MSG_SIZ) && appData.debugMode )
        fprintf(debugFP, "GetArgValue: buffer truncated.\n");
 
       return TRUE;