Support for g++-4.1.
[gf1.git] / gamelog2.cxx
blob56c4e33fc1e7fb82532d0caf24892c4b7a8bfae6
1 /*
2 ** $Id$
3 **
4 ** a lot of things for dealing with the log from a gipf-game
5 **
6 ** the original of this file was gamelog.c
7 ** but because I had to add c++ code I had to rename it
8 */
9 /*
10 ** Copyright (C) 1998 Kurt Van den Branden
12 ** This program is free software; you can redistribute it and/or modify
13 ** it under the terms of the GNU General Public License as published by
14 ** the Free Software Foundation; either version 2 of the License, or
15 ** (at your option) any later version.
16 **
17 ** This program is distributed in the hope that it will be useful,
18 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 ** GNU General Public License for more details.
21 **
22 ** You should have received a copy of the GNU General Public License
23 ** along with this program; if not, write to the Free Software
24 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 #include <stdio.h>
28 #include <string.h>
29 #include <ctype.h>
30 #include <malloc.h>
31 #include <string>
33 #include "gamelog.h"
36 ** create a new, empty log structure
38 ** parameters:
39 ** type: gametype (string)
40 ** wname: name of the player with white
41 ** bname: name of the player with black
43 gamelog * newlog (const char * type, const char * wname, const char * bname)
45 gamelog * log;
47 log = (gamelog *) malloc (sizeof (gamelog));
48 log->gametype = strdup (type);
49 log->whitename = strdup (wname);
50 log->blackname = strdup (bname);
52 log->moves = (listheader *) malloc (sizeof (listheader));
53 newlist (log->moves);
55 return (log);
60 ** delete a complete gamelog structure
62 void deletelog (gamelog * log)
64 logitem * item;
65 char * pos;
67 free (log->gametype);
68 free (log->whitename);
69 free (log->blackname);
71 while ((item = (logitem *) llrembynr (log->moves, 1)) != NULL)
73 if (item->plist != NULL)
75 while ((pos = (char *) llrembynr (item->plist, 1)) != NULL)
77 free (pos);
79 free (item->plist);
82 free (item);
84 free (log->moves);
86 return;
90 ** add to the gamelog
92 ** the contents of 'data' depend on 'type'
93 ** LOGMOVE: <piece>:<from>:<last moved piece>
94 ** LOGREMGIPF: <gipfowner>:<gipf position><piece>
95 ** LOGREMROW: <rowowner>:<rowstart>:<rowend>:[<piece position><piece>:]...
96 ** (remark: the data for LOGREMROW must end on ':')
98 int addtolog (gamelog * log, int type, char * data)
100 logitem * item;
101 char * kar,
102 piece,
103 start[10]=" ",
104 end[10]=" ",
105 pos[10]=" ";
107 item = (logitem *) malloc (sizeof (logitem));
108 item->plist = NULL;
109 item->type = type;
111 switch (type)
113 case LOGMOVE:
114 if (sscanf (data, "%c:%2s:%2s", &piece, start, end) != 3)
116 free (item);
117 return (-1);
119 break;
120 case LOGREMGIPF:
121 if (sscanf (data, "%c:%3s", &piece, pos) != 2)
123 free (item);
124 return (-1);
126 item->plist = (listheader *) malloc (sizeof (listheader));
127 newlist (item->plist);
128 pushll (item->plist, (void *) strdup (pos));
129 break;
130 case LOGREMROW:
131 if (sscanf (data, "%c:%2s:%2s:", &piece, start, end) != 3)
133 free (item);
134 return (-1);
136 item->plist = (listheader *) malloc (sizeof (listheader));
137 newlist (item->plist);
138 kar = data + 8;
139 while (kar[0] != '\0')
141 strncpy (pos, kar, 3);
142 pushll (item->plist, (void *) strdup (pos));
143 kar += 4;
145 break;
147 item->player = piece;
148 strcpy (item->start, start);
149 strcpy (item->end, end);
151 pushll (log->moves, (void *) item);
152 return (0);
155 xmlite_entity * logtoxml (gamelog * log)
157 xmlite_entity *x1, *x2, *x3;
158 char tempstr[100],
159 * strptr;
160 int counter = 1,
161 counter2;
162 logitem * item;
163 char * pos;
165 x1 = new xmlite_entity ("gamelog");
166 x1->addattribute ("gametype", log->gametype);
167 x1->addattribute ("whiteplayer", log->whitename);
168 x1->addattribute ("blackplayer", log->blackname);
170 while ((item = (logitem *) llitembynr (log->moves, counter)) != NULL)
172 counter++;
174 switch (item->type)
176 case LOGMOVE:
177 x2 = new xmlite_entity ("move");
178 x1->addcontent (x2);
179 x2->addattribute ("start", item->start);
180 x2->addattribute ("end", item->end);
181 sprintf (tempstr, "%c", item->player);
182 x2->addattribute ("piece", tempstr);
183 break;
184 case LOGREMGIPF:
185 x2 = new xmlite_entity ("removegipf");
186 x1->addcontent (x2);
187 sprintf (tempstr, "%c", item->player);
188 x2->addattribute ("owner", tempstr);
189 pos = (char *) llitembynr (item->plist, 1);
190 x2->setvalue (pos);
191 break;
192 case LOGREMROW:
193 x2 = new xmlite_entity ("removerow");
194 x1->addcontent (x2);
195 x2->addattribute ("start", item->start);
196 x2->addattribute ("end", item->end);
197 sprintf (tempstr, "%c", item->player);
198 x2->addattribute ("owner", tempstr);
200 counter2 = 1;
201 while ((pos = (char *) llitembynr (item->plist, counter2)) != NULL)
203 counter2++;
205 x3 = new xmlite_entity ("position");
206 x2->addcontent (x3);
207 x3->setvalue (pos);
209 break;
210 default: ;
214 return (x1);
217 gamelog * logfromxml (xmlite_entity * root)
219 gamelog * log;
220 int counter = 0,
221 counter2;
222 xmlite_entity * move,
223 * pos;
224 logitem * item;
226 if (root->getname () != "gamelog")
227 return (NULL);
229 log = newlog (root->getattribute ("gametype").c_str(),
230 root->getattribute ("whiteplayer").c_str(),
231 root->getattribute ("blackplayer").c_str());
233 while ((move = root->getcontentbynr (counter)) != NULL)
235 counter++;
237 item = (logitem *) malloc (sizeof (logitem));
238 item->plist = NULL;
239 pushll (log->moves, (void *) item);
241 if (move->getname () == "move")
243 item->type = LOGMOVE;
244 item->player = (move->getattribute("piece"))[0];
245 strcpy (item->start, move->getattribute("start").c_str());
246 strcpy (item->end, move->getattribute("end").c_str());
248 else if (move->getname() == "removerow")
250 item->type = LOGREMROW;
251 item->player = (move->getattribute("owner"))[0];
252 strcpy (item->start, move->getattribute("start").c_str());
253 strcpy (item->end, move->getattribute("end").c_str());
254 item->plist = (listheader *) malloc (sizeof (listheader));
255 newlist (item->plist);
256 counter2 = 0;
257 while ((pos = move->getcontentbynr (counter2)) != NULL)
259 counter2++;
261 pushll (item->plist,
262 (void *) strdup (pos->getvalue().c_str()));
265 else if (move->getname() == "removegipf")
267 item->type = LOGREMGIPF;
268 item->player = (move->getattribute("owner"))[0];
269 item->plist = (listheader *) malloc (sizeof (listheader));
270 newlist (item->plist);
271 pushll (item->plist, (void *) strdup (move->getvalue().c_str()));
273 else
275 printf ("\nERROR: not a valid move-entry\n\n");
279 return (log);
284 ** write contents of a gamelog-structure to a file
285 ** in the format appropriate for writing down a gipf-game
287 ** parameters:
288 ** log: gamelog structure
289 ** fp: pointer to an open file
291 int logtofile (gamelog * log, FILE * fp)
293 char player = 'o',
294 newplayer,
295 * tempstr;
296 logitem * item;
297 int count = 1,
298 movecounter = 0,
299 textlength = 0,
300 before = 1,
301 totallength = 0,
303 count2;
304 string move,
305 remove,
306 removerow,
307 removewhite = "",
308 removeblack = "";
310 fprintf (fp, " %s\n\n", log->gametype);
312 fprintf (fp, " %-37.37s %s\n\n01. ",
313 log->whitename, log->blackname);
315 while ((item = (logitem *) llitembynr (log->moves, count)) != NULL)
317 count++;
319 if ((item->type == LOGMOVE) ||
320 (item->type == LOGREMROW))
322 if ((removewhite.length() > 0) ||
323 (removeblack.length() > 0))
325 if (player == 'o')
326 remove = removewhite + removerow + removeblack;
327 else
328 remove = removeblack + removerow + removewhite;
330 if (before)
332 fprintf (fp, "%s; ", remove.c_str());
333 totallength += 2 + remove.length();
335 else
337 fprintf (fp, " ; %s", remove.c_str());
338 totallength += 3 + remove.length();
340 removewhite = "";
341 removeblack = "";
344 // check if the next action is for the other player
345 newplayer = tolower (item->player);
346 if (newplayer != player)
348 if (newplayer == 'o')
350 fprintf (fp, "\n%2.2d. ", movecounter/2 + 1);
352 else
354 for (i = totallength; i < 38; i++)
355 fprintf (fp, " ");
357 totallength = 0;
358 player = newplayer;
359 before = 1;
363 if (item->type == LOGMOVE)
365 movecounter++;
367 move = "";
368 if ((item->player == 'O') || (item->player == 'X'))
369 move += "G";
371 move += item->start;
372 move += "-";
373 move += item->end;
374 fprintf (fp, "%s", move.c_str());
376 totallength += move.length();
377 before = 0;
379 else if (item->type == LOGREMGIPF)
381 tempstr = (char *) llitembynr (item->plist, 1);
382 if (tolower (tempstr[2]) == 'o')
384 removewhite += 'G';
385 removewhite += tempstr[0];
386 removewhite += tempstr[1];
387 removewhite += ' ';
389 else
391 removeblack += 'G';
392 removeblack += tempstr[0];
393 removeblack += tempstr[1];
394 removeblack += ' ';
397 else /* must be LOGREMROW now */
399 removerow = "x(";
400 removerow += item->start;
401 removerow += "-";
402 removerow += item->end;
403 removerow += ") ";
405 count2 = 1;
406 while ((tempstr = (char *) llitembynr (item->plist, count2))
407 != NULL)
409 count2++;
410 if (tolower (tempstr[2]) == 'o')
412 removewhite += tempstr[0];
413 removewhite += tempstr[1];
414 removewhite += ' ';
416 else
418 removeblack += tempstr[0];
419 removeblack += tempstr[1];
420 removeblack += ' ';
426 if ((removewhite.length() > 0) ||
427 (removeblack.length() > 0))
429 if (player == 'o')
430 remove = removewhite + removerow + removeblack;
431 else
432 remove = removeblack + removerow + removewhite;
434 if (before)
435 fprintf (fp, "%s; ", remove.c_str());
436 else
437 fprintf (fp, " ; %s", remove.c_str());
439 fprintf (fp, "\n");
441 return (0);
446 ** read log from a file and put it in a gamelog-structure
447 ** (the layout must be the same as written by logtofile)
449 ** the inputfile must already be open and should be at the first
450 ** line from the gamelog
452 ** REMARK: this is only used to read logs in the old fileformat
453 ** (before version 1.02)
455 gamelog * logfromfile (FILE * fp)
457 gamelog * log;
458 char buffer[100],
459 type[100],
460 wname[100],
461 bname[100];
462 logitem * item;
463 char * kar,
464 piece,
465 start[10]=" ",
466 end[10]=" ",
467 pos[10]=" ";
469 if (fgets (buffer, 100, fp) == NULL)
470 return (NULL);
471 buffer[strlen(buffer)-1] = '\0';
472 if (strncmp (buffer, "game: ", 6) != 0)
473 return (NULL);
474 strcpy (type, buffer+6);
476 if (fgets (buffer, 100, fp) == NULL)
477 return (NULL);
478 buffer[strlen(buffer)-1] = '\0';
479 if (strncmp (buffer, "white player: ", 14) != 0)
480 return (NULL);
481 strcpy (wname, buffer+14);
483 if (fgets (buffer, 100, fp) == NULL)
484 return (NULL);
485 buffer[strlen(buffer)-1] = '\0';
486 if (strncmp (buffer, "black player: ", 14) != 0)
487 return (NULL);
488 strcpy (bname, buffer+14);
490 log = newlog (type, wname, bname);
492 fgets (buffer, 100, fp);
493 fgets (buffer, 100, fp);
495 while (1)
497 if (fgets (buffer, 100, fp) == NULL)
499 deletelog (log);
500 return (NULL);
502 if (strncmp (buffer, "end of gamelog", 14) == 0)
503 break;
505 item = (logitem *) malloc (sizeof (logitem));
506 item->plist = NULL;
508 if (sscanf (buffer, "%c: %2s-%2s", &piece, start, end) == 3)
510 item->type = LOGMOVE;
512 else if (sscanf (buffer, " %c removegipf: %3s", &piece, pos) == 2)
514 item->type = LOGREMGIPF;
515 item->plist = (listheader *) malloc (sizeof (listheader));
516 newlist (item->plist);
517 pushll (item->plist, (void *) strdup (pos));
519 else if (sscanf (buffer, " %c removerow (%2s-%2s):",
520 &piece, start, end) == 3)
522 item->type = LOGREMROW;
523 item->plist = (listheader *) malloc (sizeof (listheader));
524 newlist (item->plist);
526 /* find pieces */
527 kar = strchr (buffer, ':');
528 kar++;
529 while (1)
531 while (isspace ((int) kar[0]))
532 kar++;
533 if (sscanf (kar, "%3s", pos) != 1)
534 break;
535 pushll (item->plist, (void *) strdup (pos));
536 kar += 4;
539 item->player = piece;
540 strcpy (item->start, start);
541 strcpy (item->end, end);
543 pushll (log->moves, (void *) item);
546 return (log);
551 ** take the contents of a gamelog-structure and format it in
552 ** a nice way to show in an fltk browser-widget
554 ** this function returns a list of lines that can be sent to the
555 ** widget without change
557 ** !! don't forget to cleanup the list !!
559 listheader * logtobrowser (gamelog * log)
561 listheader * lines;
562 char * newline,
563 whitepieces[50] = "",
564 blackpieces[50] = "",
565 owner = ' ',
566 * tempstr;
567 int movecounter = 0,
568 count = 1,
569 count2;
570 logitem * item;
572 lines = (listheader *) malloc (sizeof (listheader));
573 newlist (lines);
575 newline = (char *) malloc (40); /* is 40 always enough ? */
576 sprintf (newline, "@b%s", log->gametype);
577 pushll (lines, newline);
578 newline = (char *) malloc (1);
579 newline[0] = '\0';
580 pushll (lines, newline);
582 newline = (char *) malloc (40); /* is 40 always enough ? */
583 sprintf (newline, "@iwhite: %s", log->whitename);
584 pushll (lines, newline);
585 newline = (char *) malloc (40); /* is 40 always enough ? */
586 sprintf (newline, "@iblack: %s", log->blackname);
587 pushll (lines, newline);
588 newline = (char *) malloc (1);
589 newline[0] = '\0';
590 pushll (lines, newline);
592 while ((item = (logitem *) llitembynr (log->moves, count)) != NULL)
594 count++;
596 if ((owner != ' ') &&
597 ((item->type == LOGMOVE) || (item->type == LOGREMROW)))
599 newline = (char *) malloc (50); /* is 50 enough ? */
600 if (owner == 'o')
601 sprintf (newline, "@s w: %sx %s",
602 whitepieces, blackpieces);
603 else
604 sprintf (newline, "@s b: %sx %s",
605 blackpieces, whitepieces);
607 pushll (lines, newline);
609 owner = ' ';
610 whitepieces[0] = '\0';
611 blackpieces[0] = '\0';
614 if (item->type == LOGMOVE)
616 if ((movecounter % 2) == 0)
617 { /* need to show the nr of the move here */
618 newline = (char *) malloc (40); /* is 40 always enough ? */
619 sprintf (newline, "@c@b%d", movecounter/2 + 1);
620 pushll (lines, newline);
622 movecounter++;
624 newline = (char *) malloc (40); /* is 40 always enough ? */
625 if (tolower (item->player) == 'o')
626 sprintf (newline, "white: ");
627 else
628 sprintf (newline, "black: ");
630 if ((item->player == 'O') || (item->player == 'X'))
631 sprintf (newline + 7, "G");
633 sprintf (newline + strlen (newline), "%2s-%2s",
634 item->start, item->end);
636 pushll (lines, newline);
638 else if (item->type == LOGREMGIPF)
640 tempstr = (char *) llitembynr (item->plist, 1);
641 if (tolower (tempstr[2]) == 'o')
642 sprintf (whitepieces + strlen (whitepieces), "G%2.2s ",
643 tempstr);
644 else
645 sprintf (blackpieces + strlen (blackpieces), "G%2.2s ",
646 tempstr);
648 else /* must be LOGREMROW now */
650 count2 = 1;
651 owner = tolower (item->player);
653 while ((tempstr = (char *) llitembynr (item->plist, count2))
654 != NULL)
656 count2++;
657 if (tolower (tempstr[2]) == 'o')
658 sprintf (whitepieces + strlen (whitepieces), "%2.2s ",
659 tempstr);
660 else
661 sprintf (blackpieces + strlen (blackpieces), "%2.2s ",
662 tempstr);
667 if (owner != ' ')
669 newline = (char *) malloc (50); /* is 50 enough ? */
670 if (owner == 'o')
671 sprintf (newline, "@s w: %sx %s",
672 whitepieces, blackpieces);
673 else
674 sprintf (newline, "@s b: %sx %s",
675 blackpieces, whitepieces);
677 pushll (lines, newline);
680 return (lines);
685 ** return 1 if this logitem represents a move
687 int isamove (void * data)
689 logitem * item = (logitem *) data;
691 if (item->type == LOGMOVE)
692 return (1);
694 return (0);
699 ** remove the last move from a gamelog
700 ** (include all the removerows and removegipfs)
702 ** returns:
703 ** -1: error
704 ** number of items removed from the log
706 int remlastmove (gamelog * log)
708 int nr,
709 counter = 0;
710 logitem * item;
711 char * pos;
713 if ((nr = findlastll (log->moves, isamove)) == 0)
715 return (-1);
718 /* delete everything from the last move to the end of the list */
719 while ((item = (logitem *) llrembynr (log->moves, nr)) != NULL)
721 if (item->plist != NULL)
723 while ((pos = (char *) llrembynr (item->plist, 1)) != NULL)
725 free (pos);
727 free (item->plist);
730 free (item);
731 counter++;
734 return (counter);