//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // PBook::ReadFile(): read in a file. errorT PBook::ReadFile () { ASSERT (FileName != NULL); ReadOnly = false; MFile fp; if (fp.Open (FileName, FMODE_Both) != OK) { ReadOnly = true; if (fp.Open (FileName, FMODE_ReadOnly) != OK) { return ERROR_FileOpen; } } LineCount = 1; Position * pos = new Position; DString * line = new DString; ReadLine(line, &fp); DString dstr; while (line->Length() || ! fp.EndOfFile()) { if (pos->ReadFromFEN (line->Data()) != OK) { fprintf (stderr, "Error reading line: %u\n", LineCount); LineCount++; line->Clear(); ReadLine(line, &fp); continue; //exit (1); } char * s = (char *) line->Data(); // Skip over first four fields, which were the position: while (*s == ' ') { s++; } for (uint i=0; i < 4; i++) { while (*s != ' ' && *s != 0) { s++; } while (*s == ' ') { s++; } } // Now process each field in turn: while (*s == ';' || *s == ' ') { s++; } dstr.Clear(); while (*s != 0) { while (*s == ';' || *s == ' ') { s++; } bool seenCode = false; while (*s != ';' && *s != 0) { seenCode = true; char ch = *s; // Check for backslash (escape) character: if (ch == '\\') { s++; ch = *s; // "\s" -> semicolon within a field: if (ch == 's') { ch = ';'; } } dstr.AddChar (ch); s++; } if (seenCode) { dstr.AddChar ('\n'); } } if (Insert (pos, dstr.Data()) != OK) { //fprintf (stderr, "Warning: position already exists! Line %u\n", // LineCount); } LineCount++; line->Clear(); ReadLine(line, &fp); } delete pos; delete line; Altered = false; NextIndex = NodeListCount - 1; return OK; }
int main (int argc, char * argv[]) { setbuf(stdout, NULL); // Make stdout unbuffered. gameNumberT gNumber; bool option_ForceReplace = false; bool option_PreGameComments = true; uint pgnFileSize = 0; char *progname = argv[0]; fileNameT fname; fileNameT baseName; uint argsleft = argc - 1; char ** nextArg = argv + 1; // Parse command-line argments: while (argsleft > 0 && nextArg[0][0] == '-') { if (! strCompare (*nextArg, "-f")) { option_ForceReplace = true; } else if (! strCompare (*nextArg, "-x")) { option_PreGameComments = false; } else { usage (progname); } argsleft--; nextArg++; } if (argsleft != 1 && argsleft != 2) { usage (progname); } char * pgnName = *nextArg; MFile pgnFile; pgnFileSize = fileSize (pgnName, ""); // Ensure positive file size counter to avoid division by zero: if (pgnFileSize < 1) { pgnFileSize = 1; } // Make baseName from pgnName if baseName is not provided: if (argsleft == 1) { strCopy (baseName, pgnName); // If a gzip file, remove two suffixes, the first being ".gz": const char * lastSuffix = strFileSuffix (baseName); if (lastSuffix != NULL && strEqual (lastSuffix, GZIP_SUFFIX)) { strTrimFileSuffix (baseName); } // Trim the ".pgn" suffix: strTrimFileSuffix (baseName); } else { strCopy (baseName, nextArg[1]); } // Check for existing database, avoid overwriting it: if (! option_ForceReplace) { if (fileSize (baseName, INDEX_SUFFIX) > 0) { // Scid index file already exists: fprintf (stderr, "%s: database already exists: %s\n", progname, baseName); fprintf (stderr, "You can use: %s -f %s to overwrite" " the existing database.\n", progname, pgnName); exit(1); } } if (pgnFile.Open (pgnName, FMODE_ReadOnly) != OK) { fprintf (stderr, "%s: could not open file %s\n", progname, pgnName); exit(1); } // Try opening the log file: strCopy (fname, baseName); strAppend (fname, ".err"); FILE * logFile = fopen (fname, "w"); if (logFile == NULL) { fprintf (stderr, "%s: could not open log file: %s\n", progname, fname); exit(1); } printf ("Converting file %s to Scid database %s:\n", pgnName, baseName); printf ("Errors/warnings will be written to %s.\n\n", fname); scid_Init(); GFile * gameFile = new GFile; if ((gameFile->Create (baseName, FMODE_WriteOnly)) != OK) { fprintf (stderr, "%s: could not create the file %s%s\n", progname, baseName, GFILE_SUFFIX); fprintf (stderr, "The file may already exist and be read-only, or\n"); fprintf (stderr, "you may not have permission to create this file.\n"); exit(1); } NameBase * nb = new NameBase; Index * idx = new Index; IndexEntry * ie = new IndexEntry; idx->SetFileName (baseName); idx->CreateIndexFile (FMODE_WriteOnly); Game * game = new Game; ProgBar progBar(stdout); progBar.Start(); ByteBuffer *bbuf = new ByteBuffer; bbuf->SetBufferSize (BBUF_SIZE); // 32768 PgnParser pgnParser (&pgnFile); pgnParser.SetErrorFile (logFile); pgnParser.SetPreGameText (option_PreGameComments); // TODO: Add command line option for ignored tags, rather than // just hardcoding PlyCount as the only ignored tag. pgnParser.AddIgnoredTag ("PlyCount"); // Add each game found to the database: while (pgnParser.ParseGame(game) != ERROR_NotFound) { ie->Init(); if (idx->AddGame (&gNumber, ie) != OK) { fprintf (stderr, "\nLimit of %d games reached!\n", MAX_GAMES); exit(1); } // Add the names to the namebase: idNumberT id = 0; if (nb->AddName (NAME_PLAYER, game->GetWhiteStr(), &id) != OK) { fatalNameError (NAME_PLAYER); } nb->IncFrequency (NAME_PLAYER, id, 1); ie->SetWhite (id); if (nb->AddName (NAME_PLAYER, game->GetBlackStr(), &id) != OK) { fatalNameError (NAME_PLAYER); } nb->IncFrequency (NAME_PLAYER, id, 1); ie->SetBlack (id); if (nb->AddName (NAME_EVENT, game->GetEventStr(), &id) != OK) { fatalNameError (NAME_EVENT); } nb->IncFrequency (NAME_EVENT, id, 1); ie->SetEvent (id); if (nb->AddName (NAME_SITE, game->GetSiteStr(), &id) != OK) { fatalNameError (NAME_SITE); } nb->IncFrequency (NAME_SITE, id, 1); ie->SetSite (id); if (nb->AddName (NAME_ROUND, game->GetRoundStr(), &id) != OK) { fatalNameError (NAME_ROUND); } nb->IncFrequency (NAME_ROUND, id, 1); ie->SetRound (id); bbuf->Empty(); if (game->Encode (bbuf, ie) != OK) { fprintf (stderr, "Fatal error encoding game!\n"); abort(); } uint offset = 0; if (gameFile->AddGame (bbuf, &offset) != OK) { fprintf (stderr, "Fatal error writing game file!\n"); abort(); } ie->SetOffset (offset); ie->SetLength (bbuf->GetByteCount()); idx->WriteEntries (ie, gNumber, 1); // Update the progress bar: if (! (gNumber % 100)) { int bytesSeen = pgnParser.BytesUsed(); int percentDone = 1 + ((bytesSeen) * 100 / pgnFileSize); progBar.Update (percentDone); } } uint t = 0; // = time(0); nb->SetTimeStamp(t); nb->SetFileName (baseName); if (nb->WriteNameFile() != OK) { fprintf (stderr, "Fatal error writing name file!\n"); exit(1); } progBar.Finish(); printf ("\nDatabase `%s': %d games, %d players, %d events, %d sites.\n", baseName, idx->GetNumGames(), nb->GetNumNames (NAME_PLAYER), nb->GetNumNames (NAME_EVENT), nb->GetNumNames (NAME_SITE)); fclose (logFile); if (pgnParser.ErrorCount() > 0) { printf ("There were %u errors or warnings; ", pgnParser.ErrorCount()); printf ("examine the file \"%s.err\"\n", baseName); } else { printf ("There were no warnings or errors.\n"); removeFile (baseName, ".err"); } gameFile->Close(); idx->CloseIndexFile(); // If there is a tree cache file for this database, it is out of date: removeFile (baseName, TREEFILE_SUFFIX); #ifdef ASSERTIONS printf("%d asserts were tested\n", numAsserts); #endif return 0; }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // PBook::ReadEcoFile(): // Read an ECO (not EPD) format file. errorT PBook::ReadEcoFile () { MFile fp; if (fp.Open (FileName, FMODE_ReadOnly) != OK) { return ERROR_FileOpen; } ReadOnly = true; LineCount = 1; Position std_start; std_start.StdStart(); DString text; DString moves; ecoStringT ecoStr; ecoT ecoCode; int ch; errorT err = OK; bool done = false; // Loop to read in and add all positions: while (!done) { // Find the next ECO code: while (true) { ch = fp.ReadOneByte(); if (ch == EOF) { done = true; break; } if (ch == '\n') { LineCount++; } if (ch >= 'A' && ch <= 'E') { break; } if (ch == '#') { while (ch != '\n' && ch != EOF) { ch = fp.ReadOneByte(); } if (ch == EOF) { done = true; } LineCount++; } } if (done) { break; } // Read in the rest of the ECO code: ecoStr[0] = ch; ch = fp.ReadOneByte(); if (ch < '0' || ch > '9') { goto corrupt; } ecoStr[1] = ch; ch = fp.ReadOneByte(); if (ch < '0' || ch > '9') { goto corrupt; } ecoStr[2] = ch; ecoStr[3] = 0; // Now check for optional extra part of code, e.g. "A00a1": ch = fp.ReadOneByte(); if (ch >= 'a' && ch <= 'z') { ecoStr[3] = ch; ecoStr[4] = 0; ch = fp.ReadOneByte(); if (ch >= '1' && ch <= '4') { ecoStr[4] = ch; ecoStr[5] = 0; } } // Now put ecoCode in the text string and read the text in quotes: ecoCode = eco_FromString (ecoStr); eco_ToExtendedString (ecoCode, ecoStr); text.Clear(); text.Append ("eco ", ecoStr, " ["); // Find the start of the text: while ((ch = fp.ReadOneByte()) != '"') { if (ch == EOF) { goto corrupt; } } while ((ch = fp.ReadOneByte()) != '"') { if (ch == EOF) { goto corrupt; } text.AddChar ((char) ch); } text.Append ("]\n"); // Now read the position: moves.Clear(); char prev = 0; while ((ch = fp.ReadOneByte()) != '*') { if (ch == EOF) { goto corrupt; } if (ch == '\n') { ch = ' '; LineCount++; } if (ch != ' ' || prev != ' ') { moves.AddChar ((char) ch); } prev = ch; } Position pos (std_start); err = pos.ReadLine (moves.Data()); if (err != OK) { goto corrupt; } text.Append ("moves ", strTrimLeft (moves.Data()), "\n"); if (Insert (&pos, text.Data()) != OK) { // Position already exists: just ignore it. } } return OK; corrupt: return ERROR_Corrupt; }