PageRenderTime 54ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/lk/sgfparser.cpp

https://bitbucket.org/ugoertz/kombilo
C++ | 917 lines | 723 code | 164 blank | 30 comment | 299 complexity | 3881a9ce59c09c113c519198365922ba MD5 | raw file
  1. // File: sgfparser.cpp
  2. // part of libkombilo, http://www.u-go.net/kombilo/
  3. // Copyright (c) 2006-12 Ulrich Goertz <ug@geometry.de>
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy of
  5. // this software and associated documentation files (the "Software"), to deal in
  6. // the Software without restriction, including without limitation the rights to
  7. // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
  8. // of the Software, and to permit persons to whom the Software is furnished to do
  9. // so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in all
  12. // copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  20. // SOFTWARE.
  21. #include <string.h>
  22. #include <iostream>
  23. #include "sgfparser.h"
  24. using std::vector;
  25. using std::stack;
  26. using std::pair;
  27. using std::map;
  28. using std::string;
  29. SGFError::SGFError() {}
  30. ExtendedMoveNumber::ExtendedMoveNumber() {
  31. length = 0;
  32. data = 0;
  33. }
  34. ExtendedMoveNumber::ExtendedMoveNumber(int LENGTH, int* DATA) {
  35. length = LENGTH;
  36. if (length) data = new int[length];
  37. else data = 0;
  38. for(int i=0; i<length; i++) data[i] = DATA[i];
  39. }
  40. ExtendedMoveNumber::ExtendedMoveNumber(int D) {
  41. length = 1;
  42. data = new int[1];
  43. data[0] = D;
  44. }
  45. ExtendedMoveNumber::ExtendedMoveNumber(const ExtendedMoveNumber& emn) {
  46. length = emn.length;
  47. if (length) data = new int[length];
  48. else data = 0;
  49. for(int i=0; i<length; i++) data[i] = emn.data[i];
  50. }
  51. ExtendedMoveNumber::~ExtendedMoveNumber() {
  52. if (data) delete [] data;
  53. }
  54. ExtendedMoveNumber& ExtendedMoveNumber::operator=(const ExtendedMoveNumber& emn) {
  55. if (this != &emn) {
  56. length = emn.length;
  57. if (data) delete [] data;
  58. if (length) {
  59. data = new int[length];
  60. for(int i=0; i<length; i++) data[i] = emn.data[i];
  61. } else data = 0;
  62. }
  63. return *this;
  64. }
  65. void ExtendedMoveNumber::next() {
  66. data[length-1]++;
  67. }
  68. void ExtendedMoveNumber::down() throw(SGFError) {
  69. if (length==0) throw SGFError();
  70. else if (length==1) {
  71. int* newdata = new int[3];
  72. newdata[0] = data[0];
  73. newdata[1] = 1;
  74. newdata[2] = 0;
  75. length = 3;
  76. delete [] data;
  77. data = newdata;
  78. } else {
  79. if (data[length-1]) {
  80. int* newdata = new int[length+2];
  81. for(int i=0; i<length; i++) newdata[i] = data[i];
  82. newdata[length] = 1;
  83. newdata[length+1] = 0;
  84. length += 2;
  85. delete [] data;
  86. data = newdata;
  87. } else data[length-2]++;
  88. }
  89. }
  90. int ExtendedMoveNumber::total_move_num() {
  91. int result = 0;
  92. for(int i=0; i<(length+1)/2; i++) result += data[2*i];
  93. return result;
  94. }
  95. char* SGFescape(const char* s) {
  96. char* t = new char[2*strlen(s)+1];
  97. int j = 0;
  98. for(unsigned int i = 0; i<strlen(s); i++) {
  99. if (s[i] == '\\' || s[i] == ']') t[j++]='\\';
  100. t[j++] = s[i];
  101. }
  102. t[j++] = 0;
  103. char* result = new char[j];
  104. strcpy(result, t);
  105. delete [] t;
  106. return result;
  107. }
  108. vector<string>* parseRootNode(Node* n, vector<string>* tags) throw(SGFError) {
  109. vector<string>* results = new vector<string>(tags->size());
  110. string s = n->SGFstring;
  111. int lSGFstring = s.size();
  112. int i = 0;
  113. while (i < lSGFstring && s[i] != ';' && (s[i]==' ' || s[i]=='\n' || s[i]=='\r' || s[i]=='\t'))
  114. i++;
  115. if (i>=lSGFstring || s[i] != ';') throw SGFError();
  116. i++;
  117. while (i < lSGFstring) {
  118. while (i < lSGFstring && (s[i]==' ' || s[i]=='\n' || s[i]=='\r' || s[i]=='\t'))
  119. i++;
  120. if (i >= lSGFstring) break;
  121. char ID[30];
  122. int IDindex = 0;
  123. while (i < lSGFstring && s[i] != '[' && IDindex < 30) {
  124. if (65 <= s[i] && s[i] <= 90) {
  125. ID[IDindex++] = s[i];
  126. } else if (!(97 <= s[i] && s[i] <= 122) && (!(s[i]==' ' || s[i]=='\n' || s[i]=='\r' || s[i]=='\t'))) {
  127. throw SGFError();
  128. }
  129. i++;
  130. }
  131. i++;
  132. if (i >= lSGFstring || IDindex >= 30 || !IDindex) {
  133. throw SGFError();
  134. }
  135. ID[IDindex] = 0;
  136. char* propValue = new char[lSGFstring+1];
  137. int propValueIndex = 0;
  138. while (i < lSGFstring) {
  139. while (s[i] != ']') {
  140. if (s[i] == '\t') {
  141. propValue[propValueIndex++] = ' ';
  142. i++;
  143. continue;
  144. }
  145. if (s[i] == '\\') {
  146. i++;
  147. if ((s[i]=='\n' && s[i+1]=='\r') || (s[i]=='\r' && s[i+1]=='\n')) {
  148. i += 2;
  149. continue;
  150. }
  151. else if (s[i]=='\n' || s[i]=='\r') {
  152. i++;
  153. continue;
  154. }
  155. }
  156. propValue[propValueIndex++] = s[i];
  157. i++;
  158. if (i >= lSGFstring) {
  159. throw SGFError();
  160. }
  161. }
  162. propValue[propValueIndex++] = ',';
  163. propValue[propValueIndex++] = ' ';
  164. i++;
  165. while (i < lSGFstring && (s[i]==' ' || s[i]=='\n' || s[i]=='\r' || s[i]=='\t'))
  166. i++;
  167. if (i >= lSGFstring || s[i] != '[') {
  168. propValue[propValueIndex-2] = 0;
  169. string IDstring = ID;
  170. int ctr = 0;
  171. for(vector<string>::iterator it = tags->begin(); it != tags->end(); it++) {
  172. if (IDstring == *it) {
  173. (*results)[ctr] = propValue;
  174. break;
  175. }
  176. ctr++;
  177. }
  178. delete [] propValue;
  179. break;
  180. }
  181. else i++;
  182. }
  183. }
  184. return results;
  185. }
  186. PropValue::PropValue(std::string IDC, std::vector<std::string>* PV) {
  187. IDcomplete = IDC;
  188. pv = PV;
  189. }
  190. PropValue::PropValue(const PropValue& pval) {
  191. IDcomplete = pval.IDcomplete;
  192. pv = new vector<string>(*pval.pv);
  193. }
  194. PropValue::~PropValue() {
  195. if (pv) delete pv;
  196. }
  197. Node::Node(Node* prev, char* SGFst) throw(SGFError) {
  198. next = NULL;
  199. previous = prev;
  200. up = NULL;
  201. down = NULL;
  202. numChildren = 0;
  203. level = 0;
  204. parsed = 0;
  205. if (SGFst) {
  206. SGFstring = SGFst;
  207. // parseNode();
  208. } else SGFstring = "";
  209. posyD = 0;
  210. }
  211. Node::~Node() {
  212. }
  213. string remove_lowercase(string s) throw(SGFError) {
  214. vector<char> ID;
  215. for(unsigned int i=0; i<s.size(); i++) {
  216. if (65 <= s[i] && s[i] <= 90) ID.push_back(s[i]);
  217. else if (!(97 <= s[i] && s[i] <= 122)) {
  218. throw SGFError();
  219. }
  220. }
  221. return string(ID.begin(), ID.end());
  222. }
  223. vector<string> Node::gpv(const string& prop) {
  224. vector<string>* result = get_property_value(prop);
  225. if (result) return *result;
  226. else return vector<string>();
  227. }
  228. vector<string>* Node::get_property_value(const string& prop) {
  229. if (!parsed) {
  230. parseNode();
  231. }
  232. map<string, PropValue >::iterator result = data.find(remove_lowercase(prop));
  233. if (result == data.end()) return 0;
  234. else return result->second.pv;
  235. }
  236. ExtendedMoveNumber Node::get_move_number() {
  237. vector<int> l;
  238. Node* n = this;
  239. l.push_back(0);
  240. while (n->previous) {
  241. if (n->level) l.push_back(n->level);
  242. else l[l.size()-1]++;
  243. n = n->previous;
  244. }
  245. int* result = new int[l.size()];
  246. for(int i = l.size()-1; i >= 0; i--) {
  247. result[l.size()-i-1] = l[i];
  248. }
  249. ExtendedMoveNumber emn(l.size(), result);
  250. delete [] result;
  251. return emn;
  252. }
  253. void Node::parseNode() throw(SGFError) {
  254. // printf("Parse node, %s\n", SGFstring.c_str());
  255. if (!parsed) {
  256. string s = SGFstring;
  257. int lSGFstring = s.size();
  258. int i = 0;
  259. while (i < lSGFstring && s[i] != ';' && (s[i]==' ' || s[i]=='\n' || s[i]=='\r' || s[i]=='\t'))
  260. i++;
  261. if (i>=lSGFstring || s[i] != ';') throw SGFError();
  262. i++;
  263. while (i < lSGFstring) {
  264. while (i < lSGFstring && (s[i]==' ' || s[i]=='\n' || s[i]=='\r' || s[i]=='\t'))
  265. i++;
  266. if (i >= lSGFstring) break;
  267. char ID[30];
  268. int IDindex = 0;
  269. char IDcomplete[100]; // store long property name here
  270. int IDcompleteIndex = 0;
  271. while (i < lSGFstring && s[i] != '[' && IDindex < 30 && IDcompleteIndex < 100) {
  272. if (65 <= s[i] && s[i] <= 90) {
  273. ID[IDindex++] = s[i];
  274. IDcomplete[IDcompleteIndex++] = s[i];
  275. } else if (97 <= s[i] && s[i] <= 122) {
  276. IDcomplete[IDcompleteIndex++] = s[i];
  277. } else if (!(s[i]==' ' || s[i]=='\n' || s[i]=='\r' || s[i]=='\t')) {
  278. throw SGFError();
  279. }
  280. i++;
  281. }
  282. i++;
  283. if (i >= lSGFstring || IDindex >= 30 || !IDindex || IDcompleteIndex >= 100) {
  284. throw SGFError();
  285. }
  286. ID[IDindex] = 0;
  287. IDcomplete[IDcompleteIndex] = 0;
  288. vector<string>* propValueList = new vector<string>;
  289. while (i < lSGFstring) {
  290. string propValue;
  291. while (s[i] != ']') {
  292. //printf("i, s[i]: %d, %c\n", i, s[i]);
  293. if (s[i] == '\t') {
  294. propValue += ' ';
  295. i++;
  296. continue;
  297. }
  298. if (s[i] == '\\') {
  299. i++;
  300. if ((s[i]=='\n' && s[i+1]=='\r') || (s[i]=='\r' && s[i+1]=='\n')) {
  301. i += 2;
  302. continue;
  303. }
  304. else if (s[i]=='\n' || s[i]=='\r') {
  305. i++;
  306. continue;
  307. }
  308. }
  309. if (Node::sloppy && (s[i] == '\n' || s[i] == '\r') && \
  310. (!strcmp(ID, "B") || !strcmp(ID, "W") || !strcmp(ID, "AW") || !strcmp(ID, "AB"))) {
  311. i++;
  312. continue;
  313. }
  314. propValue += s[i]; // building propValue in this way could be a performance problem
  315. i++;
  316. if (i >= lSGFstring) throw SGFError();
  317. }
  318. if ((!strcmp(ID,"B") || !strcmp(ID,"W")) && !(propValue.size() == 2 || (propValue.size() == 0))) {
  319. throw SGFError();
  320. }
  321. propValueList->push_back(propValue);
  322. i++;
  323. while (i < lSGFstring && (s[i]==' ' || s[i]=='\n' || s[i]=='\r' || s[i]=='\t'))
  324. i++;
  325. if (i >= lSGFstring || s[i] != '[') break;
  326. else i++;
  327. }
  328. data.insert(make_pair(string(ID), PropValue(string(IDcomplete), propValueList))); // this calls the PropValue copy constructor twice! can't we improve on that?
  329. }
  330. parsed = 1;
  331. }
  332. }
  333. void Node::del_property_value(const string& IDcomplete) throw(SGFError) {
  334. if (!parsed) parseNode();
  335. string ID = remove_lowercase(IDcomplete);
  336. data.erase(ID);
  337. SGFstring = nodeToString(data);
  338. }
  339. void Node::set_property_value(const string& IDcomplete, vector<string> propValue) throw(SGFError) {
  340. if (!parsed) parseNode();
  341. string ID = remove_lowercase(IDcomplete);
  342. data.erase(ID);
  343. data.insert(make_pair(ID, PropValue(IDcomplete, new vector<string>(propValue))));
  344. SGFstring = nodeToString(data);
  345. }
  346. void Node::add_property_value(const string& IDcomplete, vector<string> propValue) throw(SGFError) {
  347. if (!parsed) parseNode();
  348. string ID = remove_lowercase(IDcomplete);
  349. map<string, PropValue >::iterator it = data.find(ID);
  350. if (it == data.end()) data.insert(make_pair(ID, PropValue(IDcomplete, new vector<string>(propValue))));
  351. else it->second.pv->insert(it->second.pv->end(), propValue.begin(), propValue.end());
  352. SGFstring = nodeToString(data);
  353. }
  354. vector<string> Node::keys() {
  355. vector<string> result;
  356. for(map<string, PropValue>::iterator it = data.begin(); it != data.end(); it++)
  357. result.push_back(it->first);
  358. return result;
  359. }
  360. int Node::sloppy = 1;
  361. Cursor::Cursor(const char* sgf, int sloppy) throw(SGFError) {
  362. Node::sloppy = sloppy;
  363. height = 0;
  364. width = 0;
  365. posx = 0;
  366. posy = 0;
  367. root = new Node(NULL, NULL);
  368. parse(sgf);
  369. currentN = root->next;
  370. setFlags();
  371. }
  372. Cursor::~Cursor() {
  373. deltree(root);
  374. }
  375. void Cursor::setFlags() {
  376. if (currentN->next) atEnd = 0;
  377. else atEnd = 1;
  378. if (currentN->previous) atStart = 0;
  379. else atStart = 1;
  380. }
  381. void Cursor::parse(const char* s) throw(SGFError) {
  382. Node* curr = root;
  383. int p = -1; // start of the currently parsed node
  384. stack<Node* > c; // stack of nodes from which variations started
  385. stack<int> c_width;
  386. stack<int> c_height;
  387. int height_previous = 0;
  388. int width_currentVar = 0;
  389. char last = ')'; // type of last parsed bracked ('(' or ')')
  390. bool inbrackets = false; // are the currently parsed characters in []'s?
  391. int i = 0; // current parser position
  392. int lSGFstring = strlen(s);
  393. int found_par = 0;
  394. while (i < lSGFstring) {
  395. if (s[i]=='(') {
  396. found_par = i+1;
  397. i++;
  398. continue;
  399. }
  400. if (found_par && s[i]==';') break;
  401. if (found_par && !(s[i]==' ' || s[i]=='\n' || s[i]=='\r' || s[i]=='\t'))
  402. found_par = 0;
  403. i++;
  404. }
  405. if (i >= lSGFstring) throw SGFError();
  406. i = found_par-1; // found beginning of SGF file
  407. while (i < lSGFstring) {
  408. while (i < lSGFstring && !(s[i]=='(' || s[i]==')' || s[i]=='[' || s[i]==']' || s[i]==';')) i++;
  409. if (i >= lSGFstring) break;
  410. if (inbrackets) {
  411. if (s[i]==']') {
  412. int numberBackslashes = 0;
  413. int j = i-1;
  414. while (s[j] == '\\') {
  415. numberBackslashes++;
  416. j--;
  417. }
  418. if (!(numberBackslashes % 2))
  419. inbrackets = 0;
  420. }
  421. i++;
  422. continue;
  423. }
  424. if (s[i] == '[') inbrackets = 1;
  425. if (s[i] == '(') {
  426. if (last != ')' && p != -1) curr->SGFstring = string(s+p, i-p);
  427. Node* nn = new Node(0,0);
  428. nn->previous = curr;
  429. if (++width_currentVar > width) width = width_currentVar;
  430. if (curr->next) {
  431. Node* last = curr->next;
  432. while (last->down) last = last->down;
  433. nn->up = last;
  434. last->down = nn;
  435. nn->level = last->level + 1;
  436. height++;
  437. nn->posyD = height - height_previous;
  438. }
  439. else {
  440. curr->next = nn;
  441. nn->posyD = 0;
  442. height_previous = height;
  443. }
  444. curr->numChildren++;
  445. c.push(curr);
  446. c_width.push(width_currentVar-1);
  447. c_height.push(height);
  448. curr = nn;
  449. p = -1;
  450. last = '(';
  451. }
  452. if (s[i] == ')') {
  453. if (last != ')' && p != -1) {
  454. curr->SGFstring = string(s+p, i-p);
  455. }
  456. if (c.size()) {
  457. curr = c.top();
  458. c.pop();
  459. width_currentVar = c_width.top();
  460. c_width.pop();
  461. height_previous = c_height.top();
  462. c_height.pop();
  463. }
  464. else throw SGFError();
  465. last = ')';
  466. }
  467. if (s[i] == ';') {
  468. if (p != -1) {
  469. curr->SGFstring = string(s+p, i-p);
  470. Node* nn = new Node(0,0);
  471. nn->previous = curr;
  472. if (++width_currentVar > width) width = width_currentVar;
  473. nn->posyD = 0;
  474. curr->numChildren = 1;
  475. curr->next = nn;
  476. curr = nn;
  477. }
  478. p = i;
  479. }
  480. i++;
  481. }
  482. if (inbrackets || c.size() || curr->next == NULL) throw SGFError();
  483. Node* n = curr->next;
  484. n->previous = NULL;
  485. n->up = NULL;
  486. while (n->down) {
  487. n = n->down;
  488. n->previous = NULL;
  489. }
  490. }
  491. void Cursor::game(int n) throw(SGFError) {
  492. if (n < root->numChildren) {
  493. posx = 0;
  494. posy = 0;
  495. currentN = root->next;
  496. for(int i=0; i<n; i++) currentN = currentN->down;
  497. setFlags();
  498. }
  499. else throw SGFError();
  500. }
  501. void Cursor::deltree(Node* node) {
  502. Node* n;
  503. if (node->next) {
  504. n = node->next;
  505. while (n->down) {
  506. n = n->down;
  507. deltree(n->up);
  508. }
  509. deltree(n);
  510. }
  511. delete node;
  512. }
  513. void Cursor::delVariation(Node* c) {
  514. if (c->previous) {
  515. delVar(c);
  516. }
  517. else {
  518. if (c->next) {
  519. Node* node = c->next;
  520. while (node->down) {
  521. node = node->down;
  522. delVar(node->up);
  523. }
  524. delVar(node);
  525. }
  526. c->next = 0;
  527. }
  528. setFlags();
  529. }
  530. void Cursor::delVar(Node* node) {
  531. if (node->up) node->up->down = node->down;
  532. else {
  533. node->previous->next = node->down;
  534. }
  535. if (node->down) {
  536. node->down->up = node->up;
  537. node->down->posyD = node->posyD;
  538. Node* n = node->down;
  539. while (n) {
  540. n->level--;
  541. n = n->down;
  542. }
  543. }
  544. int h = 0;
  545. Node* n = node;
  546. while (n->next) {
  547. n = n->next;
  548. while (n->down) {
  549. n = n->down;
  550. h += n->posyD;
  551. }
  552. }
  553. if (node->up || node->down) h++;
  554. Node* p = node->previous;
  555. p->numChildren--;
  556. while (p) {
  557. if (p->down) p->down->posyD -= h;
  558. p = p->previous;
  559. }
  560. height -= h;
  561. // p = node->down;
  562. deltree(node);
  563. // node = 0;
  564. }
  565. void Cursor::add(char* st) {
  566. Node* node = new Node(currentN,st);
  567. node->down = 0;
  568. node->next = 0;
  569. node->numChildren = 0;
  570. if (!currentN->next) {
  571. // printf("new %s at %s\n", node->SGFstring, currentN->SGFstring);
  572. node->level = 0;
  573. node->posyD = 0;
  574. node->up = 0;
  575. currentN->next = node;
  576. currentN->numChildren = 1;
  577. } else {
  578. // printf("adding %s at %s\n", node->SGFstring, currentN->SGFstring);
  579. Node* n = currentN->next;
  580. while (n->down) {
  581. n = n->down;
  582. posy+=n->posyD;
  583. }
  584. n->down = node;
  585. node->up = n;
  586. node->level = n->level + 1;
  587. node->next= 0;
  588. currentN->numChildren++;
  589. node->posyD = 1;
  590. while (n->next) {
  591. n = n->next;
  592. while (n->down) {
  593. n = n->down;
  594. node->posyD += n->posyD;
  595. }
  596. }
  597. posy += node->posyD;
  598. height++;
  599. n = node;
  600. while (n->previous) {
  601. n = n->previous;
  602. if (n->down) n->down->posyD++;
  603. }
  604. }
  605. currentN = node;
  606. posx++;
  607. setFlags();
  608. if (posx > width) width++;
  609. }
  610. Node* Cursor::next(int n) throw(SGFError) {
  611. if (n >= currentN->numChildren) {
  612. throw SGFError();
  613. }
  614. posx++;
  615. currentN = currentN->next;
  616. for (int i=0; i<n; i++) {
  617. currentN = currentN->down;
  618. posy += currentN->posyD;
  619. }
  620. setFlags();
  621. return currentN;
  622. }
  623. Node* Cursor::previous() throw(SGFError) {
  624. if (currentN->previous) {
  625. while (currentN->up) {
  626. posy -= currentN->posyD;
  627. currentN = currentN->up;
  628. }
  629. currentN = currentN->previous;
  630. posx--;
  631. }
  632. else throw SGFError();
  633. setFlags();
  634. return currentN;
  635. }
  636. Node* Cursor::getRootNode(int n) throw(SGFError) {
  637. if (!root) return 0;
  638. if (n >= root->numChildren) throw SGFError();
  639. Node* nn = root->next;
  640. for(int i=0; i<n; i++) nn = nn->down;
  641. if (!nn->parsed) nn->parseNode();
  642. return nn;
  643. }
  644. string nodeToString(map<string, PropValue >& data) throw(SGFError) {
  645. string result = ";";
  646. int l = 0;
  647. for(map<string, PropValue >::iterator kv = data.begin(); kv != data.end(); kv++) {
  648. if (!kv->second.pv) continue;
  649. result += kv->second.IDcomplete;
  650. if (!kv->second.pv->size()) result += "[]";
  651. for(vector<string>::iterator it = kv->second.pv->begin(); it != kv->second.pv->end(); it++) {
  652. char* t = SGFescape(it->c_str());
  653. result += "[";
  654. result += t;
  655. result += "]";
  656. l += strlen(t) + 2;
  657. delete [] t;
  658. if (l>72) {
  659. result += '\n';
  660. l = 0;
  661. }
  662. }
  663. }
  664. result += '\n';
  665. return result;
  666. }
  667. char* Cursor::outputVar(Node* node) {
  668. int s = 1000;
  669. char* result = new char[s];
  670. result[0] = 0;
  671. if ((int)(node->SGFstring.size() + strlen(result)) >= s-5) {
  672. s += 1000 + node->SGFstring.size();
  673. char* res = new char[s];
  674. strcpy(res, result);
  675. delete [] result;
  676. result = res;
  677. }
  678. strcat(result, node->SGFstring.c_str());
  679. // printf("%s\n", node->SGFstring);
  680. while (node->next) {
  681. node = node->next;
  682. if (node->down) {
  683. strcat(result, "(");
  684. char* r = outputVar(node);
  685. if ((int)(strlen(r) + strlen(result)) >= s-5) {
  686. s += 1000 + strlen(r);
  687. char* res = new char[s];
  688. strcpy(res, result);
  689. delete [] result;
  690. result = res;
  691. }
  692. strcat(result, r);
  693. delete [] r;
  694. while(node->down) {
  695. node = node->down;
  696. strcat(result, ")(");
  697. char* r = outputVar(node);
  698. if ((int)(strlen(r) + strlen(result)) >= s-5) {
  699. s += 1000 + strlen(r);
  700. char* res = new char[s];
  701. strcpy(res, result);
  702. delete [] result;
  703. result = res;
  704. }
  705. strcat(result, r);
  706. delete [] r;
  707. }
  708. strcat(result, ")");
  709. break;
  710. }
  711. else {
  712. if ((int)(node->SGFstring.size() + strlen(result)) >= s) {
  713. s += 1000 + node->SGFstring.size();
  714. char* res = new char[s];
  715. strcpy(res, result);
  716. delete [] result;
  717. result = res;
  718. }
  719. strcat(result, node->SGFstring.c_str());
  720. // printf("%s\n", node->SGFstring);
  721. }
  722. }
  723. // printf("r: %d \n", strlen(result));
  724. char* t = new char[strlen(result)+1];
  725. strcpy(t, result);
  726. delete [] result;
  727. return t;
  728. }
  729. char* Cursor::output() {
  730. int s = 2000;
  731. char* result = new char[s];
  732. result[0] = 0;
  733. Node* n = root->next;
  734. while (n) {
  735. char* t = outputVar(n);
  736. if ((int)(strlen(t) + strlen(result)) >= s-5) {
  737. s += 2000 + strlen(t);
  738. char* res = new char[s];
  739. strcpy(res, result);
  740. delete [] result;
  741. result = res;
  742. }
  743. strcat(result, "(");
  744. strcat(result, t);
  745. strcat(result, ")\n");
  746. delete [] t;
  747. n = n->down;
  748. }
  749. char* t = new char[strlen(result)+1];
  750. strcpy(t, result);
  751. delete [] result;
  752. return t;
  753. }