OJD database committing support
[eidogo-ojd.git] / kombilo / sgfparser.cpp
blob95e6d87b46c280bdae790f413ce86651d2608a2a
1 // File: sgfparser.cpp
2 // part of libkombilo, http://www.u-go.net/kombilo/
4 // Copyright (c) 2006-7 Ulrich Goertz <u@g0ertz.de>
6 // Permission is hereby granted, free of charge, to any person obtaining a copy of
7 // this software and associated documentation files (the "Software"), to deal in
8 // the Software without restriction, including without limitation the rights to
9 // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
10 // of the Software, and to permit persons to whom the Software is furnished to do
11 // so, subject to the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be included in all
14 // copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 // SOFTWARE.
24 #include "sgfparser.h"
26 using std::vector;
27 using std::stack;
28 using std::pair;
29 using std::map;
30 using std::string;
32 SGFError::SGFError() {}
34 ExtendedMoveNumber::ExtendedMoveNumber() {
35 length = 0;
36 data = 0;
39 ExtendedMoveNumber::ExtendedMoveNumber(int LENGTH, int* DATA) {
40 length = LENGTH;
41 if (length) data = new int[length];
42 else data = 0;
43 for(int i=0; i<length; i++) data[i] = DATA[i];
46 ExtendedMoveNumber::ExtendedMoveNumber(int D) {
47 length = 1;
48 data = new int[1];
49 data[0] = D;
52 ExtendedMoveNumber::ExtendedMoveNumber(const ExtendedMoveNumber& emn) {
53 length = emn.length;
54 if (length) data = new int[length];
55 else data = 0;
56 for(int i=0; i<length; i++) data[i] = emn.data[i];
59 ExtendedMoveNumber::~ExtendedMoveNumber() {
60 if (data) delete [] data;
63 ExtendedMoveNumber& ExtendedMoveNumber::operator=(const ExtendedMoveNumber& emn) {
64 if (this != &emn) {
65 length = emn.length;
66 if (data) delete [] data;
67 if (length) {
68 data = new int[length];
69 for(int i=0; i<length; i++) data[i] = emn.data[i];
70 } else data = 0;
72 return *this;
75 void ExtendedMoveNumber::next() {
76 data[length-1]++;
79 void ExtendedMoveNumber::down() throw(SGFError) {
80 if (length==0) throw SGFError();
81 else if (length==1) {
82 int* newdata = new int[3];
83 newdata[0] = data[0];
84 newdata[1] = 1;
85 newdata[2] = 0;
86 length = 3;
87 delete [] data;
88 data = newdata;
89 } else {
90 if (data[length-1]) {
91 int* newdata = new int[length+2];
92 for(int i=0; i<length; i++) newdata[i] = data[i];
93 newdata[length] = 1;
94 newdata[length+1] = 0;
95 length += 2;
96 delete [] data;
97 data = newdata;
98 } else data[length-2]++;
102 int ExtendedMoveNumber::total_move_num() {
103 int result = 0;
104 for(int i=0; i<(length+1)/2; i++) result += data[2*i];
105 return result;
108 char* SGFescape(const char* s) {
109 char* t = new char[2*strlen(s)+1];
110 int j = 0;
111 for(unsigned int i = 0; i<strlen(s); i++) {
112 if (s[i] == '\\' || s[i] == ']') t[j++]='\\';
113 t[j++] = s[i];
116 t[j++] = 0;
118 char* result = new char[j];
119 strcpy(result, t);
120 delete t;
121 return result;
124 vector<string>* parseRootNode(Node* n, vector<string>* tags) throw(SGFError) {
125 vector<string>* results = new vector<string>(tags->size());
126 string s = n->SGFstring;
127 int lSGFstring = s.size();
128 int i = 0;
130 while (i < lSGFstring && s[i] != ';' && (s[i]==' ' || s[i]=='\n' || s[i]=='\r' || s[i]=='\t'))
131 i++;
133 if (i>=lSGFstring || s[i] != ';') throw SGFError();
134 i++;
136 while (i < lSGFstring) {
137 while (i < lSGFstring && (s[i]==' ' || s[i]=='\n' || s[i]=='\r' || s[i]=='\t'))
138 i++;
140 if (i >= lSGFstring) break;
142 char ID[30];
143 int IDindex = 0;
145 while (i < lSGFstring && s[i] != '[' && IDindex < 30) {
146 if (65 <= s[i] && s[i] <= 90) {
147 ID[IDindex++] = s[i];
148 } else if (!(97 <= s[i] && s[i] <= 122) && (!(s[i]==' ' || s[i]=='\n' || s[i]=='\r' || s[i]=='\t'))) {
149 throw SGFError();
151 i++;
153 i++;
155 if (i >= lSGFstring || IDindex >= 30 || !IDindex) {
156 throw SGFError();
158 ID[IDindex] = 0;
160 char* propValue = new char[lSGFstring+1];
161 int propValueIndex = 0;
163 while (i < lSGFstring) {
165 while (s[i] != ']') {
166 if (s[i] == '\t') {
167 propValue[propValueIndex++] = ' ';
168 i++;
169 continue;
171 if (s[i] == '\\') {
172 i++;
173 if ((s[i]=='\n' && s[i+1]=='\r') || (s[i]=='\r' && s[i+1]=='\n')) {
174 i += 2;
175 continue;
177 else if (s[i]=='\n' || s[i]=='\r') {
178 i++;
179 continue;
182 propValue[propValueIndex++] = s[i];
183 i++;
185 if (i >= lSGFstring) {
186 throw SGFError();
190 propValue[propValueIndex++] = ',';
191 propValue[propValueIndex++] = ' ';
193 i++;
194 while (i < lSGFstring && (s[i]==' ' || s[i]=='\n' || s[i]=='\r' || s[i]=='\t'))
195 i++;
196 if (i >= lSGFstring || s[i] != '[') {
197 propValue[propValueIndex-2] = 0;
198 string IDstring = ID;
199 int ctr = 0;
200 for(vector<string>::iterator it = tags->begin(); it != tags->end(); it++) {
201 if (IDstring == *it) {
202 (*results)[ctr] = propValue;
203 break;
205 ctr++;
207 delete [] propValue;
208 break;
210 else i++;
213 return results;
216 PropValue::PropValue(std::string IDC, std::vector<std::string>* PV) {
217 IDcomplete = IDC;
218 pv = PV;
221 PropValue::~PropValue() {
222 if (pv) delete pv;
226 Node::Node(Node* prev, char* SGFst, int lvl=0) throw(SGFError) {
227 next = NULL;
228 previous = prev;
229 up = NULL;
230 down = NULL;
231 numChildren = 0;
232 level = lvl;
233 parsed = 0;
235 if (SGFst) {
236 SGFstring = SGFst;
237 // parseNode();
238 } else SGFstring = "";
239 posyD = 0;
242 Node::~Node() {
245 string remove_lowercase(string s) throw(SGFError) {
246 char ID[s.size()+1];
247 int IDindex = 0;
248 for(unsigned int i=0; i<s.size(); i++) {
249 if (65 <= s[i] && s[i] <= 90) ID[IDindex++] = s[i];
250 else if (!(97 <= s[i] && s[i] <= 122)) {
251 throw SGFError();
254 ID[IDindex] = 0;
255 return string(ID);
258 vector<string> Node::gpv(const string& prop) {
259 vector<string>* result = get_property_value(prop);
260 if (result) return *result;
261 else return vector<string>();
264 vector<string>* Node::get_property_value(const string& prop) {
265 if (!parsed) {
266 parseNode();
268 map<string, PropValue >::iterator result = data.find(remove_lowercase(prop));
269 if (result == data.end()) return 0;
270 else return result->second.pv;
273 ExtendedMoveNumber Node::get_move_number() {
274 vector<int> l;
275 Node* n = this;
276 l.push_back(0);
278 while (n->previous) {
279 if (n->level) l.push_back(n->level);
280 else l[l.size()-1]++;
281 n = n->previous;
284 int* result = new int[l.size()];
285 for(int i = l.size()-1; i >= 0; i--) {
286 result[l.size()-i-1] = l[i];
288 ExtendedMoveNumber emn(l.size(), result);
289 delete [] result;
290 return emn;
294 void Node::parseNode() throw(SGFError) {
295 // printf("Parse node, %s\n", SGFstring);
296 if (!parsed) {
297 string s = SGFstring;
298 int lSGFstring = s.size();
299 int i = 0;
301 while (i < lSGFstring && s[i] != ';' && (s[i]==' ' || s[i]=='\n' || s[i]=='\r' || s[i]=='\t'))
302 i++;
304 if (i>=lSGFstring || s[i] != ';') throw SGFError();
305 i++;
307 while (i < lSGFstring) {
308 while (i < lSGFstring && (s[i]==' ' || s[i]=='\n' || s[i]=='\r' || s[i]=='\t'))
309 i++;
311 if (i >= lSGFstring) break;
313 char ID[30];
314 int IDindex = 0;
315 char IDcomplete[100]; // store long property name here
316 int IDcompleteIndex = 0;
318 while (i < lSGFstring && s[i] != '[' && IDindex < 30 && IDcompleteIndex < 100) {
319 if (65 <= s[i] && s[i] <= 90) {
320 ID[IDindex++] = s[i];
321 IDcomplete[IDcompleteIndex++] = s[i];
322 } else if (97 <= s[i] && s[i] <= 122) {
323 IDcomplete[IDcompleteIndex++] = s[i];
324 } else if (!(s[i]==' ' || s[i]=='\n' || s[i]=='\r' || s[i]=='\t')) {
325 throw SGFError();
327 i++;
329 i++;
331 if (i >= lSGFstring || IDindex >= 30 || !IDindex || IDcompleteIndex >= 100) {
332 throw SGFError();
334 ID[IDindex] = 0;
335 IDcomplete[IDcompleteIndex] = 0;
336 vector<string>* propValueList = new vector<string>;
338 while (i < lSGFstring) {
339 string propValue;
341 while (s[i] != ']') {
342 //printf("i, s[i]: %d, %c\n", i, s[i]);
343 if (s[i] == '\t') {
344 propValue += ' ';
345 i++;
346 continue;
348 if (s[i] == '\\') {
349 i++;
351 if ((s[i]=='\n' && s[i+1]=='\r') || (s[i]=='\r' && s[i+1]=='\n')) {
352 i += 2;
353 continue;
355 else if (s[i]=='\n' || s[i]=='\r') {
356 i++;
357 continue;
360 if (Node::sloppy && (s[i] == '\n' || s[i] == '\r') && \
361 (!strcmp(ID, "B") || !strcmp(ID, "W") || !strcmp(ID, "AW") || !strcmp(ID, "AB"))) {
362 i++;
363 continue;
366 propValue += s[i]; // building propValue in this way could be a performance problem
367 // maybe we should use reserve before. FIXME
368 i++;
370 if (i >= lSGFstring) throw SGFError();
372 if ((!strcmp(ID,"B") || !strcmp(ID,"W")) && !(propValue.size() == 2 || (propValue.size() == 0))) {
373 throw SGFError();
376 propValueList->push_back(propValue);
377 i++;
379 while (i < lSGFstring && (s[i]==' ' || s[i]=='\n' || s[i]=='\r' || s[i]=='\t'))
380 i++;
381 if (i >= lSGFstring || s[i] != '[') break;
382 else i++;
384 data.insert(make_pair(string(ID), PropValue(string(IDcomplete), propValueList)));
386 parsed = 1;
390 void Node::set_property_value(string& IDcomplete, vector<string>* propValue) throw(SGFError) {
391 string ID = remove_lowercase(IDcomplete);
392 map<string, PropValue >::iterator it = data.find(ID);
393 if (it == data.end()) data.insert(make_pair(ID, PropValue(IDcomplete, propValue)));
394 else it->second.pv->insert(it->second.pv->end(), propValue->begin(), propValue->end());
395 SGFstring = nodeToString(data);
396 parsed = 1;
400 int Node::sloppy = 1;
402 Cursor::Cursor(const char* sgf, int sloppy) throw(SGFError) {
403 Node::sloppy = sloppy;
405 height = 0;
406 width = 0;
407 posx = 0;
408 posy = 0;
410 root = new Node(NULL, NULL, 0);
411 parse(sgf);
413 currentN = root->next;
414 setFlags();
417 Cursor::~Cursor() {
418 deltree(root);
421 void Cursor::setFlags() {
422 if (currentN->next) atEnd = 0;
423 else atEnd = 1;
424 if (currentN->previous) atStart = 0;
425 else atStart = 1;
428 void Cursor::parse(const char* s) throw(SGFError) {
430 Node* curr = root;
431 int p = -1; // start of the currently parsed node
432 stack<Node* > c; // stack of nodes from which variations started
433 stack<int> c_width;
434 stack<int> c_height;
436 int height_previous = 0;
437 int width_currentVar = 0;
439 char last = ')'; // type of last parsed bracked ('(' or ')')
440 bool inbrackets = false; // are the currently parsed characters in []'s?
442 int i = 0; // current parser position
443 int lSGFstring = strlen(s);
445 int found_par = 0;
446 while (i < lSGFstring) {
447 if (s[i]=='(') {
448 found_par = i+1;
449 i++;
450 continue;
452 if (found_par && s[i]==';') break;
454 if (found_par && !(s[i]==' ' || s[i]=='\n' || s[i]=='\r' || s[i]=='\t'))
455 found_par = 0;
456 i++;
459 if (i >= lSGFstring) throw SGFError();
461 i = found_par-1; // found beginning of SGF file
463 while (i < lSGFstring) {
464 while (i < lSGFstring && !(s[i]=='(' || s[i]==')' || s[i]=='[' || s[i]==']' || s[i]==';')) i++;
465 if (i >= lSGFstring) break;
467 if (inbrackets) {
468 if (s[i]==']') {
469 int numberBackslashes = 0;
470 int j = i-1;
471 while (s[j] == '\\') {
472 numberBackslashes++;
473 j--;
475 if (!(numberBackslashes % 2))
476 inbrackets = 0;
478 i++;
479 continue;
482 if (s[i] == '[') inbrackets = 1;
484 if (s[i] == '(') {
485 if (last != ')' && p != -1) curr->SGFstring = string(s+p, i-p);
487 Node* nn = new Node(0,0,0);
488 nn->previous = curr;
490 if (++width_currentVar > width) width = width_currentVar;
491 if (curr->next) {
492 Node* last = curr->next;
493 while (last->down) last = last->down;
494 nn->up = last;
495 last->down = nn;
496 nn->level = last->level + 1;
497 height++;
498 nn->posyD = height - height_previous;
500 else {
501 curr->next = nn;
502 nn->posyD = 0;
503 height_previous = height;
506 curr->numChildren++;
508 c.push(curr);
509 c_width.push(width_currentVar-1);
510 c_height.push(height);
512 curr = nn;
514 p = -1;
515 last = '(';
518 if (s[i] == ')') {
519 if (last != ')' && p != -1) {
520 curr->SGFstring = string(s+p, i-p);
522 if (c.size()) {
523 curr = c.top();
524 c.pop();
525 width_currentVar = c_width.top();
526 c_width.pop();
527 height_previous = c_height.top();
528 c_height.pop();
530 else throw SGFError();
531 last = ')';
534 if (s[i] == ';') {
535 if (p != -1) {
536 curr->SGFstring = string(s+p, i-p);
538 Node* nn = new Node(0,0,0);
539 nn->previous = curr;
541 if (++width_currentVar > width) width = width_currentVar;
542 nn->posyD = 0;
543 curr->numChildren = 1;
544 curr->next = nn;
545 curr = nn;
547 p = i;
550 i++;
553 if (inbrackets || c.size()) throw SGFError();
555 Node* n = curr->next;
556 n->previous = NULL;
557 n->up = NULL;
559 while (n->down) {
560 n = n->down;
561 n->previous = NULL;
565 void Cursor::game(int n) throw(SGFError) {
566 if (n < root->numChildren) {
567 posx = 0;
568 posy = 0;
569 currentN = root->next;
570 for(int i=0; i<n; i++) currentN = currentN->down;
571 setFlags();
573 else throw SGFError();
576 void Cursor::deltree(Node* node) {
577 Node* n;
578 if (node->next) {
579 n = node->next;
580 while (n->down) {
581 n = n->down;
582 deltree(n->up);
584 deltree(n);
586 delete node;
589 void Cursor::delVariation(Node* c) {
590 if (c->previous) {
591 delVar(c);
593 else {
594 if (c->next) {
595 Node* node = c->next;
596 while (node->down) {
597 node = node->down;
598 delVar(node->up);
600 delVar(node);
602 c->next = 0;
605 setFlags();
608 void Cursor::delVar(Node* node) {
610 if (node->up) node->up->down = node->down;
611 else {
612 node->previous->next = node->down;
614 if (node->down) {
615 node->down->up = node->up;
616 node->down->posyD = node->posyD;
617 Node* n = node->down;
618 while (n) {
619 n->level--;
620 n = n->down;
624 int h = 0;
625 Node* n = node;
626 while (n->next) {
627 n = n->next;
628 while (n->down) {
629 n = n->down;
630 h += n->posyD;
634 if (node->up || node->down) h++;
636 Node* p = node->previous;
637 p->numChildren--;
639 while (p) {
640 if (p->down) p->down->posyD -= h;
641 p = p->previous;
644 height -= h;
646 // p = node->down;
647 deltree(node);
648 // node = 0;
652 void Cursor::add(char* st) {
654 Node* node = new Node(currentN,st,0);
656 node->down = 0;
657 node->next = 0;
658 node->numChildren = 0;
660 if (!currentN->next) {
661 // printf("new %s at %s\n", node->SGFstring, currentN->SGFstring);
662 node->level = 0;
663 node->posyD = 0;
664 node->up = 0;
666 currentN->next = node;
667 currentN->numChildren = 1;
669 else {
670 // printf("adding %s at %s\n", node->SGFstring, currentN->SGFstring);
671 Node* n = currentN->next;
672 while (n->down) {
673 n = n->down;
674 posy+=n->posyD;
677 n->down = node;
678 node->up = n;
679 node->level = n->level + 1;
680 node->next= 0;
681 currentN->numChildren++;
683 node->posyD = 1;
684 while (n->next) {
685 n = n->next;
686 while (n->down) {
687 n = n->down;
688 node->posyD += n->posyD;
691 posy += node->posyD;
693 height++;
695 n = node;
696 while (n->previous) {
697 n = n->previous;
698 if (n->down) n->down->posyD++;
703 currentN = node;
705 posx++;
706 setFlags();
708 if (posx > width) width++;
712 void Cursor::next(int n) throw(SGFError) {
714 if (n >= currentN->numChildren) {
715 throw SGFError();
717 posx++;
718 currentN = currentN->next;
719 for (int i=0; i<n; i++) {
720 currentN = currentN->down;
721 posy += currentN->posyD;
723 setFlags();
726 void Cursor::previous() throw(SGFError) {
727 if (currentN->previous) {
728 while (currentN->up) {
729 posy -= currentN->posyD;
730 currentN = currentN->up;
732 currentN = currentN->previous;
733 posx--;
735 else throw SGFError();
736 setFlags();
739 Node* Cursor::getRootNode(int n) throw(SGFError) {
740 if (!root) return 0;
742 if (n >= root->numChildren) throw SGFError();
743 Node* nn = root->next;
744 for(int i=0; i<n; i++) nn = nn->down;
746 if (!nn->parsed) nn->parseNode();
747 return nn;
751 // void Cursor::updateRootNode(PyObject* data, int n) throw(SGFError) {
752 // if (n >= root->numChildren) throw SGFError();
753 // Node* nn = root->next;
754 // for(int i=0; i<n; i++) nn = nn->down;
755 // delete[] nn->SGFstring;
756 // nn->SGFstring = rootNodeToString(data);
757 // Py_DECREF(nn->data);
758 // if (!(nn->data=PyDict_New())) throw SGFError();
759 // nn->parsed = 0;
760 // nn->parseNode();
761 // }
764 // char* Cursor::rootNodeToString(PyObject* data) {
765 // char result[10000]; // FIXME check whether this is exceeded, on the way
766 // result[0] = 0;
767 // strcat(result, ";");
769 // PyObject* item;
770 // if ((item=PyDict_GetItem(data, PyString_FromString("GM")))) {
771 // strcat(result, "GM[");
772 // char* t = SGFescape(PyString_AsString(PyList_GetItem(item, 0)));
773 // strcat(result, t);
774 // delete[] t;
775 // strcat(result, "]\n");
776 // }
777 // if ((item=PyDict_GetItem(data, PyString_FromString("FF")))) {
778 // strcat(result, "FF[");
779 // char* t = SGFescape(PyString_AsString(PyList_GetItem(item, 0)));
780 // strcat(result, t);
781 // delete[] t;
782 // strcat(result, "]\n");
783 // }
784 // if ((item=PyDict_GetItem(data, PyString_FromString("SZ")))) {
785 // strcat(result, "SZ[");
786 // char* t = SGFescape(PyString_AsString(PyList_GetItem(item, 0)));
787 // strcat(result, t);
788 // delete[] t;
789 // strcat(result, "]\n");
790 // }
791 // if ((item=PyDict_GetItem(data, PyString_FromString("PW")))) {
792 // strcat(result, "PW[");
793 // char* t = SGFescape(PyString_AsString(PyList_GetItem(item, 0)));
794 // strcat(result, t);
795 // delete[] t;
796 // strcat(result, "]\n");
797 // }
798 // if ((item=PyDict_GetItem(data, PyString_FromString("WR")))) {
799 // strcat(result, "WR[");
800 // char* t = SGFescape(PyString_AsString(PyList_GetItem(item, 0)));
801 // strcat(result, t);
802 // delete[] t;
803 // strcat(result, "]\n");
804 // }
805 // if ((item=PyDict_GetItem(data, PyString_FromString("PB")))) {
806 // strcat(result, "PB[");
807 // char* t = SGFescape(PyString_AsString(PyList_GetItem(item, 0)));
808 // strcat(result, t);
809 // delete[] t;
810 // strcat(result, "]\n");
811 // }
812 // if ((item=PyDict_GetItem(data, PyString_FromString("BR")))) {
813 // strcat(result, "BR[");
814 // char* t = SGFescape(PyString_AsString(PyList_GetItem(item, 0)));
815 // strcat(result, t);
816 // delete[] t;
817 // strcat(result, "]\n");
818 // }
819 // if ((item=PyDict_GetItem(data, PyString_FromString("EV")))) {
820 // strcat(result, "EV[");
821 // char* t = SGFescape(PyString_AsString(PyList_GetItem(item, 0)));
822 // strcat(result, t);
823 // delete[] t;
824 // strcat(result, "]\n");
825 // }
826 // if ((item=PyDict_GetItem(data, PyString_FromString("RO")))) {
827 // strcat(result, "RO[");
828 // char* t = SGFescape(PyString_AsString(PyList_GetItem(item, 0)));
829 // strcat(result, t);
830 // delete[] t;
831 // strcat(result, "]\n");
832 // }
833 // if ((item=PyDict_GetItem(data, PyString_FromString("DT")))) {
834 // strcat(result, "DT[");
835 // char* t = SGFescape(PyString_AsString(PyList_GetItem(item, 0)));
836 // strcat(result, t);
837 // delete[] t;
838 // strcat(result, "]\n");
839 // }
840 // if ((item=PyDict_GetItem(data, PyString_FromString("PC")))) {
841 // strcat(result, "PC[");
842 // char* t = SGFescape(PyString_AsString(PyList_GetItem(item, 0)));
843 // strcat(result, t);
844 // delete[] t;
845 // strcat(result, "]\n");
846 // }
847 // if ((item=PyDict_GetItem(data, PyString_FromString("KM")))) {
848 // strcat(result, "KM[");
849 // char* t = SGFescape(PyString_AsString(PyList_GetItem(item, 0)));
850 // strcat(result, t);
851 // delete[] t;
852 // strcat(result, "]\n");
853 // }
854 // if ((item=PyDict_GetItem(data, PyString_FromString("RE")))) {
855 // strcat(result, "RE[");
856 // char* t = SGFescape(PyString_AsString(PyList_GetItem(item, 0)));
857 // strcat(result, t);
858 // delete[] t;
859 // strcat(result, "]\n");
860 // }
861 // if ((item=PyDict_GetItem(data, PyString_FromString("US")))) {
862 // strcat(result, "US[");
863 // char* t = SGFescape(PyString_AsString(PyList_GetItem(item, 0)));
864 // strcat(result, t);
865 // delete[] t;
866 // strcat(result, "]\n");
867 // }
868 // if ((item=PyDict_GetItem(data, PyString_FromString("GC")))) {
869 // strcat(result, "GC[");
870 // char* t = SGFescape(PyString_AsString(PyList_GetItem(item, 0)));
871 // strcat(result, t);
872 // delete[] t;
873 // strcat(result, "]\n");
874 // }
876 // int l = 0;
878 // PyObject *key, *value;
879 // int pos = 0;
881 // while (PyDict_Next(data, &pos, &key, &value)) {
882 // char* s = PyString_AsString(key);
883 // if (strcmp(s, "GM") && strcmp(s, "FF") && strcmp(s, "SZ") && strcmp(s, "PW") && strcmp(s, "WR") &&
884 // strcmp(s, "PB") && strcmp(s, "BR") && strcmp(s, "EV") && strcmp(s, "RO") && strcmp(s, "DT") &&
885 // strcmp(s, "PC") && strcmp(s, "KM") && strcmp(s, "RE") && strcmp(s, "US") && strcmp(s, "GC")) {
887 // strcat(result, s);
889 // for(int k = 0; k < PyList_Size(value); k++) {
890 // PyObject* item = PyList_GetItem(value, k);
891 // char* t = SGFescape(PyString_AsString(item));
892 // strcat(result, "[");
893 // strcat(result, t);
894 // strcat(result, "]");
895 // l += strlen(t) + 2;
896 // delete[] t;
897 // if (l>72) {
898 // strcat(result, "\n");
899 // l = 0;
900 // }
901 // }
902 // }
903 // }
904 // strcat(result, "\n");
905 // char* t = new char[strlen(result)+1];
906 // strcpy(t, result);
907 // return t;
908 // }
910 string nodeToString(map<string, PropValue >& data) throw(SGFError) {
911 string result = ";";
912 int l = 0;
913 for(map<string, PropValue >::iterator kv = data.begin(); kv != data.end(); kv++) {
914 if (!kv->second.pv || !kv->second.pv->size()) continue;
916 result += kv->second.IDcomplete;
917 for(vector<string>::iterator it = kv->second.pv->begin(); it != kv->second.pv->end(); it++) {
918 char* t = SGFescape(it->c_str());
919 result += "[";
920 result += t;
921 result += "]";
922 l += strlen(t) + 2;
923 delete [] t;
924 if (l>72) {
925 result += '\n';
926 l = 0;
930 result += '\n';
931 return result;
935 char* Cursor::outputVar(Node* node) {
936 int s = 1000;
937 char* result = new char[s];
938 result[0] = 0;
940 if ((int)(node->SGFstring.size() + strlen(result)) >= s-5) {
941 s += 1000 + node->SGFstring.size();
942 char* res = new char[s];
943 strcpy(res, result);
944 delete [] result;
945 result = res;
948 strcat(result, node->SGFstring.c_str());
949 // printf("%s\n", node->SGFstring);
951 while (node->next) {
952 node = node->next;
953 if (node->down) {
954 strcat(result, "(");
956 char* r = outputVar(node);
958 if ((int)(strlen(r) + strlen(result)) >= s-5) {
959 s += 1000 + strlen(r);
960 char* res = new char[s];
961 strcpy(res, result);
962 delete [] result;
963 result = res;
966 strcat(result, r);
967 delete [] r;
969 while(node->down) {
970 node = node->down;
971 strcat(result, ")(");
973 char* r = outputVar(node);
975 if ((int)(strlen(r) + strlen(result)) >= s-5) {
976 s += 1000 + strlen(r);
977 char* res = new char[s];
978 strcpy(res, result);
979 delete [] result;
980 result = res;
983 strcat(result, r);
984 delete [] r;
986 strcat(result, ")");
987 break;
989 else {
990 if ((int)(node->SGFstring.size() + strlen(result)) >= s) {
991 s += 1000 + node->SGFstring.size();
992 char* res = new char[s];
993 strcpy(res, result);
994 delete [] result;
995 result = res;
997 strcat(result, node->SGFstring.c_str());
998 // printf("%s\n", node->SGFstring);
1002 // printf("r: %d \n", strlen(result));
1004 char* t = new char[strlen(result)+1];
1005 strcpy(t, result);
1007 delete [] result;
1008 return t;
1012 char* Cursor::output() {
1014 int s = 2000;
1015 char* result = new char[s];
1016 result[0] = 0;
1018 Node* n = root->next;
1020 while (n) {
1021 char* t = outputVar(n);
1023 if ((int)(strlen(t) + strlen(result)) >= s-5) {
1024 s += 2000 + strlen(t);
1025 char* res = new char[s];
1026 strcpy(res, result);
1027 delete [] result;
1028 result = res;
1031 strcat(result, "(");
1032 strcat(result, t);
1033 strcat(result, ")\n");
1034 delete [] t;
1035 n = n->down;
1038 char* t = new char[strlen(result)+1];
1039 strcpy(t, result);
1040 delete [] result;
1041 return t;