Пример #1
0
/* Build the list of games in the open file f.
 * Returns 0 for success or error number.
 */
int
GameListBuild (FILE *f)
{
    ChessMove cm, lastStart;
    int gameNumber;
    ListGame *currentListGame = NULL;
    int error, scratch=100, plyNr=0, fromX, fromY, toX, toY;
    int offset;
    char lastComment[MSG_SIZ], buf[MSG_SIZ];
    TimeMark t, t2;

    GetTimeMark(&t);
    GameListFree(&gameList);
    yynewfile(f);
    gameNumber = 0;
    movePtr = 0;

    lastStart = (ChessMove) 0;
    yyskipmoves = FALSE;
    do {
        yyboardindex = scratch;
	offset = yyoffset();
	quickFlag = plyNr + 1;
	cm = (ChessMove) Myylex();
	switch (cm) {
	  case GNUChessGame:
	    if ((error = GameListNewGame(&currentListGame))) {
		rewind(f);
		yyskipmoves = FALSE;
		return(error);
	    }
	    currentListGame->number = ++gameNumber;
	    currentListGame->offset = offset;
	    if(1) { CopyBoard(boards[scratch], initialPosition); plyNr = 0; currentListGame->moves = PackGame(boards[scratch]); }
	    if (currentListGame->gameInfo.event != NULL) {
		free(currentListGame->gameInfo.event);
	    }
	    currentListGame->gameInfo.event = StrSave(yy_text);
	    lastStart = cm;
	    break;
	  case XBoardGame:
	    lastStart = cm;
	    break;
	  case MoveNumberOne:
	    switch (lastStart) {
	      case GNUChessGame:
		break;		/*  ignore  */
	      case PGNTag:
		lastStart = cm;
		break;		/*  Already started */
	      case (ChessMove) 0:
	      case MoveNumberOne:
	      case XBoardGame:
		if ((error = GameListNewGame(&currentListGame))) {
		    rewind(f);
		    yyskipmoves = FALSE;
		    return(error);
		}
		currentListGame->number = ++gameNumber;
		currentListGame->offset = offset;
		if(1) { CopyBoard(boards[scratch], initialPosition); plyNr = 0; currentListGame->moves = PackGame(boards[scratch]); }
		lastStart = cm;
		break;
	      default:
		break;		/*  impossible  */
	    }
	    break;
	  case PGNTag:
	    lastStart = cm;
	    if ((error = GameListNewGame(&currentListGame))) {
		rewind(f);
		yyskipmoves = FALSE;
		return(error);
	    }
	    currentListGame->number = ++gameNumber;
	    currentListGame->offset = offset;
	    ParsePGNTag(yy_text, &currentListGame->gameInfo);
	    do {
		yyboardindex = 1;
		offset = yyoffset();
		cm = (ChessMove) Myylex();
		if (cm == PGNTag) {
		    ParsePGNTag(yy_text, &currentListGame->gameInfo);
		}
	    } while (cm == PGNTag || cm == Comment);
	    if(1) {
		int btm=0;
		if(currentListGame->gameInfo.fen) ParseFEN(boards[scratch], &btm, currentListGame->gameInfo.fen, FALSE);
		else CopyBoard(boards[scratch], initialPosition);
		plyNr = (btm != 0);
		currentListGame->moves = PackGame(boards[scratch]);
	    }
	    if(cm != NormalMove) break;
	  case IllegalMove:
		if(appData.testLegality) break;
	  case NormalMove:
	    /* Allow the first game to start with an unnumbered move */
	    yyskipmoves = FALSE;
	    if (lastStart == (ChessMove) 0) {
	      if ((error = GameListNewGame(&currentListGame))) {
		rewind(f);
		yyskipmoves = FALSE;
		return(error);
	      }
	      currentListGame->number = ++gameNumber;
	      currentListGame->offset = offset;
	      if(1) { CopyBoard(boards[scratch], initialPosition); plyNr = 0; currentListGame->moves = PackGame(boards[scratch]); }
	      lastStart = MoveNumberOne;
	    }
	  case WhiteCapturesEnPassant:
	  case BlackCapturesEnPassant:
	  case WhitePromotion:
	  case BlackPromotion:
	  case WhiteNonPromotion:
	  case BlackNonPromotion:
	  case WhiteKingSideCastle:
	  case WhiteQueenSideCastle:
	  case BlackKingSideCastle:
	  case BlackQueenSideCastle:
	  case WhiteKingSideCastleWild:
	  case WhiteQueenSideCastleWild:
	  case BlackKingSideCastleWild:
	  case BlackQueenSideCastleWild:
	  case WhiteHSideCastleFR:
	  case WhiteASideCastleFR:
	  case BlackHSideCastleFR:
	  case BlackASideCastleFR:
		fromX = currentMoveString[0] - AAA;
		fromY = currentMoveString[1] - ONE;
		toX = currentMoveString[2] - AAA;
		toY = currentMoveString[3] - ONE;
		plyNr++;
		ApplyMove(fromX, fromY, toX, toY, currentMoveString[4], boards[scratch]);
		if(currentListGame && currentListGame->moves) PackMove(fromX, fromY, toX, toY, boards[scratch][toY][toX]);
	    break;
        case WhiteWins: // [HGM] rescom: save last comment as result details
        case BlackWins:
        case GameIsDrawn:
        case GameUnfinished:
	    if(!currentListGame) break;
	    if(currentListGame->gameInfo.result == GameUnfinished)
		currentListGame->gameInfo.result = cm; // correct result tag with actual result
	    if (currentListGame->gameInfo.resultDetails != NULL) {
		free(currentListGame->gameInfo.resultDetails);
	    }
	    if(yy_text[0] == '{') {
		char *p;
		safeStrCpy(lastComment, yy_text+1, sizeof(lastComment)/sizeof(lastComment[0]));
		if((p = strchr(lastComment, '}'))) *p = 0;
		currentListGame->gameInfo.resultDetails = StrSave(lastComment);
	    }
	    break;
	  default:
	    break;
	}
	if(gameNumber % 1000 == 0) {
	    snprintf(buf, MSG_SIZ, _("Reading game file (%d)"), gameNumber);
	    DisplayTitle(buf); DoEvents();
	}
    }
    while (cm != (ChessMove) 0);

 if(currentListGame) {
    if(!currentListGame->moves) DisplayError("Game cache overflowed\nPosition-searching might not work properly", 0);

    if (appData.debugMode) {
	for (currentListGame = (ListGame *) gameList.head;
	     currentListGame->node.succ;
	     currentListGame = (ListGame *) currentListGame->node.succ) {

	    fprintf(debugFP, "Parsed game number %d, offset %ld:\n",
		    currentListGame->number, currentListGame->offset);
	    PrintPGNTags(debugFP, &currentListGame->gameInfo);
	}
    }
  }
    if(appData.debugMode) { GetTimeMark(&t2);printf("GameListBuild %ld msec\n", SubtractTimeMarks(&t2,&t)); }
    quickFlag = 0;
    PackGame(boards[scratch]); // for appending end-of-game marker.
    DisplayTitle("WinBoard");
    rewind(f);
    yyskipmoves = FALSE;
    return 0;
}
Пример #2
0
/**
 * Loops until we have received buflen characters
 * return -1 on failure
 */
static int
tds_goodread(TDSSOCKET * tds, unsigned char *buf, int buflen, unsigned char unfinished)
{
	double start, global_start;
	int got = 0;
    int canceled = 0;

	if (buf == NULL || buflen < 1 || IS_TDSDEAD(tds))
		return 0;

	global_start = start = GetTimeMark();

	while (buflen > 0) {
		int len;
		double now;

		if (IS_TDSDEAD(tds))
			return -1;

        if ((len = tds_select(tds, TDSSELREAD, tds->query_timeout,
                              global_start)) > 0) {

			len = READSOCKET(tds->s, buf + got, buflen);

			if (len < 0 && TDSSOCK_WOULDBLOCK(sock_errno))
				continue;
			/* detect connection close */
			if (len <= 0) {
                tds_close_socket(tds);
                if (len == 0) {
                    tds_client_msg(tds->tds_ctx, tds, 20011, 6, 0, 0,
                                   "EOF in the socket.");
                } else {
                    tds_report_error(tds->tds_ctx, tds, sock_errno, 20012,
                                     "recv finished with an error.");
                }
				return -1;
			}
		} else if (len < 0) {
			if (TDSSOCK_WOULDBLOCK(sock_errno)) /* shouldn't happen, but OK */
				continue;
            tds_close_socket(tds);
            tds_report_error(tds->tds_ctx, tds, sock_errno, 20012,
                             "recv finished with an error.");
			return -1;
		} else { /* timeout */
    		now = GetTimeMark();
            if (tds->query_timeout > 0 && now - start >= tds->query_timeout) {
    
                int timeout_action = TDS_INT_CONTINUE;
    
                if (canceled)
                    return got ? got : -1;
    
                if (tds->query_timeout_func && tds->query_timeout)
                    timeout_action = (*tds->query_timeout_func)
                        (tds->query_timeout_param, (int)(now - global_start));
    
                switch (timeout_action) {
                case TDS_INT_EXIT:
                    exit(EXIT_FAILURE);
                    break;
                case TDS_INT_CANCEL:
                    tds_send_cancel(tds);
                    canceled = 1;
                    /* fall through to wait while cancelling happens */
                case TDS_INT_CONTINUE:
                    start = now;
                default:
                    break;
                }
            }
		}

		buflen -= len;
		got += len;

		if (unfinished && got)
			return got;
	}
	return got;
}
Пример #3
0
static int
tds_goodwrite(TDSSOCKET * tds, const unsigned char *buffer, int len, unsigned char last)
{
    double start, now;
	const unsigned char *p = buffer;
	int rc;

	assert(tds && buffer);

	if (TDS_IS_SOCKET_INVALID(tds->s))
		return -1;

	while (p - buffer < len) {
        start = GetTimeMark();
        now = start;
		if ((rc = tds_select(tds, TDSSELWRITE, tds->query_timeout, start)) > 0) {
			int err;
			size_t remaining = len - (p - buffer);
#ifdef USE_MSGMORE
			ssize_t nput = send(tds->s, p, remaining, last ? MSG_NOSIGNAL : MSG_NOSIGNAL|MSG_MORE);
			/* In case the kernel does not support MSG_MORE, try again without it */
			if (nput < 0 && errno == EINVAL && !last)
				nput = send(tds->s, p, remaining, MSG_NOSIGNAL);
#elif defined(__APPLE__) && defined(SO_NOSIGPIPE)
			ssize_t nput = send(tds->s, p, remaining, 0);
#else
			ssize_t nput = WRITESOCKET(tds->s, p, remaining);
#endif
			if (nput > 0) {
				p += nput;
				continue;
			}

			err = sock_errno;
            if (0 == nput || TDSSOCK_WOULDBLOCK(err) || err == TDSSOCK_EINTR)
				continue;

			assert(nput < 0);

			tdsdump_log(TDS_DBG_NETWORK, "send(2) failed: %d (%s)\n",
                        err, strerror(err));
            tds_report_error(tds->tds_ctx, tds, err, 20017,
                             "Write to SQL Server failed");
			tds_close_socket(tds);
			return -1;

		} else if (rc < 0) {
			int err = sock_errno;
			if (TDSSOCK_WOULDBLOCK(err)) /* shouldn't happen, but OK, retry */
				continue;
			tdsdump_log(TDS_DBG_NETWORK, "select(2) failed: %d (%s)\n",
                        err, strerror(err));
            tds_report_error(tds->tds_ctx, tds, err, 20005,
                             "select/send finished with error");
			tds_close_socket(tds);
			return -1;
		} else { /* timeout */
            now = GetTimeMark();
            if (tds->query_timeout  &&  (now - start) >= tds->query_timeout) {
                tds_client_msg(tds->tds_ctx, tds, 20002, 6, 0, 0,
                               "Writing to SQL server exceeded timeout");
                tds_close_socket(tds);
                return -1;
            }

			tdsdump_log(TDS_DBG_NETWORK, "tds_goodwrite(): timed out, asking client\n");
			switch (rc = tds_client_msg(tds->tds_ctx, tds, 20002, 6, 0, 0,
                                        "Writing to SQL server exceeded timeout")) {
			case TDS_INT_CONTINUE:
				continue;
			case TDS_INT_TIMEOUT:
				/* 
				 * "Cancel the operation ... but leave the dbproc in working condition." 
				 * We must try to send the cancel packet, else we have to abandon the dbproc.  
				 * If it can't be done, a harder error e.g. ECONNRESET will bubble up.  
				 */
				tds_send_cancel(tds);
				continue; 
			default:
			case TDS_INT_CANCEL:
				tds_close_socket(tds);
				return -1;
			}
			assert(0); /* not reached */
		}
		assert(0); /* not reached */
	}

#ifdef USE_CORK
	/* force packet flush */
	if (last) {
		int opt;
		opt = 0;
		setsockopt(tds->s, SOL_TCP, TCP_CORK, (const void *) &opt, sizeof(opt));
		opt = 1;
		setsockopt(tds->s, SOL_TCP, TCP_CORK, (const void *) &opt, sizeof(opt));
	}
#endif

	return len;
}
Пример #4
0
/**
 * Select on a socket until it's available or the timeout expires. 
 * Meanwhile, call the interrupt function. 
 * \return	>0 ready descriptors
 *		 0 timeout 
 * 		<0 error (cf. errno).  Caller should  close socket and return failure. 
 * This function does not call tdserror or close the socket because it can't know the context in which it's being called.   
 */
static int
tds_select(TDSSOCKET * tds, unsigned tds_sel, int timeout_seconds,
           double global_start)
{
	int rc, seconds;
	unsigned int poll_seconds;
	static const char method[] = "poll(2)";
    double now, start = global_start;

	assert(tds != NULL);
	assert(timeout_seconds >= 0);


	/* 
	 * The select loop.  
	 * If an interrupt handler is installed, we iterate once per second, 
	 * 	else we try once, timing out after timeout_seconds (0 == never). 
	 * If select(2) is interrupted by a signal (e.g. press ^C in sqsh), we timeout.
	 * 	(The application can retry if desired by installing a signal handler.)
	 *
	 * We do not measure current time against end time, to avoid being tricked by ntpd(8) or similar. 
	 * Instead, we just count down.  
	 *
	 * We exit on the first of these events:
	 * 1.  a descriptor is ready. (return to caller)
	 * 2.  select(2) returns an important error.  (return to caller)
	 * A timeout of zero says "wait forever".  We do that by passing a NULL timeval pointer to select(2). 
	 */
    poll_seconds = timeout_seconds;
    if (tds->query_timeout > 0) {
        if (tds->query_timeout_func  &&  tds_sel == TDSSELREAD) {
            poll_seconds = 1;
        } else {
            poll_seconds = timeout_seconds = tds->query_timeout;
        }
    }
	for (seconds = timeout_seconds; timeout_seconds == 0 || seconds > 0; seconds -= poll_seconds) {
		struct pollfd fd;
		int timeout = poll_seconds ? poll_seconds * 1000 : -1;

		fd.fd = tds->s;
		fd.events = tds_sel;
		fd.revents = 0;
		rc = poll(&fd, 1, timeout);

		if (rc > 0 ) {
			return rc;
		}

		if (rc < 0) {
			switch (sock_errno) {
			case TDSSOCK_EINTR:
            case EAGAIN:
            case TDSSOCK_EINPROGRESS:
				break;	/* let interrupt handler be called */
			default: /* documented: EFAULT, EBADF, EINVAL */
				tdsdump_log(TDS_DBG_ERROR, "error: %s returned %d, \"%s\"\n", 
						method, sock_errno, strerror(sock_errno));
				return rc;
			}
		}

		assert(rc == 0 || (rc < 0 && sock_errno == TDSSOCK_EINTR));

        if (tds->query_timeout > 0) {
			int timeout_action = TDS_INT_CONTINUE;
            now = GetTimeMark();

			/*
			 * "If hndlintr() returns INT_CANCEL, DB-Library sends an attention token [TDS_BUFSTAT_ATTN]
			 * to the server. This causes the server to discontinue command processing. 
			 * The server may send additional results that have already been computed. 
			 * When control returns to the mainline code, the mainline code should do 
			 * one of the following: 
			 * - Flush the results using dbcancel 
			 * - Process the results normally"
			 */
            if (tds->query_timeout_func  &&  tds_sel == TDSSELREAD
                &&  now - start >= tds->query_timeout) {
                timeout_action
                    = (*tds->query_timeout_func) (tds->query_timeout_param,
                                                  (int)(now - global_start));
#if 0
                tdsdump_log(TDS_DBG_ERROR,
                            "tds_ctx->query_timeout_func returned %d\n",
                            timeout_action);
#endif
                start = now;
            }
			switch (timeout_action) {
			case TDS_INT_CONTINUE:		/* keep waiting */
				continue;
			case TDS_INT_CANCEL:		/* abort the current command batch */
							/* FIXME tell tds_goodread() not to call tdserror() */
				return 0;
			default:
				tdsdump_log(TDS_DBG_NETWORK, 
					"tds_select: invalid interupt handler return code: %d\n", timeout_action);
				return -1;
			}
		}
		/* 
		 * We can reach here if no interrupt handler was installed and we either timed out or got EINTR. 
		 * We cannot be polling, so we are about to drop out of the loop. 
		 */
		assert(poll_seconds == timeout_seconds);
	}
	
	return 0;
}