home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
High Voltage Shareware
/
high1.zip
/
high1
/
DIR2
/
CBUFF09.ZIP
/
SRC.ZIP
/
CBASE.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-11-16
|
11KB
|
397 lines
/* $Id$
*
* File cbase.c
* Part of ChessBase utilities file format (CBUFF)
* Author Anjo Anjewierden, anjo@swi.psy.uva.nl
* Horst Aurisch, aurisch@informatik.uni-bonn.de
* Purpose Manipulation of entire ChessBase databases
* Works with GNU CC 2.4.5
*
* Notice Copyright (c) 1993 Anjo Anjewierden
*
* History 08/06/93 (Created)
* 03/11/93 (Last modified)
*/
/*------------------------------------------------------------
* Directives
*------------------------------------------------------------*/
#include "cbuff.h"
/*------------------------------------------------------------
* Prototypes
*------------------------------------------------------------*/
static CBase allocCBase(char *);
static void checkModeCBase(CBase, int);
static long checkBoundsCBase(CBase, long);
/*------------------------------------------------------------
* Initialisation
*------------------------------------------------------------*/
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@node newCBase
@deftypefun CBase newCBase (char *@var{name}, char *@var{mode})
Allocates a new database and returns it. @var{name} is the name of
the database (without the @file{.cbf} extension). The @var{mode}
argument is similar to the second of @code{fopen}. @var{mode} can be:
@example
"r" @r{Open for reading}
"a" @r{Open for appending}
"c" @r{Open for writing, create first}
@end example
The @code{"c"} mode requires that a database of the given @var{name}
does not exist, @code{"a"} can be used for both existing and new databases.
The constant @code{NULL} is returned when the database cannot be opened or
on another error.
@end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
CBase
newCBase(char *baseName, char *mode)
{ FILE *cbi;
FILE *cbf;
CBase cb;
if (strcmp(mode, "r") == 0)
{ cbi = fopenExtension(baseName, "cbi", "rb", TRUE);
cbf = fopenExtension(baseName, "cbf", "rb", TRUE);
if (foundError())
{ reportError(stderr);
if (cbi) fclose(cbi);
if (cbf) fclose(cbf);
return NULL;
}
cb = allocCBase(baseName);
cb->cbi = cbi;
cb->cbf = cbf;
cb->mode = READ_MODE;
} else
if (strcmp(mode, "c") == 0)
{ cbi = fopenExtension(baseName, "cbi", "wb", FALSE);
cbf = fopenExtension(baseName, "cbf", "wb", FALSE);
if (foundError())
{ reportError(stderr);
if (cbi) fclose(cbi);
if (cbf) fclose(cbf);
return NULL;
}
cb = allocCBase(baseName);
cb->cbi = cbi;
cb->cbf = cbf;
cb->mode = WRITE_MODE;
} else
if (strcmp(mode, "a") == 0)
{ cbi = fopenExtension(baseName, "cbi", "r+b", TRUE);
cbf = fopenExtension(baseName, "cbf", "r+b", TRUE);
if (foundError())
{ reportError(stderr);
if (cbi) fclose(cbi);
if (cbf) fclose(cbf);
return NULL;
}
cb = allocCBase(baseName);
cb->cbi = cbi;
cb->cbf = cbf;
cb->mode = WRITE_MODE;
fseek(cb->cbi, 0L, 0);
cb->noGames = readLong(cb->cbi) - 1;
fseek(cb->cbi, (cb->noGames+1)*sizeof(unsigned long), 0);
cb->position = readLong(cb->cbi) - cb->noGames - 1;
} else
{ fprintf(stderr, "Internal error: Opening database %s; mode (%s)?\n",
baseName, mode);
exit(1);
}
if (cb->mode == READ_MODE)
{ long i;
unsigned long pos;
cb->noGames = readLong(cb->cbi) - 1;
cb->index = (unsigned long *) alloc(cb->noGames*sizeof(unsigned long));
if (cb->index == NULL)
{ fprintf(stderr, "Could not allocate index for %s.cbi\n", baseName);
freeCBase(cb);
return NULL;
}
for (i=1; i<=cb->noGames; i++)
{ pos = readLong(cbi);
cb->index[i-1] = pos - (i+1);
}
cb->position = readLong(cbi) - cb->noGames - 1;
}
return cb;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@node freeCBase
@deftypefun void freeCBase (CBase @var{cb})
Reclaims the memory associated with the database @var{cb}.
@end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
void
freeCBase(CBase cb)
{ if (cb->cbf) fclose(cb->cbf);
if (cb->cbi) fclose(cb->cbi);
if (cb->index) unalloc(cb->index);
unallocCharp(cb->name);
unalloc(cb);
}
/*------------------------------------------------------------
* Functions
*------------------------------------------------------------*/
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@node getNoGamesCBase
@deftypefun long getNoGamesCBase (CBase @var{cb})
Returns the number of games in the database @var{cb}.
@end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
long
getNoGamesCBase(CBase cb)
{ return cb->noGames;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@node exportGameCBase
@deftypefun void exportGameCBase (CBase @var{dst}, CBase @var{src}, long @var{n})
Exports (appends) game @var{n} from database @var{src} to the output database @var{dst}.
@end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
void
exportGameCBase(CBase dst, CBase src, long n)
{ CbGame cg;
unsigned char *buf;
long bytes;
checkModeCBase(dst, WRITE_MODE);
checkModeCBase(src, READ_MODE);
if (src->index[n-1] & PHYSICALLY_DELETED)
return;
cg = newCbGame();
if ((bytes=readCbGame(cg,src,n)) == (long) NULL)
{ reportError(stderr);
return;
}
buf = (unsigned char *) alloc(bytes);
/* Read game from source */
fseek(src->cbf, src->index[n-1], 0);
fread(buf, 1, bytes, src->cbf);
/* Write number of games */
fseek(dst->cbi, 0L, 0);
writeLong(dst->noGames+1+1, dst->cbi);
/* Write index in destination */
fseek(dst->cbi, (dst->noGames+1) * sizeof(long), 0);
writeLong(dst->position+dst->noGames+1+1, dst->cbi);
/* Write game in destination */
fseek(dst->cbf, dst->position, 0);
fwrite(buf, 1, bytes, dst->cbf);
dst->position += bytes;
dst->noGames++;
/* Write last position */
writeLong(dst->position+dst->noGames+1, dst->cbi);
freeCbGame(cg);
unalloc(buf);
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@node exportManyBase
@deftypefun void exportManyCBase (CBase @var{dst}, CBase @var{src}, long @var{from}, long @var{to})
Exports (appends) games from @var{from} through @var{to} from database
@var{src} to the output database @var{dst}.
@end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
void
exportManyCBase(CBase dst, CBase src, long from, long to)
{ CbGame cg;
unsigned char *buf;
long bytes;
long n;
long count, inc;
checkModeCBase(dst, WRITE_MODE);
checkModeCBase(src, READ_MODE);
from = checkBoundsCBase(src, from);
to = checkBoundsCBase(src, to);
cg = newCbGame();
fprintf(stderr, "Writing games %ld - %ld to database %s\n",
from, to, dst->name);
n = to-from+1;
inc = (n < 50L ? 1 : n/50L);
for (n=from, count=0; n && n<=to; n++, count++)
{ if (count == inc)
{ fprintf(stderr, ".");
count = 0;
}
if (src->index[n-1] & PHYSICALLY_DELETED)
continue;
if ((bytes=readCbGame(cg,src,n)) == (long) NULL)
{ reportError(stderr);
fprintf(stderr, "; Game not written to database\n");
continue;
}
buf = (unsigned char *) alloc(bytes);
/* Read game from source */
fseek(src->cbf, src->index[n-1], 0);
fread(buf, 1, bytes, src->cbf);
/* Write index in destination */
fseek(dst->cbi, (dst->noGames+1) * sizeof(long), 0);
writeLong(dst->position+dst->noGames+1+1, dst->cbi);
/* Write game in destination */
fseek(dst->cbf, dst->position, 0);
fwrite(buf, 1, bytes, dst->cbf);
dst->position += bytes;
dst->noGames++;
unalloc(buf);
}
/* Write last position, assumes
* file pointer is correct.
*/
writeLong(dst->position+dst->noGames+1, dst->cbi);
/* Write number of games */
fseek(dst->cbi, 0L, 0);
writeLong(dst->noGames+1, dst->cbi);
freeCbGame(cg);
fprintf(stderr, "\n");
}
void
reportCBase(CBase cb, FILE *fd)
{ fprintf(fd, "ChessBase database %s (%ld games)\n",
cb->name, cb->noGames);
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@node deleteGameCBase
@deftypefun void deftypefun (CBase @var{cb}, long @var{n})
Marks game @var{n} in the database @var{cb} for deletion. The
game will be physically deleted when the game from @var{cb}
is exported to another database (for example with
@code{exportedManyCBase}).
@end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
void
deleteGameCBase(CBase cb, long n)
{ checkModeCBase(cb, READ_MODE);
if (n >= 1 && n <= cb->noGames)
cb->index[n-1] |= PHYSICALLY_DELETED;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@node deletedGameCBaseP
@deftypefun bool deletedGameCBaseP (CBase @var{cb}, long @var{n})
Succeeds if game @var{n} in database @var{cb} has been marked for
deletion with @code{deleteGameCBase}. Note that this is different
from @code{deleteGameP} (which indicates that the user has marked
the game for deletion).
@end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
bool
deletedGameCBaseP(CBase cb, long n)
{ checkModeCBase(cb, READ_MODE);
if (n >= 1 && n <= cb->noGames)
{ if (cb->index[n-1] & PHYSICALLY_DELETED)
return TRUE;
}
return FALSE;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@node getIndexGameCBase
@deftypefun {unsigned long} getIndexGameCBase (CBase @var{cb}, long @var{n})
Returns the index of game @var{n} in database @var{cb}. The index
is the position where the game starts in the @code{.cbf} file.
@end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
unsigned long
getIndexGameCBase(CBase cb, long n)
{ checkModeCBase(cb, READ_MODE);
if (n >= 1 && n <= cb->noGames)
return cb->index[n-1] & ~PHYSICALLY_DELETED;
return (unsigned long) NULL;
}
/*------------------------------------------------------------
* Private functions
*------------------------------------------------------------*/
static CBase
allocCBase(char *name)
{ CBase cb;
cb = alloc(sizeof(struct cbase));
cb->name = allocCharp(name);
cb->noGames = 0;
cb->index = NULL;
cb->cbf = NULL;
cb->cbi = NULL;
cb->position = 0L;
return cb;
}
static void
checkModeCBase(CBase cb, int mode)
{ if (cb->mode != mode)
{ switch (mode)
{ case READ_MODE:
fprintf(stderr, "Internal error: Database %s not opened for reading\n",
cb->name);
exit(1);
return;
case WRITE_MODE:
fprintf(stderr, "Internal error: Database %s not opened for writing\n",
cb->name);
exit(1);
return;
default:
fprintf(stderr, "Internal error: checkModeCBase mode = %d\n", mode);
exit(1);
}
}
}
static long
checkBoundsCBase(CBase cb, long n)
{ if (n < 1)
return 1;
if (n > cb->noGames)
return cb->noGames;
return n;
}