The following patch (written against scid-3.6.19-rc2) adds new
way of running scmerge. One can now write
scmerge newbase -
and supply the list of merged bases on standard input (one by
one, separated by newline).
I wrote it after getting 'argument list too long' error once more
(not that hard to obtain, spliteco to 1000 parts and then try
merging them back). It may also make shell scripts marginally
simpler, one can now for instance write
find . -name '*.si3' | sed s/\.si3// | scmerge newbase -
Note: the patch is smaller than it seems. I factored out the
merging code to separate function, so the diff is pretty large,
but the main difference is just in the handling of '-' arg...
PS Traditional "scmerge newbase oldbase1 oldbase2" of course
still works.
scmerge accepts - as input file name (sideways or instead other params).
Run this way, it reads file names from standard output (using newline as separator).
diff --git a/src/scmerge.cpp b/src/scmerge.cpp
--- a/src/scmerge.cpp
+++ b/src/scmerge.cpp
@@ -15,6 +15,8 @@
// scmerge: Scid database merge tool
// Usage: scmerge newfile oldfile1 [oldfile2 ....]
+// Or: scmerge newfile -
+// (and the list of old files to be given on stdin line per line)
#include "common.h"
@@ -38,6 +40,7 @@ void
void
usage (void) {
fprintf(stderr, "Usage: %s newfile oldfile1 [oldfile2 ...]\n", progName);
+ fprintf(stderr, " Or: %s newfile -\n", progName);
exit(1);
}
@@ -51,6 +54,83 @@ fileError (const char * operation, const
exit(1);
}
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// mergeFile
+inline uint
+mergeFile(Index * targetIndex, NameBase * targetNameBase, GFile * targetGFile, const char * targetFileName,
+ Index * sourceIndex, NameBase * sourceNameBase, GFile * sourceGFile, const char * sourceFileName,
+ ByteBuffer * bbuf)
+{
+ errorT err = 0;
+ uint gamesCount = 0;
+
+ sourceIndex->SetFileName (sourceFileName);
+ sourceNameBase->SetFileName (sourceFileName);
+ if (sourceIndex->OpenIndexFile(FMODE_ReadOnly) != OK) {
+ fileError ("opening", sourceFileName, INDEX_SUFFIX);
+ }
+ if (sourceNameBase->ReadNameFile() != OK) {
+ fileError ("opening/reading", sourceFileName, NAMEBASE_SUFFIX);
+ }
+ if (sourceGFile->Open (sourceFileName, FMODE_ReadOnly) != OK) {
+ fileError ("opening", sourceFileName, GFILE_SUFFIX);
+ }
+ for (uint gCount = 0; gCount < sourceIndex->GetNumGames(); gCount++) {
+ IndexEntry iE;
+ err = sourceIndex->ReadEntries (&iE, gCount, 1);
+ if (err != OK) { fileError ("reading", sourceFileName, INDEX_SUFFIX); }
+ // Now, the following fields may change: offset, whiteID, blackID,
+ // eventID, siteID, roundID. All others will be unchanged.
+
+ // We add each name to the new namebase and update the IDs:
+ uint newID;
+ err = targetNameBase->AddName (NAME_PLAYER,
+ iE.GetWhiteName (sourceNameBase), &newID);
+ targetNameBase->IncFrequency (NAME_PLAYER, newID, 1);
+ iE.SetWhite (newID);
+
+ err = targetNameBase->AddName (NAME_PLAYER,
+ iE.GetBlackName (sourceNameBase), &newID);
+ targetNameBase->IncFrequency (NAME_PLAYER, newID, 1);
+ iE.SetBlack (newID);
+
+ err = targetNameBase->AddName (NAME_EVENT,
+ iE.GetEventName (sourceNameBase), &newID);
+ targetNameBase->IncFrequency (NAME_EVENT, newID, 1);
+ iE.SetEvent (newID);
+
+ err = targetNameBase->AddName (NAME_SITE,
+ iE.GetSiteName (sourceNameBase), &newID);
+ targetNameBase->IncFrequency (NAME_SITE, newID, 1);
+ iE.SetSite (newID);
+
+ err = targetNameBase->AddName (NAME_ROUND,
+ iE.GetRoundName (sourceNameBase), &newID);
+ targetNameBase->IncFrequency (NAME_ROUND, newID, 1);
+ iE.SetRound (newID);
+
+ // Now, we add the game record to the gfile:
+ bbuf->Empty();
+ err = sourceGFile->ReadGame (bbuf, iE.GetOffset(), iE.GetLength());
+ if (err != OK) { fileError ("reading", sourceFileName, GFILE_SUFFIX); }
+ uint newOffset = 0;
+ err = targetGFile->AddGame (bbuf, &newOffset);
+ if (err != OK) { fileError ("writing", targetFileName, GFILE_SUFFIX); }
+ iE.SetOffset (newOffset);
+
+ // Last of all, we write the new index record:
+ err = targetIndex->WriteEntries (&iE, gamesCount, 1);
+ gamesCount++;
+ if (err != OK) { fileError ("writing", targetFileName, INDEX_SUFFIX); }
+ }
+
+ // Now we must close and clear the old files:
+ sourceIndex->CloseIndexFile();
+ sourceNameBase->Clear();
+ sourceGFile->Close();
+
+ return gamesCount;
+}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// main()
@@ -58,10 +138,9 @@ int
int
main (int argc, char ** argv)
{
- errorT err;
progName = argv[0];
if (argc < 3) { usage(); }
- char * mergeName = argv[1];
+ char * targetFileName = argv[1];
Index * targetIndex = new Index;
NameBase * targetNameBase = new NameBase;
@@ -74,112 +153,77 @@ main (int argc, char ** argv)
ByteBuffer * bbuf = new ByteBuffer;
bbuf->SetBufferSize (32000);
- targetIndex->SetFileName (mergeName);
- targetNameBase->SetFileName (mergeName);
+ targetIndex->SetFileName (targetFileName);
+ targetNameBase->SetFileName (targetFileName);
// Check that the target database does not already exist:
Index * tempIndex = new Index;
- tempIndex->SetFileName (mergeName);
+ tempIndex->SetFileName (targetFileName);
if (tempIndex->OpenIndexFile(FMODE_ReadOnly) == OK) {
tempIndex->CloseIndexFile();
- fprintf (stderr, "Error: the database %s already exists.\n", mergeName);
+ fprintf (stderr, "Error: the database %s already exists.\n", targetFileName);
usage();
}
// Open the target files:
if (targetIndex->CreateIndexFile(FMODE_WriteOnly) != OK) {
- fileError ("creating", mergeName, INDEX_SUFFIX);
- }
- if (targetGFile->Create (mergeName, FMODE_WriteOnly) != OK) {
- fileError ("creating", mergeName, GFILE_SUFFIX);
+ fileError ("creating", targetFileName, INDEX_SUFFIX);
+ }
+ if (targetGFile->Create (targetFileName, FMODE_WriteOnly) != OK) {
+ fileError ("creating", targetFileName, GFILE_SUFFIX);
}
uint totalCount = 0;
+ uint totalFilesCount = 0;
// Now execute the merge process once for each existing file:
for (int i=2; i < argc; i++) {
- char * fileName = argv[i];
- sourceIndex->SetFileName (fileName);
- sourceNameBase->SetFileName (fileName);
- if (sourceIndex->OpenIndexFile(FMODE_ReadOnly) != OK) {
- fileError ("opening", fileName, INDEX_SUFFIX);
+ char * sourceFileName = argv[i];
+ if (strlen(sourceFileName) == 1 && sourceFileName[0] == '-')
+ {
+ char thisFile[1024] = "";
+ while( fgets(thisFile, sizeof(thisFile), stdin) ) {
+ int l = strlen(thisFile);
+ if( l <= 1)
+ continue;
+ if( thisFile[l-1] != '\n') {
+ fprintf(stderr, "File name too long (max: %d chars)\n", sizeof(thisFile));
+ exit(1);
+ }
+ thisFile[l-1] = 0; // throw away \n
+ if( l > 2 && thisFile[l-2] == '\r') {
+ thisFile[l-2] = 0; // throw away \r (if happened)
+ }
+ totalCount += mergeFile(targetIndex, targetNameBase, targetGFile, targetFileName,
+ sourceIndex, sourceNameBase, sourceGFile, thisFile,
+ bbuf);
+ ++ totalFilesCount;
+ }
}
- if (sourceNameBase->ReadNameFile() != OK) {
- fileError ("opening/reading", fileName, NAMEBASE_SUFFIX);
+ else
+ {
+ totalCount += mergeFile(targetIndex, targetNameBase, targetGFile, targetFileName,
+ sourceIndex, sourceNameBase, sourceGFile, sourceFileName,
+ bbuf);
+ ++ totalFilesCount;
}
- if (sourceGFile->Open (fileName, FMODE_ReadOnly) != OK) {
- fileError ("opening", fileName, GFILE_SUFFIX);
- }
- for (uint gCount = 0; gCount < sourceIndex->GetNumGames(); gCount++) {
- IndexEntry iE;
- err = sourceIndex->ReadEntries (&iE, gCount, 1);
- if (err != OK) { fileError ("reading", fileName, INDEX_SUFFIX); }
- // Now, the following fields may change: offset, whiteID, blackID,
- // eventID, siteID, roundID. All others will be unchanged.
-
- // We add each name to the new namebase and update the IDs:
- uint newID;
- err = targetNameBase->AddName (NAME_PLAYER,
- iE.GetWhiteName (sourceNameBase), &newID);
- targetNameBase->IncFrequency (NAME_PLAYER, newID, 1);
- iE.SetWhite (newID);
-
- err = targetNameBase->AddName (NAME_PLAYER,
- iE.GetBlackName (sourceNameBase), &newID);
- targetNameBase->IncFrequency (NAME_PLAYER, newID, 1);
- iE.SetBlack (newID);
-
- err = targetNameBase->AddName (NAME_EVENT,
- iE.GetEventName (sourceNameBase), &newID);
- targetNameBase->IncFrequency (NAME_EVENT, newID, 1);
- iE.SetEvent (newID);
-
- err = targetNameBase->AddName (NAME_SITE,
- iE.GetSiteName (sourceNameBase), &newID);
- targetNameBase->IncFrequency (NAME_SITE, newID, 1);
- iE.SetSite (newID);
-
- err = targetNameBase->AddName (NAME_ROUND,
- iE.GetRoundName (sourceNameBase), &newID);
- targetNameBase->IncFrequency (NAME_ROUND, newID, 1);
- iE.SetRound (newID);
-
- // Now, we add the game record to the gfile:
- bbuf->Empty();
- err = sourceGFile->ReadGame (bbuf, iE.GetOffset(), iE.GetLength());
- if (err != OK) { fileError ("reading", fileName, GFILE_SUFFIX); }
- uint newOffset = 0;
- err = targetGFile->AddGame (bbuf, &newOffset);
- if (err != OK) { fileError ("writing", mergeName, GFILE_SUFFIX); }
- iE.SetOffset (newOffset);
-
- // Last of all, we write the new index record:
- err = targetIndex->WriteEntries (&iE, totalCount, 1);
- totalCount++;
- if (err != OK) { fileError ("writing", mergeName, INDEX_SUFFIX); }
- }
-
- // Now we must close and clear the old files:
- sourceIndex->CloseIndexFile();
- sourceNameBase->Clear();
- sourceGFile->Close();
}
// Now all files have been read. All we need do is close the new base:
targetIndex->CloseIndexFile();
if (targetNameBase->WriteNameFile() != OK) {
- fileError ("writing", mergeName, NAMEBASE_SUFFIX);
+ fileError ("writing", targetFileName, NAMEBASE_SUFFIX);
}
if (targetGFile->Close() != OK) {
- fileError ("closing", mergeName, GFILE_SUFFIX);
+ fileError ("closing", targetFileName, GFILE_SUFFIX);
}
// Remove any treefile for this database:
- removeFile (mergeName, TREEFILE_SUFFIX);
+ removeFile (targetFileName, TREEFILE_SUFFIX);
// All done!!
fprintf (stderr, "Successfully merged %u files, of %u games.\n",
- argc - 2, targetIndex->GetNumGames());
+ totalFilesCount, targetIndex->GetNumGames());
return 0;
}
-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
Scid-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/scid-users