Modificaciones introducidas por F. Gracia en los ficheros de Winboard versión 4.2.6.

Fecha: 9 de diciembre de 2003.


RECURSOS DE WINDOWS

- Marcar 'Grayed' en Workspace > winboard resources > menu > "winboard" > 
	- File >
		Load next game
		Load previous game
		Reload same game
		Load next position
		Load previous positon
		Reload same position
	- Mode >
		Show game list

- Desactivar la casilla AutoHScroll en el panel de configuración del diálogo que presenta los comentarios a las partidas, al que se llega desde la ventana de proyecto seleccionando sucesivamente: workspace > winboard resources > dialog > DLG_EditComment [English(U.S.)] > RichEdit > Properties > Styles.

- Hacer lo mismo con el recuadro del diálogo DLG_EditTags.




FICHEROS DE ENCABEZAMIENTO

backend.h

// (FG)

// Extracción de un posible identificador de la posición
void GetIdent (char *, char *);
// Presentación de información relativa a la posición
void PresentInfo(char * title, char * line, int positionNumber);
// Traducción de los símbolos de pieza a un idioma nacional
void TranslateMoveList(char * transBuf,
                          char * lista, char * localSymbols);
// Traducción de los símbolos de pieza de un idioma a internacional 
void NormalizePieceSymbols(char * transBuf);

extern void AllowDisplacement();

//



common. h

(Véase el documento Languages.txt)



frontend.h

//
void SetSingleGame();      // (FG)
void SetSinglePosition();
//



languages.h

(Véase el documento Languages.txt)



lists.h

int ListTotal P((List * listp));   // (FG)



winboard.h

VOID AllowDisplacement(VOID); // (FG)




FICHEROS FUENTE

backend.c

#include <windows.h>   /* required for all Windows applications (FG) */

// (FG)

char identificador[MSG_SIZ];	// texto identificador de posición
extern BOOLEAN analysisDemanded;

//

   .
   .
   .

void
InitBackEnd3 P((void))
{
   .
   .
   .
         TrainingEvent();
      }
   }

   AllowDisplacement();  // (FG)
}

   .
   .
   .

FILE *lastLoadGameFP = NULL, *lastLoadPositionFP = NULL;
int lastLoadGameNumber = 0, lastLoadPositionNumber = 0;
int lastLoadGameUseList = FALSE;
char lastLoadGameTitle[MSG_SIZ], lastLoadPositionTitle[MSG_SIZ];
ChessMove lastLoadGameStart = (ChessMove) 0;

//
int lastMult = FALSE;	// FG
int positionCount = 0;
//

   .
   .
   .
int
AutoPlayOneMove()
{
   .
   .
   .
   if (commentList[currentMove] != NULL)
   {
      DisplayComment(currentMove - 1, commentList[currentMove]);
   }
//
   // ocultar los comentarios a jugadas precedentes (FG)
   else
   {
	// DisplayComment( -1, "");	// título y texto vacíos
      // hacer desaparecer el recuadro
      CommentPopDown();
   }
   // ocultar también las circunstancias de la partida
   if (currentMove == 2)
      TagsPopDown();
//
   return TRUE;
}
   .
   .
   .

int
LoadGameOneMove(readAhead)
     ChessMove readAhead;
{
   .
   .
   .

         if (!appData.matchMode && commentList[currentMove] != NULL)
            DisplayComment(currentMove - 1, commentList[currentMove]);
//		  
   	   // no mostrar comentarios incorrectos (FG)
	   else
         {
		// DisplayComment( -1, "");
	    	// hacer desaparecer el recuadro
		CommentPopDown();
         }
//
      }

      (void) StopLoadGameTimer();
   .
   .
   .
}


/* Support for LoadNextGame, LoadPreviousGame, ReloadSameGame */
int
ReloadGame(offset)
     int offset;
{
   .
   .
   .
   if (gameNumber <= 0)
   {
	// DisplayError("Can't back up any further", 0);
      // DisplayError(firstGame, 0); // (FG)
      MessageBox(NULL, firstGame, "WinBoard", MB_OK|MB_ICONEXCLAMATION);
      return FALSE;
   }

//    (FG)
   else if (gameNumber > ListTotal(&gameList))
   {
	// DisplayError(lastGame, 0); // (FG)
      MessageBox(NULL, lastGame, "WinBoard", MB_OK|MB_ICONEXCLAMATION);
	return FALSE;
   }

//

   if (cmailMsgLoaded)
   .
   .
   .
}


/* Load the nth game from open file f */
int
LoadGame(f, gameNumber, title, useList)
     FILE * f;
     int gameNumber;
     char * title;
     int useList;
{
   .
   .
   .

   gameFileFP = f;
   if (lastLoadGameFP != NULL && lastLoadGameFP != f)
   {
   	fclose(lastLoadGameFP);

      analysisDemanded = FALSE;  // (FG)
   }
   .
   .
   .

   yynewfile(f);

   // elaboración de los rótulos identificativos (FG)	

   // si hay más de una partida en el fichero
   // y hay información de los contendientes
   if (lg && lg->gameInfo.white && lg->gameInfo.black)
   {
      // mostrar sus nombres
      sprintf(buf, "%s vs. %s", lg->gameInfo.white,
		           lg->gameInfo.black);
      DisplayTitle(buf);
   }
   // cuando no hay más que una partida
   // no se dispone todavía de información sobre
   // los contendientes; limitarse al nombre del
   // fichero
   else if (* title != NULLCHAR)
   {
//    if (gameNumber > 1)	// ¿por que omitir el primero?
      // no numerar las partidas únicas,
      // pero sí las múltiples desde la primera
      if (lg && gameNumber > 0)	// enumerarlos todos
      {
         sprintf(buf, "%s %d", title, gameNumber);
         DisplayTitle(buf);
      }
      else
      {
         // mostrar el nombre del fichero, si no hay otra cosa
         DisplayTitle(title);
      }
   }
   .
   .
   .
   if (commentList[currentMove] != NULL)
   {
      if (!matchMode && (pausing || appData.timeDelay != 0))
      {
         DisplayComment(currentMove - 1, commentList[currentMove]);
      }
//
      // no mostrar comentarios de jugadas previas (FG)
	else
	{
	   // DisplayComment( -1, "");
	   // hacer desaparecer el recuadro
	   CommentPopDown();
	}
      // ocultar también las circunstancias de la partida
      if (currentMove == 2)
         TagsPopDown();
//
   }
   .
   .
   .
// (FG)
   // Reflejar la situación en las opciones de menú activas
   AllowDisplacement();
   if (! lg)
      SetSingleGame();

   // pero impedir al acceso a una posible lista de posiciones
   // en todo caso
   SetSinglePosition();
//

   /* rewind to the start of the game */
   currentMove = backwardMostMove;
   .
   .
   .
}


/* Support for LoadNextPosition, LoadPreviousPosition, ReloadSamePosition */
int
ReloadPosition(offset)
     int offset;
{
   int positionNumber = lastLoadPositionNumber + offset;
   if (lastLoadPositionFP == NULL)
   {
      // DisplayError("No position has been loaded yet", 0);
      MessageBox(NULL, noPosition, "WinBoard", MB_OK|MB_ICONEXCLAMATION);
      return FALSE;
   }

   // si se intenta retroceder pasado el inicio de la lista
   if (positionNumber <= 0)
   {
      // DisplayError("Can't back up any further", 0);
      // DisplayError("This is the first position available.", 0);
      MessageBox(NULL, firstPosition, "WinBoard", MB_OK|MB_ICONEXCLAMATION);
	return FALSE;
   }

//
   // si no hay posiciones disponibles
   else if (positionCount == 0)
   {
      MessageBox(NULL, noPosition, "WinBoard", MB_OK|MB_ICONEXCLAMATION);
      return FALSE;
   }

   // o se intenta avanzar más allá de su final
   else if (positionNumber > positionCount)
   {
      // DisplayError("This is the last position available.", 0);
      MessageBox(NULL, lastPosition, "WinBoard", MB_OK|MB_ICONEXCLAMATION);
	return FALSE;
   }
//
   // si todo está en orden, presentar la posición
   return LoadPosition(lastLoadPositionFP, positionNumber,
	                		lastLoadPositionTitle);
}


/* Load the nth position from the given open file, and close it */
// (Note: the file remains open until a different one
// is accessed. (FG))
int
LoadPosition(f, positionNumber, title)
     FILE * f;
     int positionNumber;
     char * title;
{
   // char * p, line[MSG_SIZ];
   char line[MSG_SIZ];
   Board initial_position;    // tablero receptor provisional
   // int i, j, fenMode, pn;
   int fenMode, pn;

// (FG)
   fenMode = FALSE;
   pn = 0;
   line[0] = NULLCHAR;
//

   if (gameMode == Training)
	SetTrainingModeOff();

   if (gameMode != BeginningOfGame)
   {
      Reset(FALSE, TRUE);
   }

   // comprobar si ha cambiado el fichero de origen
   if (lastLoadPositionFP != NULL && lastLoadPositionFP != f)
   {
      fclose(lastLoadPositionFP);
//
      lastMult = FALSE;	// se trata de otro fichero (FG)
      positionCount = 0;
//
   }

   if (positionNumber == 0)
      positionNumber = 1;
   lastLoadPositionFP = f;
   lastLoadPositionNumber = positionNumber;
   strcpy(lastLoadPositionTitle, title);
   if (first.pr == NoProc)
   {
      StartChessProgram(&first);
      InitChessProgram(&first);
   }    

//
   // ver si el nuevo fichero es múltiple (FG)
   if (lastMult == FALSE && positionCount == 0)
   {
      while (fgets(line, MSG_SIZ, f)) 
	{
	   if (ParseFEN(initial_position, &blackPlaysFirst, line))
	      positionCount++;  // contar las líneas con posiciones válidas			
	}
/*
      // If there are no FEN positions, try if they are 'Old style'
      if (positionCount == 0)
      {
         // reubicar el puntero al inicio del fichero
         fseek(f, 0, SEEK_SET);
         while (fgets(line, MSG_SIZ, f)) 
	   {
	      if (ParseOldStyle(initial_position, &blackPlaysFirst, line))
	         positionCount++;  // contar las líneas con posiciones válidas			
	   }
      }
*/

      if (positionCount > 1)
         lastMult = TRUE;	// el fichero contiene varias posiciones
   }

   // Esta forma de disponer la bandera es necesaria
   // para los accesos sin nueva exploración del archivo origen
   // Requerirá cambios si se reactiva el 'Old style'
   if (positionCount)
      fenMode = TRUE;   // hay al menos una posición válida
	
   // reubicar el puntero al inicio del fichero
   fseek(f, 0, SEEK_SET);
   // Reflejar la situación en las opciones de menú activas
   AllowDisplacement();
   // pero impedir al acceso a una posible lista de juegos
   // concurrente en todo caso
   SetSingleGame();
   // cerrar posibles recuadros de comentarios y circunstancias
   // de un juego previo
   TagsPopDown();
   CommentPopDown();
//

   pn = positionNumber;    // contador de posiciones a saltar

   // situarse en el lugar adecuado del fichero
   // a) a un desplazamiento determinado del principio
   if (positionNumber < 0)
   {
      /* Negative position number means to seek to that byte offset */
      if (fseek(f, -positionNumber, 0) == -1)
      {
	   // DisplayError("Can't seek on position file", 0);
	   DisplayError(noSeekPosition, 0);
	   return FALSE;
	}
	pn = 1;
   }
   else
   {
      if (fseek(f, 0, 0) == -1)  // b) colocarse al inicio
      {
         if (f == lastLoadPositionFP ?
		             positionNumber == lastLoadPositionNumber + 1 :
		             positionNumber == 1)
         {
	      pn = 1;
	   }
	   else
	   {
		// DisplayError("Can't seek on position file", 0);
            DisplayError(noSeekPosition, 0);
		return FALSE;
	   }
	}
   }

   /* See if this file is FEN or old-style xboard */
/*
    // buscar la primera posición, si la hay
    if (fgets(line, MSG_SIZ, f) == NULL)
    {
	 // DisplayError("Position not found in file", 0);
       DisplayError(noPositionFound, 0);
       return FALSE;
    }

    switch (line[0])
    {
       case '#':  case 'x':
       default:
	    fenMode = FALSE;
	    break;
       case 'p':  case 'n':  case 'b':  case 'r':  case 'q':  case 'k':
       case 'P':  case 'N':  case 'B':  case 'R':  case 'Q':  case 'K':
       case '1':  case '2':  case '3':  case '4':  case '5':  case '6':
       case '7':  case '8':
	    fenMode = TRUE;
	    break;
    }

    if (pn >= 2)
    {
	 if (fenMode || line[0] == '#')
	    pn--;
	 while (pn > 0)
       {
	    /* skip postions before number pn */
/*
          if (fgets(line, MSG_SIZ, f) == NULL)
          {
		 // DisplayError("Position not found in file", 0);
      	 DisplayError(noPositionFound, 0);
		 return FALSE;
          }
	    
	    if (fenMode || line[0] == '#')
	       pn--;
       }
    }

    if (fenMode)
    {
       if (!ParseFEN(initial_position, &blackPlaysFirst, line))
       {
	    DisplayError("Bad FEN position in file", 0);
	    return FALSE;
	 }
    }
    else    // old style
    {
       (void) fgets(line, MSG_SIZ, f);	// saltarse una línea
       (void) fgets(line, MSG_SIZ, f);
    
       for (i = BOARD_SIZE - 1; i >= 0; i--)
       {
          (void) fgets(line, MSG_SIZ, f);
          for (p = line, j = 0; j < BOARD_SIZE; p++)
          {
	       if (* p == ' ')
	          continue;
	       initial_position[i][j++] = CharToPiece(* p);
          }
       }
    
       blackPlaysFirst = FALSE;
       if (!feof(f))
       {
          (void) fgets(line, MSG_SIZ, f);
          if (strncmp(line, "black", strlen("black")) == 0)
             blackPlaysFirst = TRUE;
       }
    }
*/

//
   if (fenMode)
   {
      // localizar la posición deseada
      while ((positionNumber <= positionCount) && (pn > 0))
      {
         // continuar leyendo líneas hasta el final del fichero
         if (fgets(line, MSG_SIZ, f) == NULL)
         {
            // el programa nunca debería llegar aquí
            Reset(TRUE, TRUE);	// usar el tablero inicial (FG)
		// DisplayError("Bad FEN position in file", 0);
            DisplayError(noMoreFEN, 0);
	      return FALSE;
         }
         // comprobar si esta línea concreta es una posición FEN
         if (ParseFEN(initial_position, &blackPlaysFirst, line))
            pn--;         // contar las posiciones que faltan 
      }    
      // estamos ante una posición válida, que es la deseada
   }
   else
   {
      DisplayError(noFEN, 0);
      return FALSE;
   }
//

   startedFromSetupPosition = TRUE;
    
   SendToProgram("force\n", &first);
   CopyBoard(boards[0], initial_position);   // posición elegida
   if (blackPlaysFirst)
   {
      currentMove = forwardMostMove = backwardMostMove = 1;
      strcpy(moveList[0], "");
      strcpy(parseList[0], "");
      CopyBoard(boards[1], initial_position);
	// DisplayMessage("", "Black to play");
	DisplayMessage("", blackToPlay);
   }
   else
   {
      currentMove = forwardMostMove = backwardMostMove = 0;
	// DisplayMessage("", "White to play");
	DisplayMessage("", whiteToPlay);
   }
   SendBoard(&first, forwardMostMove);

   // elaborar los identificadores
/*
   if (positionNumber > 1)
   {
      sprintf(line, "%s %d", title, positionNumber);
      DisplayTitle(line);
   }
   else
   {
      DisplayTitle(title);
   }
}
*/

//
   // ver si hay un texto identificador entre paréntesis
   GetIdent(line, identificador);
   PresentInfo(title, line, positionNumber);
//

   gameMode = EditGame;
   ModeHighlight();
   ResetClocks();
   timeRemaining[0][1] = whiteTimeRemaining;
   timeRemaining[1][1] = blackTimeRemaining;
   DrawPosition(FALSE, boards[currentMove]); // presentar el tablero
   
   return TRUE;
}


//
/* Extracción de un posible identificador de la posición (FG) */
void 
GetIdent(char * source, char * destination)
{
   int largo;	// longitud de la sarta identificadora
   char * origen, * final;

   * destination = NULLCHAR;
   origen = strchr(source, '(');
   if (origen)
   {
      final = strchr(source, ')');
      if (final)
      {
         largo = final - origen + 1;
         strncpy(destination, origen, largo);
         destination[largo] = NULLCHAR;
      }
	else
      {
	   // llegar hasta el final de la línea
	   strcpy(destination, origen);
         // añadir el paréntesis de cierre
         largo = strlen(destination);
         while (destination[largo] == ' ' ||
                       destination[largo] == '\n'); // 0x0a
            largo--;
         destination[largo] = ')';
         destination[largo + 1] = NULLCHAR;
      }
   }
   else
	strcpy(destination, "");

   return; 
}


/* Presentación de información relativa a la posición (FG) */
void
PresentInfo(char * title, char * line, int positionNumber)
{
   char titulillo[MSG_SIZ];
   char * origen;

   // Elaborarla primero

   // eliminar la ruta y el sufijo del fichero fuente
   * titulillo = NULLCHAR;
   origen = strrchr(title, '\\');
   if (origen)
      strcpy(titulillo, origen + 1); 
   else
      strcpy(titulillo, title);

   titulillo[strchr(titulillo, '.') - titulillo] = NULLCHAR;

   if (lastMult)	// si es un fichero múltiple,
   {
      // numerar desde la primera posición
      sprintf(line, deEntre, titulillo,
                        positionNumber, positionCount);
      if (identificador)
      {
         strcat(line, " ");
         strcat(line, identificador);
      }
      DisplayTitle(line);
   }
   else	// si no, limitarse al nombre del fichero
   {
      DisplayTitle(titulillo);
   }
   return;
}

//


void
ForwardInner(target)
     int target;
{
   .
   .
   .
      if (commentList[currentMove] && !matchMode && gameMode != Training)
	{
	   DisplayComment(currentMove - 1, commentList[currentMove]);
      }
//
      // no mostrar comentarios de jugadas previas (FG)
      else
	{
	   // DisplayComment( -1, "");
	   // hacer desaparecer el recuadro
	   CommentPopDown();
	}
      // ocultar también las circunstancias de la partida
      if (currentMove == 2)
         TagsPopDown();
//
}


void
BackwardInner(target)
     int target;
{
   .
   .
   .
   if (commentList[currentMove] != NULL)
   {
      DisplayComment(currentMove - 1, commentList[currentMove]);
   }
//
   // no mostrar comentarios de jugadas previas (FG)
   else
   {
//       DisplayComment( -1, "");
      // hacer desaparecer el recuadro
      CommentPopDown();
   }
   // ocultar también las circunstancias de la partida
   if (currentMove == 2)
      TagsPopDown();
//
}


void
DisplayMove(moveNumber)
     int moveNumber;
{
   char message[MSG_SIZ];
   char res[MSG_SIZ];
   char cpThinkOutput[MSG_SIZ];
//
   char transMov[MSG_SIZ];
//
   if (moveNumber == forwardMostMove - 1 || 
	         gameMode == AnalyzeMode || gameMode == AnalyzeFile)
   {
//
      // actuar según el lenguaje utilizado
      if (toTranslate)
         TranslateMoveList(cpThinkOutput, thinkOutput, localPieceSymbols);
      else
//
         strcpy(cpThinkOutput, thinkOutput);

	   if (strchr(cpThinkOutput, '\n'))
   .
   .
   .
   if (moveNumber < 0 || parseList[moveNumber][0] == NULLCHAR)
   {
	   DisplayMessage(res, cpThinkOutput);
   }
   else
   {
//
      transMov[0] = NULLCHAR;
      if (toTranslate)
         TranslateMoveList(transMov, parseList[moveNumber],
                                 localPieceSymbols);	   
      sprintf(message, "%d.%s%s%s", moveNumber / 2 + 1,
		               WhiteOnMove(moveNumber) ? " " : ".. ",
			         // parseList[moveNumber], res);
                     	   toTranslate ? transMov : parseList[moveNumber], res);
//

	DisplayMessage(message, cpThinkOutput);
   }
}


// (FG)

// Reemplaza los símbolos ingleses de las piezas de la sarta 'lista'
// por los correspondientes del lenguaje local contenidos en
// 'localSymbols'; el resultado de la conversión se encuentra
// en 'transBuf'
// Esta función ha de ser tan rápida y eficaz como sea posible,
// pues se la llama muchas veces

void
TranslateMoveList(char * transBuf, char * lista, char * localSymbols)
{
   char * p, * q, * r, * s;
   int c, i, j;
   BOOLEAN hecho;

   p = lista;
   q = standardPieceSymbols;
   r = localSymbols;
   s = transBuf;

   * s = NULLCHAR;
   j = strlen(standardPieceSymbols);
   hecho = FALSE;

   while (* p != NULLCHAR)    // explorar la lista hasta el final
   {
      c = * p;
      // copiar directamente los caracteres inmutables
      if (c == ' ' || c == '.' || c == '+' || c == '-' ||
                      c == '!' ||  c == '=' ||  c == 'O' ||
                      isdigit(c) || islower(c))
      {
         * s = * p;           // copiarlo
         p++;                 // avanzar en la lista
         s++;                 // y en el tampón de salida
         continue;
      }

      // comparar el carácter con todos los símbolos
      for (i = 0; i < j; i++)
      {
         if ( * p == q[i])    // si es un símbolo de pieza,
         {
            * s = r[i];       // traducirlo
            hecho = TRUE;
            break;
         }
      }
      if (!hecho)
      {
         * s = * p;           // si no, copiar lo que haya
      }
      else
         hecho = FALSE;
      
      p++;                    // avanzar en la lista
      s++;                    // y en el tampón de salida
   }
   * s = NULLCHAR;            // cerrar la sarta elaborada
}

// Convertir los símbolos de pieza locales a internacionales
// Esta función se usa mucho menos que la precedente
// y puede ser corriente

void
NormalizePieceSymbols(char * transBuf)
{
   char * p, * q, * r, * s;
   int c, i, j;
   BOOLEAN hecho;
   char lista[BUF_SIZE];

   p = lista;
   q = localPieceSymbols;
   r = standardPieceSymbols;
   s = transBuf;

   * p = NULLCHAR;
   strcpy(lista, transBuf);   // copiar el texto recibido
   * s = NULLCHAR;            // vaciar el tampón de salida
   j = strlen(standardPieceSymbols);
   hecho = FALSE;

   while (* p != NULLCHAR)    // explorar la sarta hasta el final
   {
      c = * p;
      // copiar directamente los caracteres inmutables
      if (c == ' ' || c == '.' || c == '+' || c == '-' ||
                      c == '!' ||  c == '=' ||  c == 'O' ||
                      isdigit(c) || islower(c))
      {
         * s = * p;           // copiarlo
         p++;                 // avanzar en la lista
         s++;                 // y en el tampón de salida
         continue;
      }

      // comparar el carácter con todos los símbolos
      for (i = 0; i < j; i++)
      {
         if ( * p == q[i])    // si es un símbolo de pieza,
         {
            * s = r[i];       // traducirlo
            hecho = TRUE;
            break;
         }
      }
      if (!hecho)
      {
         * s = * p;           // si no, copiar lo que haya
      }
      else
         hecho = FALSE;
      
      p++;                    // avanzar en la lista
      s++;                    // y en el tampón de salida
   }
   * s = NULLCHAR;            // cerrar la sarta elaborada
}

//


void
DisplayAnalysis()
{
   char buf[MSG_SIZ];

   char transBuf[MSG_SIZ]; // (FG)

   double nps;
   static char * xtra[] = { "", " (--)", " (++)" };
   int h, m, s, cs;
  
   if (programStats.time == 0)
   {
      programStats.time = 1;
   }
//
   if (toTranslate)
      TranslateMoveList(transBuf, programStats.movelist,
                           localPieceSymbols);
//
  
   if (programStats.got_only_move)
   {
//
      if (toTranslate)
   	   strcpy(buf, transBuf);
      else
	   strcpy(buf, programStats.movelist);
//
   }
   else
   .
   .
   .
   
      if (programStats.moves_left > 0 && appData.periodicUpdates)
      {
         if (programStats.move_name[0] != NULLCHAR)
         {
		// sprintf(buf, "depth=%d %d/%d(%s) %+.2f %s%s\nNodes: %lu NPS: %d\nTime: %02d:%02d:%02d.%02d",
	      sprintf(buf, analysisDisplay,
		             programStats.depth,
		             programStats.nr_moves-programStats.moves_left,
		             programStats.nr_moves, programStats.move_name,
		             ((float)programStats.score)/100.0,
		  	  // programStats.movelist,
			       toTranslate ?  transBuf : programStats.movelist,
		             only_one_move(programStats.movelist) ?
		             xtra[programStats.got_fail] : "",
		             programStats.nodes, (int)nps, h, m, s, cs);
         }
	   else
         {
		// sprintf(buf, "depth=%d %d/%d %+.2f %s%s\nNodes: %lu NPS: %d\nTime: %02d:%02d:%02d.%02d",
	      sprintf(buf, analysisDisplayB,
		             programStats.depth,
		             programStats.nr_moves-programStats.moves_left,
		             programStats.nr_moves, ((float)programStats.score)/100.0,
			  // programStats.movelist,
			       toTranslate ?  transBuf : programStats.movelist,
		             only_one_move(programStats.movelist)?
		             xtra[programStats.got_fail] : "",
		             programStats.nodes, (int)nps, h, m, s, cs);
         }
      }
	else
	{
	   // sprintf(buf, "depth=%d %+.2f %s%s\nNodes: %lu NPS: %d\nTime: %02d:%02d:%02d.%02d",
	      sprintf(buf, analysisDisplayC,
		             programStats.depth,
		             ((float)programStats.score)/100.0,
			    // programStats.movelist,
				 toTranslate ?  transBuf : programStats.movelist,
		             only_one_move(programStats.movelist)?
		             xtra[programStats.got_fail] : "",
		             programStats.nodes, (int)nps, h, m, s, cs);
	}
   }

   DisplayAnalysisText(buf);
}


void
DisplayComment(moveNumber, text)
     int moveNumber;
     char * text;
{
   char title[MSG_SIZ];

//
   char transBuf[MSG_SIZ]; // (FG)

   if (toTranslate)
      TranslateMoveList(transBuf, parseList[moveNumber],
                           localPieceSymbols);
//

   if (moveNumber < 0 || parseList[moveNumber][0] == NULLCHAR)
   {
      // strcpy(title, "Comment");
      strcpy(title, comment); 
   }
   else
   {
      // sprintf(title, "Comment on %d.%s%s", moveNumber / 2 + 1,
      sprintf(title, commentOn, moveNumber / 2 + 1,
	  		   WhiteOnMove(moveNumber) ? " " : ".. ",
//					parseList[moveNumber]);
	               toTranslate ? transBuf : parseList[moveNumber]);
   }

   CommentPopUp(title, text);
}

   .
   .
   .

Boolean
ParseFEN(board, blackPlaysFirst, fen)
     Board board;
     int * blackPlaysFirst;
     char * fen;
{
   .
   .
   .
      default:
	   return FALSE;
   }

// /* pruebas adicionales para eliminar 'falsos positivos' (FG) */

   q = p - 1;     // final de la presunta sarta
   i = 0;

   // cuenta del número de separadores
   for (p = fen; p != q; p++)
   {
      if (* p == '/')
         i++;
   }
   if (i != 7)
      return FALSE;

   // repaso del número y color de los reyes
   i = 0;
   for (p = fen; p != q; p++)
   {
      if (* p == 'k')
         i++;
   }
   if (i != 1)
      return FALSE;

   i = 0;
   for (p = fen; p != q; p++)
   {
      if (* p == 'K')
         i++;
   }
   if (i != 1)
      return FALSE;
//
   /* !!We ignore the rest of the FEN notation */
   return TRUE;
}




lists.c

// (FG)

/* Return the number of elements of list 'listp'.
 * Counting starts with 1.
 */
int
ListTotal(listp)
    List * listp;
{
   ListNode * ln;
   int i = 0;

   for (ln = listp->head; ln->succ != NULL; ln = ln->succ)
   {
      i++;
   }

   return(i);
}
//




wgamelist.c

extern BOOLEAN analysisDemanded; // (FG)
extern VOID ToggleShowThinking(); // (FG)


LRESULT CALLBACK
GameListDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
   .
   .
   .
   switch (message)
   {
      case WM_INITDIALOG: 
   .
   .
   .
      case WM_COMMAND:
   .
   .
   .
         /* Load the game */
         if (cmailMsgLoaded)
	   {
            CmailLoadGame(gameFile, nItem + 1, gameFileName, TRUE);
         }
         else
   	   {
            LoadGame(gameFile, nItem + 1, gameFileName, TRUE);
//
		GameListPopDown();	// quitar la lista de enmedio (FG)
            if (analysisDemanded)
            {
               // poner en marcha los procesos de análisis
               if (!appData.showThinking)
	            ToggleShowThinking();
               AnalyzeFileEvent();
   	         AnalysisPeriodicEvent(1);
            }
//
	   }
         return TRUE;

      default:
         break;
   }		// switch(message)

   return FALSE;
}


VOID
GameListPopDown(void)
{
   CheckMenuItem(GetMenu(hwndMain), IDM_ShowGameList, MF_UNCHECKED);
   if (gameListDialog)
   {
	ShowWindow(gameListDialog, SW_HIDE);

// (FG)
      (void) EnableMenuItem(GetMenu(hwndMain),
               IDM_ShowGameList, MF_BYCOMMAND | MF_ENABLED);
//
   }
   gameListUp = FALSE;
}




winboard.c
   .
   .
   .

#include <languages.h>     // (FG)

   .
   .
   .
ColorClass currentColorClass;

//
BOOLEAN analysisDemanded = FALSE;   // (FG)
Boolean toTranslate = FALSE;   // (FG)
//

HWND hCommPort = NULL;    /* currently open comm port */
   .
   .
   .

int APIENTRY
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
	LPSTR lpCmdLine, int nCmdShow)
{
   .
   .
   .

  hAccelNoAlt = LoadAccelerators (hInstance, "NO_ALT");

//
  // determinar el lenguaje utilizado
  if (StrStr(standardPieceSymbols, localPieceSymbols) == NULL)
     toTranslate = TRUE;
//

  /* Acquire and dispatch messages until a WM_QUIT message is received. */
   .
   .
   .
}


// (FG)

// reflejo en las opciones de menu de la naturaleza
// unitaria o múltiple de un fichero de partidas (PGN) 
// y de un fichero de posiciones FEN
VOID
AllowDisplacement()
{
   int a;

   extern int lastMult, positionCount;

   HMENU hmenu = GetMenu(hwndMain);

   a = ListEmpty(&gameList);

   (void) EnableMenuItem(hmenu, IDM_LoadNextGame,
	      		MF_BYCOMMAND | ((a) ? MF_GRAYED : MF_ENABLED));
   (void) EnableMenuItem(hmenu, IDM_LoadPrevGame,
			      MF_BYCOMMAND | ((a) ? MF_GRAYED : MF_ENABLED));
   (void) EnableMenuItem(hmenu, IDM_ReloadGame,
			      MF_BYCOMMAND | ((a) ? MF_GRAYED : MF_ENABLED));
   (void) EnableMenuItem(hmenu, IDM_ShowGameList,
			      MF_BYCOMMAND | ((a) ? MF_GRAYED : MF_ENABLED));


   (void) EnableMenuItem(hmenu, IDM_LoadNextPosition,
			      MF_BYCOMMAND | ((lastMult) ? MF_ENABLED : MF_GRAYED));
   (void) EnableMenuItem(hmenu, IDM_LoadPrevPosition,
			      MF_BYCOMMAND | ((lastMult) ? MF_ENABLED : MF_GRAYED));
   (void) EnableMenuItem(hmenu, IDM_ReloadPosition,
			      MF_BYCOMMAND | ((positionCount) ? MF_ENABLED : MF_GRAYED));
}

//


/* Process messages for main window, etc. */
LRESULT CALLBACK
WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
  FARPROC lpProc;
  int wmId, wmEvent;
  char *defName;
  FILE *f;
//  UINT number;	// For unknown reasons opens the dialog in the My documents directory
  UINT number = 0;   // (FG) For unknown reasons opens in the Winboard.exe directory
  char fileTitle[MSG_SIZ];
   .
   .
   .
      case WM_COMMAND: /* message: command from application menu */
         wmId    = LOWORD(wParam);
         wmEvent = HIWORD(wParam);
   .
   .
   .
            case IDM_LoadPosition:
/*
               if (gameMode == AnalyzeMode || gameMode == AnalyzeFile)
               {
                  Reset(FALSE, TRUE);
               }       
               number = 1;
               f = OpenFileDialog(hwnd, FALSE, "",
					 appData.oldSaveStyle ? "pos" : "fen",
			 		 POSITION_FILT,
			 		 "Load Position from File", &number, fileTitle, NULL);
*/
               f = OpenFileDialog(hwnd, FALSE, "",
					 appData.oldSaveStyle ? "pos" : "fen",
			 		 POSITION_FILT,
			 		 loadPosition, &number, fileTitle, NULL);
       	   if (f != NULL)
               {

//
			// terminate any pending analysis (FG)
          		// but only after a new position has been requested
          		if (gameMode == AnalyzeMode || gameMode == AnalyzeFile)
          		{
             	   Reset(FALSE, TRUE);
          		}
//
	       	LoadPosition(f, number, fileTitle);
       	   }
       	   break;

   .
   .
   .
	    case IDM_AnalyzeFile:
      	 if (!first.analysisSupport)
       	 {
          	    char buf[MSG_SIZ];
                sprintf(buf, "%s does not support analysis", first.tidy);
                DisplayError(buf, 0);
             }
	       else
             {
/*	          if (!appData.showThinking)
			 ToggleShowThinking();
	          AnalyzeFileEvent();
	          LoadGameDialog(hwnd, "Analyze Game from File");
	          AnalysisPeriodicEvent(1);
*/
//
                // no iniciar los procesos de análisis mientras no
                // se haya especificado un fichero .pgn
                // (y se haya elegido una partida en el caso de los
                // múltiples, pero de momento no sé cómo hacerlo) (FG)
                f = OpenFileDialog(hwnd, FALSE, "",
 	                                appData.oldSaveStyle ? "gam" : "pgn",
	      	                    GAME_FILT,
		                          analyzeGame, &number, fileTitle, NULL);
                if (f != NULL)
                {
                   int error;
                   cmailMsgLoaded = FALSE;
                   // ver si es un fichero de partidas múltiples
                   error = GameListBuild(f);
                   if (error)
                   {
			    // DisplayError("Cannot build game list", error);
			    DisplayError(noGameList, error);
                      GameListDestroy();
                      number = 1;
                   }
                   else if (!ListEmpty(&gameList) &&
                                 ((ListGame *) gameList.tailPred)->number > 1)
                   {
                      GameListPopUp(f, fileTitle);
                      // tomar nota de que hay que analizar las partidas
                      // que se elijan
                      analysisDemanded = TRUE;
                   }
                   else
                   {
                      // una sola partida en el fichero
                      LoadGame(f, number, fileTitle, FALSE);
   	                if (!appData.showThinking)
	                   ToggleShowThinking();
                      AnalyzeFileEvent();
   	                AnalysisPeriodicEvent(1);
                   }
                }
//

             }
             break;
   .
   .
   .
}


LRESULT CALLBACK
TypeInMoveDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
   char move[MSG_SIZ];
   HWND hInput;
   ChessMove moveType;
   int fromX, fromY, toX, toY;
   char promoChar;

// (FG)
   extern int lastMult;
   extern int positionCount;
   extern int lastLoadPositionNumber;
   char info[MSG_SIZ], imove[MSG_SIZ];
   if (lastMult)
   {
      strcpy(info, parte2);
   }
   else
      strcpy(info, parte1);
//
   switch (message)
   {
      case WM_INITDIALOG:
         move[0] = (char) lParam;
         move[1] = NULLCHAR;
         CenterWindow(hDlg, GetWindow(hDlg, GW_OWNER));
         hInput = GetDlgItem(hDlg, OPT_Move);

         SetWindowText(hDlg, info);// (FG)

         SetWindowText(hInput, move);
   .
   .
   .
      case WM_COMMAND:
         switch (LOWORD(wParam))
         {
            case IDOK:
               if (gameMode != EditGame && currentMove != forwardMostMove && 
	                 gameMode != Training)
               {
			// DisplayMoveError("Displayed move is not current");
	            DisplayMoveError(moveNotCurrent);
               }
		   else
               {
	            GetDlgItemText(hDlg, OPT_Move, move, sizeof(move));
//
                  // interpretar la entrada como el número
                  // de la posición a cargar (FG)
                  if (atoi(move) && lastMult)
                  {
                     if ( atoi(move) <= positionCount)
                     {
                        ReloadPosition( atoi(move) - lastLoadPositionNumber);
                     }
                     else
                     {
                        MessageBox(NULL, outPosition, "WinBoard", MB_OK|MB_ICONEXCLAMATION);
                     }
                  }
                  else
                  {
                     strcpy(imove, move); // guardar una copia
                     if (toTranslate)
                     {
                        NormalizePieceSymbols(move);
                     }
//	                  

                     if (ParseOneMove(move, gameMode == EditPosition ? blackPlaysFirst : currentMove, 
	                         &moveType, &fromX, &fromY, &toX, &toY, &promoChar))
                     {
	                  if (gameMode != Training)
	                     forwardMostMove = currentMove;
	                  UserMoveEvent(fromX, fromY, toX, toY, promoChar);	
                     }
			   else
                     {
//	                    DisplayMoveError("Could not parse move");
                        sprintf(move, ignoteMove, imove);
	                  DisplayMoveError(move);
                     }
                  }
               } 
   .
   .
   .
}


// (FG)

Enables singleGameEnables[] = {
   { IDM_LoadNextGame, MF_BYCOMMAND | MF_GRAYED },
   { IDM_LoadPrevGame, MF_BYCOMMAND | MF_GRAYED },
   { IDM_ReloadGame, MF_BYCOMMAND | MF_GRAYED },
   { IDM_ShowGameList, MF_BYCOMMAND | MF_GRAYED },
   { -1, -1 }
};


Enables singlePositionEnables[] = {
   { IDM_LoadNextPosition, MF_BYCOMMAND | MF_GRAYED },
   { IDM_LoadPrevPosition, MF_BYCOMMAND | MF_GRAYED },
   { IDM_ReloadPosition, MF_BYCOMMAND | MF_GRAYED },
   { IDM_ShowGameList, MF_BYCOMMAND | MF_GRAYED },
   { -1, -1 }
};

   .
   .
   .


VOID
SetSingleGame()
{
   extern FILE * lastLoadGameFP;
   int i = 0;
   HMENU hMenu = GetMenu(hwndMain);

   SetMenuEnables(hMenu, singleGameEnables);
   // si ya se recuperó un juego, permítase volver a él
   if (lastLoadGameFP != NULL)
      (void) EnableMenuItem(hMenu, IDM_ReloadGame, MF_BYCOMMAND | MF_ENABLED);
}

VOID
SetSinglePosition()
{
   extern FILE * lastLoadPositionFP;
   HMENU hMenu = GetMenu(hwndMain);

   SetMenuEnables(hMenu, singlePositionEnables);
   // si ya se recuperó una posición, permítase volver a ella
   if (lastLoadPositionFP != NULL)
      (void) EnableMenuItem(hMenu, IDM_ReloadPosition, MF_BYCOMMAND | MF_ENABLED);
}

//


VOID
DisplayTitle(char * str)
{
   char title[MSG_SIZ], * host;

//
   // no perturbar el título preexistente (FG)
   if (gameMode == AnalyzeMode ||
         gameMode == AnalyzeFile ||
         gameMode == PlayFromGameFile)
      return;
//

   if (str[0] != NULLCHAR)
   {

   .
   .
   .
}
