root/05/release-0.5j/sgfpars.cc

Revision 65, 21.6 kB (checked in by ug, 5 years ago)

Another typo

Line 
1// File: sgfpars.cc
2
3//   Copyright (C) 2001-4 Ulrich Goertz (u@g0ertz.de)
4
5//   This is part of Kombilo, a go database program.
6
7//   This program is free software; you can redistribute it and/or modify
8//   it under the terms of the GNU General Public License as published by
9//   the Free Software Foundation; either version 2 of the License, or
10//   (at your option) any later version.
11
12//   This program is distributed in the hope that it will be useful,
13//   but WITHOUT ANY WARRANTY; without even the implied warranty of
14//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15//   GNU General Public License for more details.
16
17//   You should have received a copy of the GNU General Public License
18//   along with this program (see doc/license.txt); if not, write to the Free Software
19//   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20//   The GNU GPL is also currently available at
21//   http://www.gnu.org/copyleft/gpl.html
22
23
24
25#include "sgfpars.h"
26// #include <cstring>
27
28intN::intN(int i, intN* p) { 
29  data = i; 
30  prev = p; 
31}
32
33IntStack::IntStack() { 
34  root = 0; 
35}
36
37void IntStack::push(int i) {
38  intN* n = new intN(i, root);
39  root = n;
40}
41
42void IntStack::pop() {
43  intN* d = root;
44  root = d->prev;
45  delete d;
46}
47
48int IntStack::top() {
49  if (root) return root->data;
50  else return -1;
51}
52
53bool IntStack::nonempty() {
54  if (root) return 1;
55  else return 0;
56}
57
58
59nodeN::nodeN(Node* i, nodeN* p) { 
60  data = i; 
61  prev = p; 
62}
63
64NodeStack::NodeStack() { 
65  root = 0; 
66}
67
68void NodeStack::push(Node* i) {
69  nodeN* n = new nodeN(i, root);
70  root = n;
71}
72
73void NodeStack::pop() {
74  nodeN* d = root;
75  root = d->prev;
76  delete d;
77}
78
79Node* NodeStack::top() {
80  if (root) return root->data;
81  else return 0;
82}
83
84bool NodeStack::nonempty() {
85  if (root) return 1;
86  else return 0;
87}
88
89
90
91
92SGFError::SGFError() {}
93
94char* SGFescape(char* s) {
95  char* t = new char[2*strlen(s)+1];
96  int j = 0;
97  for(int i = 0; i<strlen(s); i++) {
98    if (s[i] == '\\' || s[i] == ']') t[j++]='\\';
99    t[j++] = s[i];
100  }
101                                   
102  t[j++] = 0;
103
104  char* result = new char[j];
105  strcpy(result, t);
106  delete t;
107  return result;
108}
109
110Node::Node(Node* prev, char* SGFst, int lvl=0) throw(SGFError) {
111  next = NULL;
112  previous = prev;
113  up = NULL;
114  down = NULL;
115
116  numChildren = 0;
117  level = lvl;
118       
119  parsed = 0;
120
121  if (SGFst) {
122    SGFstring = new char[strlen(SGFst)+1];
123    strcpy(SGFstring, SGFst);
124    if (!(data=PyDict_New())) throw SGFError();
125    parseNode();
126  }
127  else {
128    SGFstring = new char[1];
129    SGFstring[0] = 0;
130    if (!(data = PyDict_New())) throw SGFError();
131  }
132   
133  posyD = 0;
134}
135       
136Node::~Node() {
137  delete [] SGFstring;
138  Py_DECREF(data);
139}
140
141
142PyObject* Node::getData() {
143  if (!parsed) parseNode();
144  Py_INCREF(data);
145  return data;
146}
147
148PyObject* Node::pathToNode() {
149  PyObject* l = PyList_New(0);
150  Node* n = this;
151
152  while (n->previous) {
153    PyList_Append(l, PyInt_FromLong(n->level));
154    n = n->previous;
155  }       
156  PyList_Reverse(l);
157  return l;
158}
159
160
161void Node::parseNode() throw(SGFError) {
162  // printf("Parse node, %s\n", SGFstring);
163
164  if (!parsed) {
165
166    char* s = SGFstring;
167    int lSGFstring = strlen(s);
168    int i = 0;
169   
170    while (i < lSGFstring && s[i] != ';' && (s[i]==' ' || s[i]=='\n' || s[i]=='\r' || s[i]=='\t')) 
171      i++;
172   
173    if (i>=lSGFstring) {
174      throw SGFError();
175    }
176    if (s[i] != ';') {
177      throw SGFError();
178    }
179    i++;
180   
181    while (i < lSGFstring) {
182      while (i < lSGFstring && (s[i]==' ' || s[i]=='\n' || s[i]=='\r' || s[i]=='\t')) 
183        i++;
184     
185      if (i >= lSGFstring) break;
186     
187      char ID[20];
188      int IDindex = 0;
189     
190      while (i < lSGFstring && s[i] != '[') {
191        if (65 <= s[i] && s[i] <= 90)
192          ID[IDindex++] = s[i];
193        else if (!(97 <= s[i] && s[i] <= 122) && !(s[i]==' ' || s[i]=='\n' || s[i]=='\r' || s[i]=='\t')) {
194          throw SGFError();
195        }
196       
197        i++;
198      }
199     
200      i++;
201     
202      if (i >= lSGFstring) {
203        throw SGFError();
204      }
205     
206      if (!IDindex) {
207        throw SGFError();
208      }
209      ID[IDindex] = 0;
210     
211      if (PyDict_GetItemString(data, ID)) {
212        if (!Node::sloppy) {
213          throw SGFError();
214        }
215      }
216      else {
217        PyObject* nl = PyList_New(0);
218        if (!nl) {
219          throw SGFError(); 
220        }
221        if (PyDict_SetItemString(data, ID, nl)==-1) {
222          throw SGFError();
223        }
224        Py_DECREF(nl);
225      }
226     
227      PyObject* propertyValueList = PyDict_GetItemString(data, ID);
228      if (!propertyValueList) {
229        throw SGFError();
230      }
231     
232      while (i < lSGFstring) {
233        char* propValue = new char[lSGFstring+1];
234        int propValueIndex = 0;
235       
236        while (s[i] != ']') {
237         
238          //printf("i, s[i]: %d, %c\n", i, s[i]);
239          if (s[i] == '\t') {
240            propValue[propValueIndex++] = ' ';
241            i++;
242            continue;
243          }
244          if (s[i] == '\\') {
245            i++;
246           
247            if ((s[i]=='\n' && s[i+1]=='\r') || (s[i]=='\r' && s[i+1]=='\n')) {
248              i += 2;
249              continue;
250            }
251            else if (s[i]=='\n' || s[i]=='\r') {
252              i++;
253              continue;
254            }
255          }
256          propValue[propValueIndex++] = s[i];
257          i++;
258         
259          if (i >= lSGFstring) {
260            throw SGFError();
261          }
262        }
263       
264        propValue[propValueIndex] = 0;
265        PyObject* hlp = PyString_FromString(propValue);
266        PyList_Append(propertyValueList, hlp);
267        delete [] propValue;
268        Py_DECREF(hlp);
269       
270        i++;
271       
272        while (i < lSGFstring && (s[i]==' ' || s[i]=='\n' || s[i]=='\r' || s[i]=='\t')) 
273          i++;
274       
275        if (i >= lSGFstring || s[i] != '[') break;
276        else i++;
277      }
278     
279      if (!strcmp(ID, "B") || !strcmp(ID, "W") || !strcmp(ID, "AW") || !strcmp(ID, "AB")) {
280        for(int N=0; N < PyList_Size(propertyValueList); N++) {
281          char* en = PyString_AsString(PyList_GetItem(propertyValueList, N));
282          char* en1 = new char[strlen(en)+1];
283          int jj = 0;
284         
285          for (int ii=0; ii<strlen(en); ii++) {
286            if (!Node::sloppy || !(en[ii]=='\n' || en[ii]=='\r')) 
287              en1[jj++] = en[ii];
288          }
289          en1[jj] = 0;
290         
291          if (!(strlen(en1) == 2 || (strlen(en) == 0 && (!strcmp(ID,"B") || !strcmp(ID,"W"))))) {
292            throw SGFError();
293          }
294         
295          PyList_SetItem(propertyValueList, N, PyString_FromString(en1));
296          delete en1;
297        }
298      }                                       
299     
300    }
301    parsed = 1;
302  }
303}   
304   
305
306int Node::sloppy = 1;
307
308Cursor::Cursor(char* sgf, int sloppy) throw(SGFError) {
309  Node::sloppy = sloppy;
310
311  height = 0;
312  width = 0;
313  posx = 0;
314  posy = 0;
315
316  root = new Node(NULL, NULL, 0);
317  parse(sgf);
318
319  currentN = root->next;
320  setFlags();       
321
322  if (!currentN->parsed) currentN->parseNode();
323
324  PyObject* val = PyDict_GetItemString(currentN->data, "CA");
325  PyObject* v = 0;
326
327  if (val && PyList_Check(val) && PyList_Size(val)) v = PyList_GetItem(val, 0); 
328  if (v && PyString_Check(v)) {
329    char* s = PyString_AsString(v);
330    encoding = new char[strlen(s)+1];
331    strcpy(encoding, s);
332  }
333  else {
334    encoding = new char[1];
335    encoding[0] = 0;
336  }
337}
338
339
340
341Cursor::~Cursor() {
342  deltree(root);
343  delete [] encoding;
344}
345
346void Cursor::setFlags() {
347  if (currentN->next) atEnd = 0;
348  else atEnd = 1;
349  if (currentN->previous) atStart = 0;
350  else atStart = 1;
351}
352 
353int Cursor::noChildren() {
354  return currentN->numChildren;
355}
356
357PyObject* Cursor::currentNode() {
358  if (!currentN->parsed)
359    currentN->parseNode();
360
361  Py_INCREF(currentN->data); 
362  return currentN->data;
363}
364
365void Cursor::parse(char* s) throw(SGFError) {
366
367  Node* curr = root;       
368  int p = -1;           // start of the currently parsed node
369  NodeStack c;       // stack of nodes from which variations started
370  IntStack c_width;
371  IntStack c_height;
372
373  int height_previous = 0;
374  int width_currentVar = 0;
375
376  char last = ')';      // type of last parsed bracked ('(' or ')')
377  bool inbrackets = false;   // are the currently parsed characters in []'s?
378
379  int i = 0;  // current parser position
380  int lSGFstring = strlen(s);
381
382  int found_par = 0;
383  while (i < lSGFstring) {
384    if (s[i]=='(') {
385      found_par = i+1;
386      i++;
387      continue;
388    }
389    if (found_par && s[i]==';') break;
390   
391    if (found_par && !(s[i]==' ' || s[i]=='\n' || s[i]=='\r' || s[i]=='\t'))
392      found_par = 0;
393    i++;
394  }
395
396  if (i >= lSGFstring) throw SGFError();
397
398  i = found_par-1; // found beginning of SGF file
399       
400  while (i < lSGFstring) {
401    while (i < lSGFstring && !(s[i]=='(' || s[i]==')' || s[i]=='[' || s[i]==']' || s[i]==';')) i++; 
402    if (i >= lSGFstring) break;
403
404    if (inbrackets) {
405      if (s[i]==']') {
406        int numberBackslashes = 0;
407        int j = i-1;
408        while (s[j] == '\\') {
409          numberBackslashes++;
410          j--;
411        }
412        if (!(numberBackslashes % 2))
413          inbrackets = 0;
414      }
415      i++;
416      continue;
417    }
418         
419    if (s[i] == '[') inbrackets = 1;
420       
421    if (s[i] == '(') {
422      if (last != ')' && p != -1) {
423        delete[] curr->SGFstring;
424        curr->SGFstring = new char[i-p+1];
425        curr->SGFstring = strncpy(curr->SGFstring, s+p, i-p);       
426        curr->SGFstring[i-p] = 0;
427        // curr->parseNode();
428      }
429
430      Node* nn = new Node(0,0,0);
431      nn->previous = curr;
432
433      if (++width_currentVar > width) width = width_currentVar;
434      if (curr->next) {
435        Node* last = curr->next;
436        while (last->down) last = last->down;
437        nn->up = last;                                 
438        last->down = nn;
439        nn->level = last->level + 1;
440        height++;
441        nn->posyD = height - height_previous;
442      }
443      else {
444        curr->next = nn;
445        nn->posyD = 0;
446        height_previous = height;
447      }
448
449      curr->numChildren++;
450     
451      c.push(curr);
452      c_width.push(width_currentVar-1);
453      c_height.push(height);
454         
455      curr = nn;
456               
457      p = -1;
458      last = '(';
459    }
460
461    if (s[i] == ')') {
462      if (last != ')' && p != -1) {
463        delete[] curr->SGFstring;
464        curr->SGFstring = new char[i-p+1];
465        curr->SGFstring = strncpy(curr->SGFstring, s+p, i-p);       
466        curr->SGFstring[i-p] = 0;
467        // curr->parseNode();
468      }
469      if (c.nonempty()) { 
470        curr = c.top();
471        c.pop();
472        width_currentVar = c_width.top();
473        c_width.pop();
474        height_previous = c_height.top();
475        c_height.pop();
476      }
477      else {
478        throw SGFError();
479      }
480      last = ')';
481    }
482   
483    if (s[i] == ';') {
484      if (p != -1) {
485        delete[] curr->SGFstring;
486        curr->SGFstring = new char[i-p+1];
487        curr->SGFstring = strncpy(curr->SGFstring, s+p, i-p);       
488        curr->SGFstring[i-p] = 0;
489        // curr->parseNode();
490
491        Node* nn = new Node(0,0,0);
492        nn->previous = curr;
493
494        if (++width_currentVar > width) width = width_currentVar;
495        nn->posyD = 0;
496        curr->numChildren = 1;
497        curr->next = nn;
498        curr = nn;
499      }
500      p = i;
501    }
502
503    i++;
504  }
505
506  if (inbrackets || c.nonempty()) throw SGFError();
507 
508  Node* n = curr->next;
509  n->previous = NULL;
510  n->up = NULL;
511
512  while (n->down) {
513    n = n->down;
514    n->previous = NULL;
515  }
516}
517
518void Cursor::game(int n) throw(SGFError) {
519  if (n < root->numChildren) {
520    posx = 0;
521    posy = 0;
522    currentN = root->next;
523    for(int i=0; i<n; i++) currentN = currentN->down;
524    setFlags();
525  }
526  else throw SGFError();
527}
528
529
530
531
532void Cursor::deltree(Node* node) {
533  Node* n;
534
535  if (node->next) {
536    n = node->next;
537
538    while (n->down) {
539      n = n->down;
540      deltree(n->up);
541    }
542
543    deltree(n);
544  }
545
546  delete node;
547}
548
549
550
551
552void Cursor::delVariation(Node* c) {
553
554  if (c->previous) {
555    delVar(c);
556  }
557  else {
558    if (c->next) {
559      Node* node = c->next;
560      while (node->down) {
561        node = node->down;
562        delVar(node->up);
563      } 
564      delVar(node);
565    }
566    c->next = 0;
567  }
568
569  setFlags();
570}
571
572void Cursor::delVar(Node* node) {
573
574  if (node->up) node->up->down = node->down;
575  else {
576    node->previous->next = node->down;
577  }
578  if (node->down) {
579    node->down->up = node->up;
580    node->down->posyD = node->posyD;
581    Node* n = node->down;
582    while (n) { 
583      n->level--;
584      n = n->down;
585    }
586  }
587
588  int h = 0;
589  Node* n = node;
590  while (n->next) {
591    n = n->next;
592    while (n->down) {
593      n = n->down;
594      h += n->posyD;
595    }
596  }
597
598  if (node->up || node->down) h++;
599
600  Node* p = node->previous;
601  p->numChildren--;
602
603  while (p) {
604    if (p->down) p->down->posyD -= h;
605    p = p->previous;
606  }
607
608  height -= h;
609
610  // p = node->down;
611  deltree(node);
612  // node = 0;
613}
614
615
616void Cursor::add(char* st) {
617
618  Node* node = new Node(currentN,st,0);
619
620  node->down = 0;
621  node->next = 0;
622  node->numChildren = 0;
623
624  if (!currentN->next) {
625    // printf("new %s at %s\n", node->SGFstring, currentN->SGFstring);
626    node->level = 0;
627    node->posyD = 0;
628    node->up = 0;
629
630    currentN->next = node;
631    currentN->numChildren = 1;
632  }
633  else {
634    // printf("adding %s at %s\n", node->SGFstring, currentN->SGFstring);
635    Node* n = currentN->next;
636    while (n->down) {
637      n = n->down;
638      posy+=n->posyD;
639    }
640   
641    n->down = node;
642    node->up = n;
643    node->level = n->level + 1;
644    node->next= 0;
645    currentN->numChildren++;
646
647    node->posyD = 1;
648    while (n->next) {
649      n = n->next;
650      while (n->down) {
651        n = n->down;
652        node->posyD += n->posyD;
653      }
654    }
655    posy += node->posyD;
656
657    height++;
658
659    n = node;
660    while (n->previous) {
661      n = n->previous;
662      if (n->down) n->down->posyD++;
663    }
664
665  }
666
667  currentN = node;
668
669  posx++;
670  setFlags();
671
672  if (posx > width) width++;
673
674}
675
676
677PyObject* Cursor::next(int n) throw(SGFError) {
678
679  if (n >= noChildren()) {
680    throw SGFError();
681  }
682  posx++;
683  currentN = currentN->next;
684  for (int i=0; i<n; i++) {
685    currentN = currentN->down;
686    posy += currentN->posyD;
687  }
688  setFlags();
689
690  return currentNode();
691}
692   
693PyObject* Cursor::previous() throw(SGFError) {
694  if (currentN->previous) {
695    while (currentN->up) {
696      posy -= currentN->posyD;
697      currentN = currentN->up;
698    }
699    currentN = currentN->previous;
700    posx--;
701  }
702  else throw SGFError();
703  setFlags();
704  return currentNode();
705}
706
707PyObject* Cursor::getRootNode(int n) throw(SGFError) {
708  if (!root) {
709    Py_INCREF(Py_None);
710    return Py_None;
711  }
712
713  if (n >= root->numChildren) throw SGFError();
714  Node* nn = root->next;
715  for(int i=0; i<n; i++) nn = nn->down; 
716 
717  if (!nn->parsed) nn->parseNode();
718  Py_INCREF(nn->data);
719  return nn->data;
720}
721
722
723void Cursor::updateCurrentNode() throw(SGFError) {
724  delete[] currentN->SGFstring;
725  currentN->SGFstring = nodeToString(currentN->data);
726  if (!currentN->parsed) {
727    currentN->parsed = 1;
728  }
729
730  // Py_DECREF(currentN->data);
731  // if (!(currentN->data=PyDict_New())) throw SGFError();
732  // currentN->parseNode();
733}
734
735void Cursor::updateRootNode(PyObject* data, int n) throw(SGFError) {
736  if (n >= root->numChildren) throw SGFError();
737  Node* nn = root->next;
738  for(int i=0; i<n; i++) nn = nn->down;
739  delete[] nn->SGFstring;
740  nn->SGFstring = rootNodeToString(data);
741  Py_DECREF(nn->data);
742  if (!(nn->data=PyDict_New())) throw SGFError();
743  nn->parsed = 0;
744  nn->parseNode();
745}
746
747
748char* Cursor::rootNodeToString(PyObject* data) {
749  char result[10000];
750  result[0] = 0;
751  strcat(result, ";");
752 
753  PyObject* item;
754  if ((item=PyDict_GetItem(data, PyString_FromString("GM")))) {
755    strcat(result, "GM[");
756    char* t = SGFescape(PyString_AsString(PyList_GetItem(item, 0)));
757    strcat(result, t);
758    delete[] t;
759    strcat(result, "]\n");
760  }
761  if ((item=PyDict_GetItem(data, PyString_FromString("FF")))) {
762    strcat(result, "FF[");
763    char* t = SGFescape(PyString_AsString(PyList_GetItem(item, 0)));
764    strcat(result, t);
765    delete[] t;
766    strcat(result, "]\n");
767  }
768  if ((item=PyDict_GetItem(data, PyString_FromString("SZ")))) {
769    strcat(result, "SZ[");
770    char* t = SGFescape(PyString_AsString(PyList_GetItem(item, 0)));
771    strcat(result, t);
772    delete[] t;
773    strcat(result, "]\n");
774  }
775  if ((item=PyDict_GetItem(data, PyString_FromString("PW")))) {
776    strcat(result, "PW[");
777    char* t = SGFescape(PyString_AsString(PyList_GetItem(item, 0)));
778    strcat(result, t);
779    delete[] t;
780    strcat(result, "]\n");
781  }
782  if ((item=PyDict_GetItem