PageRenderTime 76ms CodeModel.GetById 2ms app.highlight 66ms RepoModel.GetById 1ms app.codeStats 0ms

/kombilo/sgfparser.cpp

https://github.com/eped/eidogo
C++ | 1044 lines | 698 code | 159 blank | 187 comment | 292 complexity | 2b876c2068c2e7719a1c43604c261a3a MD5 | raw file
   1// File: sgfparser.cpp
   2// part of libkombilo, http://www.u-go.net/kombilo/
   3
   4// Copyright (c) 2006-7 Ulrich Goertz <u@g0ertz.de>
   5
   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.
  23
  24#include "sgfparser.h"
  25
  26using std::vector;
  27using std::stack;
  28using std::pair;
  29using std::map;
  30using std::string;
  31
  32SGFError::SGFError() {}
  33
  34ExtendedMoveNumber::ExtendedMoveNumber() {
  35  length = 0;
  36  data = 0;
  37}
  38
  39ExtendedMoveNumber::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];
  44}
  45
  46ExtendedMoveNumber::ExtendedMoveNumber(int D) {
  47  length = 1;
  48  data = new int[1];
  49  data[0] = D;
  50}
  51
  52ExtendedMoveNumber::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];
  57}
  58
  59ExtendedMoveNumber::~ExtendedMoveNumber() {
  60  if (data) delete [] data;
  61}
  62
  63ExtendedMoveNumber& 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;
  71  }
  72  return *this;
  73}
  74
  75void ExtendedMoveNumber::next() {
  76  data[length-1]++;
  77}
  78
  79void 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]++;
  99  }
 100}
 101
 102int 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;
 106}
 107
 108char* 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];
 114  }
 115           
 116  t[j++] = 0;
 117
 118  char* result = new char[j];
 119  strcpy(result, t);
 120  delete t;
 121  return result;
 122}
 123
 124vector<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;
 129
 130  while (i < lSGFstring && s[i] != ';' && (s[i]==' ' || s[i]=='\n' || s[i]=='\r' || s[i]=='\t')) 
 131    i++;
 132
 133  if (i>=lSGFstring || s[i] != ';') throw SGFError();
 134  i++;
 135
 136  while (i < lSGFstring) {
 137    while (i < lSGFstring && (s[i]==' ' || s[i]=='\n' || s[i]=='\r' || s[i]=='\t')) 
 138      i++;
 139
 140    if (i >= lSGFstring) break;
 141
 142    char ID[30];
 143    int IDindex = 0;
 144
 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();
 150      }
 151      i++;
 152    }
 153    i++;
 154
 155    if (i >= lSGFstring || IDindex >= 30 || !IDindex) {
 156      throw SGFError();
 157    }
 158    ID[IDindex] = 0;
 159
 160    char* propValue = new char[lSGFstring+1];
 161    int propValueIndex = 0;
 162
 163    while (i < lSGFstring) {
 164
 165      while (s[i] != ']') {
 166        if (s[i] == '\t') {
 167          propValue[propValueIndex++] = ' ';
 168          i++;
 169          continue;
 170        }
 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;
 176          }
 177          else if (s[i]=='\n' || s[i]=='\r') {
 178            i++;
 179            continue;
 180          }
 181        }
 182        propValue[propValueIndex++] = s[i];
 183        i++;
 184
 185        if (i >= lSGFstring) {
 186          throw SGFError();
 187        }
 188      }
 189
 190      propValue[propValueIndex++] = ',';
 191      propValue[propValueIndex++] = ' ';
 192
 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;
 204          }
 205          ctr++;
 206        }
 207        delete [] propValue;
 208        break;
 209      }
 210      else i++;
 211    }
 212  }
 213  return results;
 214}
 215
 216PropValue::PropValue(std::string IDC, std::vector<std::string>* PV) {
 217  IDcomplete = IDC;
 218  pv = PV;
 219}
 220
 221PropValue::~PropValue() {
 222  if (pv) delete pv;
 223}
 224
 225
 226Node::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;
 234
 235  if (SGFst) {
 236    SGFstring = SGFst;
 237    // parseNode();
 238  } else SGFstring = "";
 239  posyD = 0;
 240}
 241        
 242Node::~Node() {
 243}
 244
 245string 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();
 252    }
 253  }
 254  ID[IDindex] = 0;
 255  return string(ID);
 256}
 257
 258vector<string> Node::gpv(const string& prop) {
 259  vector<string>* result = get_property_value(prop);
 260  if (result) return *result;
 261  else return vector<string>();
 262}
 263
 264vector<string>* Node::get_property_value(const string& prop) {
 265  if (!parsed) {
 266    parseNode();
 267  }
 268  map<string, PropValue >::iterator result = data.find(remove_lowercase(prop));
 269  if (result == data.end()) return 0;
 270  else return result->second.pv;
 271}
 272
 273ExtendedMoveNumber Node::get_move_number() {
 274  vector<int> l;
 275  Node* n = this;
 276  l.push_back(0);
 277
 278  while (n->previous) {
 279    if (n->level) l.push_back(n->level);
 280    else l[l.size()-1]++;
 281    n = n->previous;
 282  }        
 283
 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];
 287  }
 288  ExtendedMoveNumber emn(l.size(), result);
 289  delete [] result;
 290  return emn;
 291}
 292
 293
 294void 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;
 300
 301    while (i < lSGFstring && s[i] != ';' && (s[i]==' ' || s[i]=='\n' || s[i]=='\r' || s[i]=='\t')) 
 302      i++;
 303
 304    if (i>=lSGFstring || s[i] != ';')  throw SGFError();
 305    i++;
 306
 307    while (i < lSGFstring) {
 308      while (i < lSGFstring && (s[i]==' ' || s[i]=='\n' || s[i]=='\r' || s[i]=='\t')) 
 309        i++;
 310
 311      if (i >= lSGFstring) break;
 312
 313      char ID[30];
 314      int IDindex = 0;
 315      char IDcomplete[100]; // store long property name here
 316      int IDcompleteIndex = 0;
 317
 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();
 326        }
 327        i++;
 328      }
 329      i++;
 330
 331      if (i >= lSGFstring || IDindex >= 30 || !IDindex || IDcompleteIndex >= 100) {
 332        throw SGFError();
 333      }
 334      ID[IDindex] = 0;
 335      IDcomplete[IDcompleteIndex] = 0;
 336      vector<string>* propValueList = new vector<string>;
 337
 338      while (i < lSGFstring) {
 339        string propValue;
 340
 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;
 347          }
 348          if (s[i] == '\\') {
 349            i++;
 350
 351            if ((s[i]=='\n' && s[i+1]=='\r') || (s[i]=='\r' && s[i+1]=='\n')) {
 352              i += 2;
 353              continue;
 354            }
 355            else if (s[i]=='\n' || s[i]=='\r') {
 356              i++;
 357              continue;
 358            }
 359          }
 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;
 364          }
 365
 366          propValue += s[i]; // building propValue in this way could be a performance problem
 367                             // maybe we should use reserve before. FIXME
 368          i++;
 369
 370          if (i >= lSGFstring) throw SGFError();
 371        }
 372        if ((!strcmp(ID,"B") || !strcmp(ID,"W")) && !(propValue.size() == 2 || (propValue.size() == 0))) {
 373          throw SGFError();
 374        }
 375
 376        propValueList->push_back(propValue);
 377        i++;
 378
 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++;
 383      }
 384      data.insert(make_pair(string(ID), PropValue(string(IDcomplete), propValueList)));
 385    }
 386    parsed = 1;
 387  }
 388}    
 389
 390void 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;
 397}
 398    
 399
 400int Node::sloppy = 1;
 401
 402Cursor::Cursor(const char* sgf, int sloppy) throw(SGFError) {
 403  Node::sloppy = sloppy;
 404
 405  height = 0;
 406  width = 0;
 407  posx = 0;
 408  posy = 0;
 409
 410  root = new Node(NULL, NULL, 0);
 411  parse(sgf);
 412
 413  currentN = root->next;
 414  setFlags();       
 415}
 416
 417Cursor::~Cursor() {
 418  deltree(root);
 419}
 420
 421void Cursor::setFlags() {
 422  if (currentN->next) atEnd = 0;
 423  else atEnd = 1;
 424  if (currentN->previous) atStart = 0;
 425  else atStart = 1;
 426}
 427
 428void Cursor::parse(const char* s) throw(SGFError) {
 429
 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;
 435
 436  int height_previous = 0;
 437  int width_currentVar = 0;
 438
 439  char last = ')';      // type of last parsed bracked ('(' or ')')
 440  bool inbrackets = false;   // are the currently parsed characters in []'s?
 441
 442  int i = 0;  // current parser position
 443  int lSGFstring = strlen(s);
 444
 445  int found_par = 0;
 446  while (i < lSGFstring) {
 447    if (s[i]=='(') {
 448      found_par = i+1;
 449      i++;
 450      continue;
 451    }
 452    if (found_par && s[i]==';') break;
 453
 454    if (found_par && !(s[i]==' ' || s[i]=='\n' || s[i]=='\r' || s[i]=='\t'))
 455      found_par = 0;
 456    i++;
 457  }
 458
 459  if (i >= lSGFstring) throw SGFError();
 460
 461  i = found_par-1; // found beginning of SGF file
 462
 463  while (i < lSGFstring) {
 464    while (i < lSGFstring && !(s[i]=='(' || s[i]==')' || s[i]=='[' || s[i]==']' || s[i]==';')) i++; 
 465    if (i >= lSGFstring) break;
 466
 467    if (inbrackets) {
 468      if (s[i]==']') {
 469        int numberBackslashes = 0;
 470        int j = i-1;
 471        while (s[j] == '\\') {
 472          numberBackslashes++;
 473          j--;
 474        }
 475        if (!(numberBackslashes % 2))
 476          inbrackets = 0;
 477      }
 478      i++;
 479      continue;
 480    }
 481
 482    if (s[i] == '[') inbrackets = 1;
 483
 484    if (s[i] == '(') {
 485      if (last != ')' && p != -1) curr->SGFstring = string(s+p, i-p);
 486
 487      Node* nn = new Node(0,0,0);
 488      nn->previous = curr;
 489
 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;
 499      }
 500      else {
 501        curr->next = nn;
 502        nn->posyD = 0;
 503        height_previous = height;
 504      }
 505
 506      curr->numChildren++;
 507
 508      c.push(curr);
 509      c_width.push(width_currentVar-1);
 510      c_height.push(height);
 511
 512      curr = nn;
 513
 514      p = -1;
 515      last = '(';
 516    }
 517
 518    if (s[i] == ')') {
 519      if (last != ')' && p != -1) {
 520        curr->SGFstring = string(s+p, i-p);       
 521      }
 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();
 529      }
 530      else throw SGFError();
 531      last = ')';
 532    }
 533
 534    if (s[i] == ';') {
 535      if (p != -1) {
 536        curr->SGFstring = string(s+p, i-p);       
 537
 538        Node* nn = new Node(0,0,0);
 539        nn->previous = curr;
 540
 541        if (++width_currentVar > width) width = width_currentVar;
 542        nn->posyD = 0;
 543        curr->numChildren = 1;
 544        curr->next = nn;
 545        curr = nn;
 546      }
 547      p = i;
 548    }
 549
 550    i++;
 551  }
 552
 553  if (inbrackets || c.size()) throw SGFError();
 554
 555  Node* n = curr->next;
 556  n->previous = NULL;
 557  n->up = NULL;
 558
 559  while (n->down) {
 560    n = n->down;
 561    n->previous = NULL;
 562  }
 563}
 564
 565void 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();
 572  }
 573  else throw SGFError();
 574}
 575
 576void 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);
 583    }
 584    deltree(n);
 585  }
 586  delete node;
 587}
 588
 589void Cursor::delVariation(Node* c) {
 590  if (c->previous) {
 591    delVar(c);
 592  }
 593  else {
 594    if (c->next) {
 595      Node* node = c->next;
 596      while (node->down) {
 597        node = node->down;
 598        delVar(node->up);
 599      }  
 600      delVar(node);
 601    }
 602    c->next = 0;
 603  }
 604
 605  setFlags();
 606}
 607
 608void Cursor::delVar(Node* node) {
 609
 610  if (node->up) node->up->down = node->down;
 611  else {
 612    node->previous->next = node->down;
 613  }
 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;
 621    }
 622  }
 623
 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;
 631    }
 632  }
 633
 634  if (node->up || node->down) h++;
 635
 636  Node* p = node->previous;
 637  p->numChildren--;
 638
 639  while (p) {
 640    if (p->down) p->down->posyD -= h;
 641    p = p->previous;
 642  }
 643
 644  height -= h;
 645
 646  // p = node->down;
 647  deltree(node);
 648  // node = 0;
 649}
 650
 651
 652void Cursor::add(char* st) {
 653
 654  Node* node = new Node(currentN,st,0);
 655
 656  node->down = 0;
 657  node->next = 0;
 658  node->numChildren = 0;
 659
 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;
 665
 666    currentN->next = node;
 667    currentN->numChildren = 1;
 668  }
 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;
 675    }
 676
 677    n->down = node;
 678    node->up = n;
 679    node->level = n->level + 1;
 680    node->next= 0;
 681    currentN->numChildren++;
 682
 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;
 689      }
 690    }
 691    posy += node->posyD;
 692
 693    height++;
 694
 695    n = node;
 696    while (n->previous) {
 697      n = n->previous;
 698      if (n->down) n->down->posyD++;
 699    }
 700
 701  }
 702
 703  currentN = node;
 704
 705  posx++;
 706  setFlags();
 707
 708  if (posx > width) width++;
 709}
 710
 711
 712void Cursor::next(int n) throw(SGFError) {
 713
 714  if (n >= currentN->numChildren) {
 715    throw SGFError();
 716  }
 717  posx++;
 718  currentN = currentN->next;
 719  for (int i=0; i<n; i++) {
 720    currentN = currentN->down;
 721    posy += currentN->posyD;
 722  }
 723  setFlags();
 724}
 725    
 726void Cursor::previous() throw(SGFError) {
 727  if (currentN->previous) {
 728    while (currentN->up) {
 729      posy -= currentN->posyD;
 730      currentN = currentN->up;
 731    }
 732    currentN = currentN->previous;
 733    posx--;
 734  }
 735  else throw SGFError();
 736  setFlags();
 737}
 738
 739Node* Cursor::getRootNode(int n) throw(SGFError) {
 740  if (!root) return 0;
 741
 742  if (n >= root->numChildren) throw SGFError();
 743  Node* nn = root->next;
 744  for(int i=0; i<n; i++) nn = nn->down;  
 745  
 746  if (!nn->parsed) nn->parseNode();
 747  return nn;
 748}
 749
 750
 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// }
 762
 763
 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, ";");
 768//   
 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//   }
 875// 
 876//   int l = 0;
 877// 
 878//   PyObject *key, *value;
 879//   int pos = 0;
 880// 
 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")) {
 886//       
 887//       strcat(result, s);
 888// 
 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// }
 909 
 910string 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;
 915
 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;
 927      }
 928    }
 929  }
 930  result += '\n';
 931  return result;
 932}
 933
 934
 935char* Cursor::outputVar(Node* node) {
 936  int s = 1000;
 937  char* result = new char[s];
 938  result[0] = 0;
 939
 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;
 946  }
 947
 948  strcat(result, node->SGFstring.c_str());
 949  // printf("%s\n", node->SGFstring);
 950
 951  while (node->next) {
 952    node = node->next;
 953    if (node->down) {
 954      strcat(result, "(");
 955
 956      char* r = outputVar(node);
 957
 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;
 964      }
 965
 966      strcat(result, r);
 967      delete [] r;
 968
 969      while(node->down) {
 970        node = node->down;
 971        strcat(result, ")(");
 972
 973        char* r = outputVar(node);
 974
 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;
 981        }
 982
 983        strcat(result, r);
 984        delete [] r;
 985      }
 986      strcat(result, ")");
 987      break;
 988    }
 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;
 996      }
 997      strcat(result, node->SGFstring.c_str());
 998      // printf("%s\n", node->SGFstring);
 999    }
1000  }
1001
1002  // printf("r: %d \n", strlen(result));
1003
1004  char* t = new char[strlen(result)+1];
1005  strcpy(t, result);
1006
1007  delete [] result;
1008  return t;
1009}
1010
1011
1012char* Cursor::output() {
1013
1014  int s = 2000;
1015  char* result = new char[s];
1016  result[0] = 0;
1017
1018  Node* n = root->next;
1019
1020  while (n) {
1021    char* t = outputVar(n);
1022
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;
1029    }
1030
1031    strcat(result, "(");
1032    strcat(result, t);
1033    strcat(result, ")\n");
1034    delete [] t;    
1035    n = n->down;
1036  }  
1037
1038  char* t = new char[strlen(result)+1];
1039  strcpy(t, result);
1040  delete [] result;
1041  return t;
1042}
1043
1044