home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR2 / CBUFF09.ZIP / SRC.ZIP / CBASE.C < prev    next >
C/C++ Source or Header  |  1993-11-16  |  11KB  |  397 lines

  1. /*  $Id$
  2.  *  
  3.  *  File    cbase.c
  4.  *  Part of    ChessBase utilities file format (CBUFF)
  5.  *  Author    Anjo Anjewierden, anjo@swi.psy.uva.nl
  6.  *          Horst Aurisch, aurisch@informatik.uni-bonn.de
  7.  *  Purpose    Manipulation of entire ChessBase databases
  8.  *  Works with    GNU CC 2.4.5
  9.  *  
  10.  *  Notice    Copyright (c) 1993  Anjo Anjewierden
  11.  *  
  12.  *  History    08/06/93  (Created)
  13.  *          03/11/93  (Last modified)
  14.  */ 
  15.  
  16.  
  17. /*------------------------------------------------------------
  18.  *  Directives
  19.  *------------------------------------------------------------*/
  20.  
  21. #include "cbuff.h"
  22.  
  23.  
  24. /*------------------------------------------------------------
  25.  *  Prototypes
  26.  *------------------------------------------------------------*/
  27.  
  28. static CBase    allocCBase(char *);
  29. static void    checkModeCBase(CBase, int);
  30. static long    checkBoundsCBase(CBase, long);
  31.  
  32.  
  33. /*------------------------------------------------------------
  34.  *  Initialisation
  35.  *------------------------------------------------------------*/
  36.  
  37. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  38. @node newCBase
  39. @deftypefun CBase newCBase (char *@var{name}, char *@var{mode})
  40. Allocates a new database and returns it.  @var{name} is the name of 
  41. the database (without the @file{.cbf} extension).  The @var{mode}
  42. argument is similar to the second of @code{fopen}.  @var{mode} can be:
  43. @example
  44. "r"   @r{Open for reading}
  45. "a"   @r{Open for appending}
  46. "c"   @r{Open for writing, create first}
  47. @end example
  48. The @code{"c"} mode requires that a database of the given @var{name}
  49. does not exist, @code{"a"} can be used for both existing and new databases.
  50.  
  51. The constant @code{NULL} is returned when the database cannot be opened or
  52. on another error.
  53. @end deftypefun
  54. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  55.  
  56. CBase
  57. newCBase(char *baseName, char *mode)
  58. { FILE *cbi;
  59.   FILE *cbf;
  60.   CBase cb;
  61.  
  62.   if (strcmp(mode, "r") == 0)
  63.   { cbi = fopenExtension(baseName, "cbi", "rb", TRUE);
  64.     cbf = fopenExtension(baseName, "cbf", "rb", TRUE);
  65.     if (foundError())
  66.     { reportError(stderr);
  67.       if (cbi) fclose(cbi);
  68.       if (cbf) fclose(cbf);
  69.       return NULL;
  70.     }
  71.     cb = allocCBase(baseName);
  72.     cb->cbi = cbi;
  73.     cb->cbf = cbf;
  74.     cb->mode = READ_MODE;
  75.   } else
  76.   if (strcmp(mode, "c") == 0)
  77.   { cbi = fopenExtension(baseName, "cbi", "wb", FALSE);
  78.     cbf = fopenExtension(baseName, "cbf", "wb", FALSE);
  79.     if (foundError())
  80.     { reportError(stderr);
  81.       if (cbi) fclose(cbi);
  82.       if (cbf) fclose(cbf);
  83.       return NULL;
  84.     }
  85.     cb = allocCBase(baseName);
  86.     cb->cbi = cbi;
  87.     cb->cbf = cbf;
  88.     cb->mode = WRITE_MODE;
  89.   } else
  90.   if (strcmp(mode, "a") == 0)
  91.   { cbi = fopenExtension(baseName, "cbi", "r+b", TRUE);
  92.     cbf = fopenExtension(baseName, "cbf", "r+b", TRUE);
  93.     if (foundError())
  94.     { reportError(stderr);
  95.       if (cbi) fclose(cbi);
  96.       if (cbf) fclose(cbf);
  97.       return NULL;
  98.     }
  99.     cb = allocCBase(baseName);
  100.     cb->cbi = cbi;
  101.     cb->cbf = cbf;
  102.     cb->mode = WRITE_MODE;
  103.     fseek(cb->cbi, 0L, 0);
  104.     cb->noGames = readLong(cb->cbi) - 1;
  105.     fseek(cb->cbi, (cb->noGames+1)*sizeof(unsigned long), 0);
  106.     cb->position = readLong(cb->cbi) - cb->noGames - 1;
  107.   } else
  108.   { fprintf(stderr, "Internal error: Opening database %s; mode (%s)?\n",
  109.         baseName, mode);
  110.     exit(1);
  111.   }
  112.  
  113.   if (cb->mode == READ_MODE)
  114.   { long i;
  115.     unsigned long pos;
  116.  
  117.     cb->noGames = readLong(cb->cbi) - 1;
  118.     cb->index = (unsigned long *) alloc(cb->noGames*sizeof(unsigned long));
  119.     if (cb->index == NULL)
  120.     { fprintf(stderr, "Could not allocate index for %s.cbi\n", baseName);
  121.       freeCBase(cb);
  122.       return NULL;
  123.     }
  124.     for (i=1; i<=cb->noGames; i++)
  125.     { pos = readLong(cbi);
  126.       cb->index[i-1] = pos - (i+1);
  127.     }
  128.     cb->position = readLong(cbi) - cb->noGames - 1;
  129.   }
  130.  
  131.   return cb;
  132. }
  133.  
  134.  
  135. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  136. @node freeCBase
  137. @deftypefun void freeCBase (CBase @var{cb})
  138. Reclaims the memory associated with the database @var{cb}.
  139. @end deftypefun
  140. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  141.  
  142. void
  143. freeCBase(CBase cb)
  144. { if (cb->cbf) fclose(cb->cbf);
  145.   if (cb->cbi) fclose(cb->cbi);
  146.   if (cb->index) unalloc(cb->index);
  147.   unallocCharp(cb->name);
  148.   unalloc(cb);
  149. }
  150.  
  151.  
  152. /*------------------------------------------------------------
  153.  *  Functions
  154.  *------------------------------------------------------------*/
  155.  
  156. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  157. @node getNoGamesCBase
  158. @deftypefun long getNoGamesCBase (CBase @var{cb})
  159. Returns the number of games in the database @var{cb}.
  160. @end deftypefun
  161. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  162.  
  163. long
  164. getNoGamesCBase(CBase cb)
  165. { return cb->noGames;
  166. }
  167.  
  168.  
  169. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  170. @node exportGameCBase
  171. @deftypefun void exportGameCBase (CBase @var{dst}, CBase @var{src}, long @var{n})
  172. Exports (appends) game @var{n} from database @var{src} to the output database @var{dst}.
  173. @end deftypefun
  174. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  175.  
  176. void
  177. exportGameCBase(CBase dst, CBase src, long n)
  178. { CbGame cg;
  179.   unsigned char *buf;
  180.   long bytes;
  181.  
  182.   checkModeCBase(dst, WRITE_MODE);
  183.   checkModeCBase(src, READ_MODE);
  184.  
  185.   if (src->index[n-1] & PHYSICALLY_DELETED)
  186.     return;
  187.  
  188.   cg = newCbGame();
  189.   if ((bytes=readCbGame(cg,src,n)) == (long) NULL)
  190.   { reportError(stderr);
  191.     return;
  192.   }
  193.   buf = (unsigned char *) alloc(bytes);
  194.                     /* Read game from source */
  195.   fseek(src->cbf, src->index[n-1], 0);
  196.   fread(buf, 1, bytes, src->cbf);
  197.                     /* Write number of games */
  198.   fseek(dst->cbi, 0L, 0);
  199.   writeLong(dst->noGames+1+1, dst->cbi);
  200.                     /* Write index in destination */
  201.   fseek(dst->cbi, (dst->noGames+1) * sizeof(long), 0);
  202.   writeLong(dst->position+dst->noGames+1+1, dst->cbi);
  203.                     /* Write game in destination */
  204.   fseek(dst->cbf, dst->position, 0);
  205.   fwrite(buf, 1, bytes, dst->cbf);
  206.   dst->position += bytes;
  207.   dst->noGames++;
  208.                     /* Write last position */
  209.   writeLong(dst->position+dst->noGames+1, dst->cbi);
  210.   freeCbGame(cg);
  211.   unalloc(buf);
  212. }
  213.  
  214.  
  215. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  216. @node exportManyBase
  217. @deftypefun void exportManyCBase (CBase @var{dst}, CBase @var{src}, long @var{from}, long @var{to})
  218. Exports (appends) games from @var{from} through @var{to} from database
  219. @var{src} to the output database @var{dst}.
  220. @end deftypefun
  221. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  222.  
  223. void
  224. exportManyCBase(CBase dst, CBase src, long from, long to)
  225. { CbGame cg;
  226.   unsigned char *buf;
  227.   long bytes;
  228.   long n;
  229.   long count, inc;
  230.  
  231.   checkModeCBase(dst, WRITE_MODE);
  232.   checkModeCBase(src, READ_MODE);
  233.  
  234.   from = checkBoundsCBase(src, from);
  235.   to = checkBoundsCBase(src, to);
  236.  
  237.   cg = newCbGame();
  238.  
  239.   fprintf(stderr, "Writing games %ld - %ld to database %s\n",
  240.       from, to, dst->name);
  241.  
  242.   n = to-from+1;
  243.   inc = (n < 50L ? 1 : n/50L);
  244.   
  245.   for (n=from, count=0; n && n<=to; n++, count++)
  246.   { if (count == inc)
  247.     { fprintf(stderr, ".");
  248.       count = 0;
  249.     }
  250.     if (src->index[n-1] & PHYSICALLY_DELETED)
  251.       continue;
  252.     if ((bytes=readCbGame(cg,src,n)) == (long) NULL)
  253.     { reportError(stderr);
  254.       fprintf(stderr, "; Game not written to database\n");
  255.       continue;
  256.     }
  257.     buf = (unsigned char *) alloc(bytes);
  258.                     /* Read game from source */
  259.     fseek(src->cbf, src->index[n-1], 0);
  260.     fread(buf, 1, bytes, src->cbf);
  261.                     /* Write index in destination */
  262.     fseek(dst->cbi, (dst->noGames+1) * sizeof(long), 0);
  263.     writeLong(dst->position+dst->noGames+1+1, dst->cbi);
  264.                     /* Write game in destination */
  265.     fseek(dst->cbf, dst->position, 0);
  266.     fwrite(buf, 1, bytes, dst->cbf);
  267.     dst->position += bytes;
  268.     dst->noGames++;
  269.     unalloc(buf);
  270.   }
  271.                     /* Write last position, assumes
  272.                      * file pointer is correct.
  273.                      */
  274.   writeLong(dst->position+dst->noGames+1, dst->cbi);
  275.                     /* Write number of games */
  276.   fseek(dst->cbi, 0L, 0);
  277.   writeLong(dst->noGames+1, dst->cbi);
  278.   freeCbGame(cg);
  279.  
  280.   fprintf(stderr, "\n");
  281. }
  282.  
  283.  
  284. void
  285. reportCBase(CBase cb, FILE *fd)
  286. { fprintf(fd, "ChessBase database %s (%ld games)\n",
  287.       cb->name, cb->noGames);
  288. }
  289.  
  290.  
  291. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  292. @node deleteGameCBase
  293. @deftypefun void deftypefun (CBase @var{cb}, long @var{n})
  294. Marks game @var{n} in the database @var{cb} for deletion.  The
  295. game will be physically deleted when the game from @var{cb}
  296. is exported to another database (for example with
  297. @code{exportedManyCBase}).
  298. @end deftypefun
  299. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  300.  
  301. void
  302. deleteGameCBase(CBase cb, long n)
  303. { checkModeCBase(cb, READ_MODE);
  304.   if (n >= 1 && n <= cb->noGames)
  305.     cb->index[n-1] |= PHYSICALLY_DELETED;
  306. }
  307.  
  308.  
  309. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  310. @node deletedGameCBaseP
  311. @deftypefun bool deletedGameCBaseP (CBase @var{cb}, long @var{n})
  312. Succeeds if game @var{n} in database @var{cb} has been marked for
  313. deletion with @code{deleteGameCBase}.  Note that this is different
  314. from @code{deleteGameP} (which indicates that the user has marked
  315. the game for deletion).
  316. @end deftypefun
  317. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  318.  
  319. bool
  320. deletedGameCBaseP(CBase cb, long n)
  321. { checkModeCBase(cb, READ_MODE);
  322.   if (n >= 1 && n <= cb->noGames)
  323.   { if (cb->index[n-1] & PHYSICALLY_DELETED)
  324.       return TRUE;
  325.   }
  326.   return FALSE;
  327. }
  328.  
  329.  
  330. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  331. @node getIndexGameCBase
  332. @deftypefun {unsigned long} getIndexGameCBase (CBase @var{cb}, long @var{n})
  333. Returns the index of game @var{n} in database @var{cb}.  The index
  334. is the position where the game starts in the @code{.cbf} file.
  335. @end deftypefun
  336. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  337.  
  338. unsigned long
  339. getIndexGameCBase(CBase cb, long n)
  340. { checkModeCBase(cb, READ_MODE);
  341.   if (n >= 1 && n <= cb->noGames)
  342.     return cb->index[n-1] & ~PHYSICALLY_DELETED;
  343.   return (unsigned long) NULL;
  344. }
  345.  
  346.  
  347. /*------------------------------------------------------------
  348.  *  Private functions
  349.  *------------------------------------------------------------*/
  350.  
  351. static CBase
  352. allocCBase(char *name)
  353. { CBase cb;
  354.  
  355.   cb = alloc(sizeof(struct cbase));
  356.   cb->name = allocCharp(name);
  357.   cb->noGames = 0;
  358.   cb->index = NULL;
  359.   cb->cbf = NULL;
  360.   cb->cbi = NULL;
  361.   cb->position = 0L;
  362.  
  363.   return cb;
  364. }
  365.  
  366.  
  367. static void
  368. checkModeCBase(CBase cb, int mode)
  369. { if (cb->mode != mode)
  370.   { switch (mode)
  371.     { case READ_MODE:
  372.     fprintf(stderr, "Internal error: Database %s not opened for reading\n",
  373.         cb->name);
  374.     exit(1);
  375.     return;
  376.       case WRITE_MODE:
  377.     fprintf(stderr, "Internal error: Database %s not opened for writing\n",
  378.         cb->name);
  379.     exit(1);
  380.     return;
  381.       default:
  382.     fprintf(stderr, "Internal error: checkModeCBase mode = %d\n", mode);
  383.     exit(1);
  384.     }
  385.   }
  386. }
  387.  
  388.  
  389. static long
  390. checkBoundsCBase(CBase cb, long n)
  391. { if (n < 1)
  392.     return 1;
  393.   if (n > cb->noGames)
  394.     return cb->noGames;
  395.   return n;
  396. }
  397.