1 // $Id: mmdb_mmcif_.cpp $ 2 // ================================================================= 3 // 4 // CCP4 Coordinate Library: support of coordinate-related 5 // functionality in protein crystallography applications. 6 // 7 // Copyright (C) Eugene Krissinel 2000-2015. 8 // 9 // This library is free software: you can redistribute it and/or 10 // modify it under the terms of the GNU Lesser General Public 11 // License version 3, modified in accordance with the provisions 12 // of the license to address the requirements of UK law. 13 // 14 // You should have received a copy of the modified GNU Lesser 15 // General Public License along with this library. If not, copies 16 // may be downloaded from http://www.ccp4.ac.uk/ccp4license.php 17 // 18 // This program is distributed in the hope that it will be useful, 19 // but WITHOUT ANY WARRANTY; without even the implied warranty of 20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 // GNU Lesser General Public License for more details. 22 // 23 // ================================================================= 24 // 25 // 28.09.15 <-- Date of Last Modification. 26 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 27 // ----------------------------------------------------------------- 28 // 29 // **** Module : MMDB_MMCIF <implementation> 30 // ~~~~~~~~~ 31 // **** Project : MacroMolecular Data Base (MMDB) 32 // ~~~~~~~~~ 33 // **** Classes : mmdb::mmcif::Category ( mmCIF category ) 34 // ~~~~~~~~~ mmdb::mmcif::Struct ( mmCIF structure ) 35 // mmdb::mmcif::Loop ( mmCIF loop ) 36 // mmdb::mmcif::Data ( mmCIF data block ) 37 // mmdb::mmcif::File ( mmCIF file ) 38 // 39 // (C) E. Krissinel 2000-2015 40 // 41 // ================================================================= 42 // 43 44 #include <string.h> 45 #include <stdlib.h> 46 #include <time.h> 47 48 #include "mmdb_mmcif_.h" 49 50 namespace mmdb { 51 52 namespace mmcif { 53 54 // ====================== SortTags =============================== 55 SortTags(psvector tag,int len,ivector index)56 void SortTags ( psvector tag, int len, ivector index ) { 57 int i,k,l,l1,l2; 58 if (len==1) { 59 index[0] = 0; 60 return; 61 } 62 if (strcasecmp(tag[0],tag[1])<0) { 63 index[0] = 0; 64 index[1] = 1; 65 } else { 66 index[0] = 1; 67 index[1] = 0; 68 } 69 for (k=2;k<len;k++) { 70 l2 = k-1; 71 if (strcasecmp(tag[k],tag[index[0]])<0) l2 = 0; 72 else if (strcasecmp(tag[k],tag[index[l2]])>0) l2 = k; 73 else { 74 l1 = 0; 75 while (l1<l2-1) { 76 l = (l1+l2)/2; 77 if (strcasecmp(tag[k],tag[index[l]])<0) l2 = l; 78 else l1 = l; 79 } 80 } 81 for (i=k;i>l2;i--) 82 index[i] = index[i-1]; 83 index[l2] = k; 84 } 85 } 86 87 88 // ====================== Category ========================== 89 90 const int CIF_NODATA_DOT = 0; 91 const int CIF_NODATA_QUESTION = 1; 92 cpstr CIF_NODATA_DOT_FIELD = pstr("\x02" "."); 93 cpstr CIF_NODATA_QUESTION_FIELD = pstr("\x02" "?"); 94 Category()95 Category::Category() : io::Stream() { 96 InitCategory(); 97 } 98 Category(cpstr N)99 Category::Category ( cpstr N ) : io::Stream() { 100 InitCategory(); 101 SetCategoryName ( N ); 102 } 103 Category(io::RPStream Object)104 Category::Category ( io::RPStream Object ) : io::Stream(Object) { 105 InitCategory(); 106 } 107 ~Category()108 Category::~Category() { 109 FreeMemory(); 110 } 111 InitCategory()112 void Category::InitCategory() { 113 name = NULL; 114 nTags = 0; 115 tag = NULL; 116 index = NULL; 117 nAllocTags = 0; 118 } 119 FreeMemory()120 void Category::FreeMemory() { 121 int i; 122 if (name) delete[] name; 123 name = NULL; 124 for (i=0;i<nAllocTags;i++) 125 if (tag[i]) delete[] tag[i]; 126 FreeVectorMemory ( tag ,0 ); 127 FreeVectorMemory ( index,0 ); 128 nTags = 0; 129 nAllocTags = 0; 130 } 131 SetCategoryName(cpstr N)132 void Category::SetCategoryName ( cpstr N ) { 133 if (N[0]) CreateCopy ( name,N ); 134 else { 135 CreateCopy ( name,pstr(" ") ); 136 name[0] = char(1); // no category name 137 } 138 } 139 ExpandTags(int nTagsNew)140 void Category::ExpandTags ( int nTagsNew ) { 141 int i,nAT; 142 psvector tag1; 143 ivector index1; 144 if (nTagsNew>nAllocTags) { 145 nAT = nTagsNew + IMin(nAllocTags/2+1,20); 146 GetVectorMemory ( tag1 ,nAT,0 ); 147 GetVectorMemory ( index1,nAT,0 ); 148 for (i=0;i<nAllocTags;i++) { 149 tag1 [i] = tag [i]; 150 index1[i] = index[i]; 151 } 152 for (i=nAllocTags;i<nAT;i++) { 153 tag1 [i] = NULL; 154 index1[i] = i; 155 } 156 FreeVectorMemory ( tag ,0 ); 157 FreeVectorMemory ( index,0 ); 158 tag = tag1; 159 index = index1; 160 nAllocTags = nAT; 161 } 162 } 163 GetTag(int tagNo)164 pstr Category::GetTag ( int tagNo ) { 165 if ((tagNo>=0) && (tagNo<nTags)) return tag[tagNo]; 166 return NULL; 167 } 168 Sort()169 void Category::Sort() { 170 // Sorts tags for easing the search 171 int i,k; 172 if (nAllocTags>0) { 173 k = 0; 174 if (!index) 175 GetVectorMemory ( index,nAllocTags,0 ); 176 for (i=0;i<nTags;i++) 177 if (tag[i]) { 178 if (k<i) { 179 tag[k] = tag[i]; 180 tag[i] = NULL; 181 } 182 k++; 183 } 184 nTags = k; 185 SortTags ( tag,nTags,index ); 186 } 187 } 188 Optimize()189 void Category::Optimize() { 190 int i,k; 191 psvector tag1; 192 k = 0; 193 for (i=0;i<nTags;i++) 194 if (tag[i]) k++; 195 if (k<=0) FreeMemory(); 196 else if (k!=nAllocTags) { 197 GetVectorMemory ( tag1,k,0 ); 198 FreeVectorMemory ( index,0 ); 199 k = 0; 200 for (i=0;i<nTags;i++) 201 if (tag[i]) 202 tag1[k++] = tag[i]; 203 FreeVectorMemory ( tag,0 ); 204 tag = tag1; 205 nTags = k; 206 nAllocTags = nTags; 207 Sort(); 208 } 209 } 210 GetTagNo(cpstr ttag)211 int Category::GetTagNo ( cpstr ttag ) { 212 // Binary search for index of tag ttag in tag[]. 213 // Return: 214 // >=0 : position of the tag found 215 // <0 : the tag was not found, it could be inserted before 216 // (-RC-1)th element, where RC is the return value 217 int l1,l2,l,k; 218 219 if (!tag) return -1; 220 221 if (!index) Sort(); 222 223 l = 0; 224 l1 = 0; 225 l2 = nTags-1; 226 k = 1; 227 while (l1<l2-1) { 228 l = (l1+l2)/2; 229 k = strcasecmp ( ttag,tag[index[l]] ); 230 if (k<0) l2 = l; 231 else if (k>0) l1 = l; 232 else { 233 l1 = l; 234 break; 235 } 236 } 237 238 if (k==0) return index[l]; // is at RCth position 239 k = strcasecmp ( ttag,tag[index[l1]] ); 240 if (k==0) return index[l1]; // is at RCth position 241 if (k<0) return -1; // would be at (-RC-1)th position 242 if (l2!=l1) { 243 k = strcasecmp ( ttag,tag[index[l2]] ); 244 if (k==0) return index[l2]; // is at RCth position 245 if (k>0) return -2-l2; // would be at l2+1=(-RC-1)th position 246 } 247 248 return -2-l1; // would be at l1+1=(-RC-1)th position 249 250 } 251 AddTag(cpstr ttag)252 int Category::AddTag ( cpstr ttag ) { 253 // return -1: the tag has been added on the top of array; 254 // index is added and sorted automatically 255 // >=0: the tag is already in the array -- its position 256 // is returned 257 int i1,i; 258 if (!tag) { 259 ExpandTags ( 3 ); // get space for first 3 tags 260 CreateCopy ( tag[0],ttag ); 261 nTags = 1; 262 return -nTags; // the tag has been added on the top of array 263 } 264 i1 = GetTagNo ( ttag ); 265 if (i1>=0) return i1; // non-negative returns mean that 266 // the tag is already in the array 267 i1 = -i1-1; // otherwise the tag has to be added and indexed at here 268 // put new tag on the top of array and update index 269 ExpandTags ( nTags+1 ); 270 CreateCopy ( tag[nTags],ttag ); 271 for (i=nTags;i>i1;i--) 272 index[i] = index[i-1]; 273 index[i1] = nTags; 274 nTags++; 275 return -nTags; // the tag has been added on the top of array 276 } 277 PrintTags()278 void Category::PrintTags() { 279 int i; 280 Sort(); 281 printf ( " Unsorted tags:\n" ); 282 for (i=0;i<nTags;i++) 283 if (tag[i]) 284 printf ( " %s.%s\n",name,tag[i] ); 285 if (index) { 286 printf ( " Sorted tags:\n" ); 287 for (i=0;i<nTags;i++) 288 if (tag[index[i]]) 289 printf ( " %s.%s\n",name,tag[index[i]] ); 290 } 291 } 292 CheckTags(cpstr * tagList)293 bool Category::CheckTags ( cpstr * tagList ) { 294 int i; 295 i = 0; 296 while (tagList[i][0]) { 297 if (GetTagNo(tagList[i])<0) return false; 298 i++; 299 } 300 return true; 301 } 302 PutCategoryName(cpstr newName)303 void Category::PutCategoryName ( cpstr newName ) { 304 CreateCopy ( name,newName ); 305 } 306 Copy(PCategory Category)307 void Category::Copy ( PCategory Category ) { 308 int i; 309 FreeMemory(); 310 if (Category) { 311 CreateCopy ( name,Category->name ); 312 nTags = Category->nTags; 313 nAllocTags = nTags; 314 if (nTags>0) { 315 GetVectorMemory ( tag ,nAllocTags,0 ); 316 GetVectorMemory ( index,nAllocTags,0 ); 317 for (i=0;i<nTags;i++) { 318 tag[i] = NULL; 319 CreateCopy ( tag[i],Category->tag[i] ); 320 index[i] = Category->index[i]; 321 } 322 } 323 } 324 } 325 326 write(io::RFile f)327 void Category::write ( io::RFile f ) { 328 int i; 329 if (!index) Sort(); 330 f.CreateWrite ( name ); 331 f.WriteInt ( &nTags ); 332 for (i=0;i<nTags;i++) 333 f.CreateWrite ( tag[i] ); 334 f.WriteVector ( index,nTags,0 ); 335 } 336 read(io::RFile f)337 void Category::read ( io::RFile f ) { 338 int i; 339 FreeMemory (); 340 f.CreateRead ( name ); 341 f.ReadInt ( &nTags ); 342 nAllocTags = nTags; 343 if (nTags>0) { 344 GetVectorMemory ( tag,nTags,0 ); 345 for (i=0;i<nTags;i++) { 346 tag[i] = NULL; 347 f.CreateRead ( tag[i] ); 348 } 349 } 350 f.CreateReadVector ( index,0 ); 351 } 352 MakeStreamFunctions(Category)353 MakeStreamFunctions(Category) 354 355 356 357 // ====================== Struct =========================== 358 359 360 Struct::Struct() : Category() { 361 InitStruct(); 362 } 363 Struct(cpstr N)364 Struct::Struct ( cpstr N ) : Category(N) { 365 InitStruct(); 366 } 367 Struct(io::RPStream Object)368 Struct::Struct ( io::RPStream Object ) : Category(Object) { 369 InitStruct(); 370 } 371 ~Struct()372 Struct::~Struct() { 373 FreeMemory(); 374 } 375 FreeMemory()376 void Struct::FreeMemory() { 377 int i; 378 for (i=0;i<nAllocTags;i++) 379 if (field[i]) delete[] field[i]; 380 FreeVectorMemory ( field,0 ); 381 Category::FreeMemory(); 382 } 383 InitStruct()384 void Struct::InitStruct() { 385 field = NULL; 386 } 387 Optimize()388 void Struct::Optimize() { 389 int i,k; 390 psvector f1; 391 k = 0; 392 for (i=0;i<nTags;i++) 393 if (!tag[i]) { 394 if (field[i]) delete[] field[i]; 395 field[i] = NULL; 396 } else if (!field[i]) { 397 delete[] tag[i]; 398 tag[i] = NULL; 399 } else 400 k++; 401 if (k<=0) FreeMemory(); 402 else if (k!=nAllocTags) { 403 f1 = new pstr[k]; 404 k = 0; 405 for (i=0;i<nTags;i++) 406 if (tag[i]) 407 f1[k++] = field[i]; 408 FreeVectorMemory ( field,0 ); 409 field = f1; 410 Category::Optimize(); 411 } 412 } 413 AddField(cpstr F,cpstr T,bool Concatenate)414 void Struct::AddField ( cpstr F, cpstr T, bool Concatenate ) { 415 psvector field1; 416 int i,nAT; 417 pstr nf; 418 419 nAT = nAllocTags; 420 i = AddTag ( T ); 421 422 if (i<0) { 423 // The tag was not in the list, but has been added on the top 424 // of list. Now expand the field list and put new field on 425 // the top of it. 426 if (nAllocTags>nAT) { 427 GetVectorMemory ( field1,nAllocTags,0 ); 428 for (i=0;i<nTags-1;i++) 429 field1[i] = field[i]; 430 for (i=nTags-1;i<nAllocTags;i++) 431 field1[i] = NULL; 432 FreeVectorMemory ( field,0 ); 433 field = field1; 434 } 435 i = nTags-1; 436 field[i] = NULL; 437 } 438 439 if (!F) { 440 if ((!Concatenate) || (!field[i])) { 441 CreateCopy ( field[i],pstr(" ?") ); 442 field[i][0] = char(2); 443 } 444 } else if ((!Concatenate) || (!field[i])) 445 CreateCopy ( field[i],F ); 446 else { 447 nf = new char[strlen(field[i])+strlen(F)+1]; 448 strcpy ( nf,field[i] ); 449 strcat ( nf,F ); 450 delete[] field[i]; 451 field[i] = nf; 452 } 453 454 } 455 GetField(int tagNo)456 pstr Struct::GetField ( int tagNo ) { 457 if ((tagNo>=0) && (tagNo<nTags)) return field[tagNo]; 458 return NULL; 459 } 460 GetString(pstr & S,cpstr TName,bool Remove)461 int Struct::GetString ( pstr & S, cpstr TName, 462 bool Remove ) { 463 int k = GetTagNo ( TName ); 464 if (S) delete[] S; 465 S = NULL; 466 if (!field) return CIFRC_NoField; 467 if (k<0) return CIFRC_NoTag; 468 if (!field[k]) return CIFRC_NoField; 469 if (field[k][0]==char(2)) { 470 if (Remove) { 471 delete[] field[k]; 472 field[k] = NULL; 473 } 474 } else if (Remove) { 475 S = field[k]; 476 field[k] = NULL; 477 } else 478 CreateCopy ( S,field[k] ); 479 return 0; 480 } 481 GetString(cpstr TName,int & RC)482 pstr Struct::GetString ( cpstr TName, int & RC ) { 483 int k = GetTagNo ( TName ); 484 if (k<0) { 485 RC = CIFRC_NoTag; 486 return NULL; 487 } 488 if (!field) { 489 RC = CIFRC_NoField; 490 return NULL; 491 } 492 if (!field[k]) { 493 RC = CIFRC_NoField; 494 return NULL; 495 } 496 RC = 0; 497 if (field[k][0]==char(2)) return NULL; 498 return field[k]; 499 } 500 DeleteField(cpstr TName)501 int Struct::DeleteField ( cpstr TName ) { 502 int k = GetTagNo ( TName ); 503 if ((k>=0) && (field)) { 504 if (field[k]) delete[] field[k]; 505 field[k] = NULL; 506 } 507 return k; 508 } 509 GetReal(realtype & R,cpstr TName,bool Remove)510 int Struct::GetReal ( realtype & R, cpstr TName, 511 bool Remove ) { 512 pstr endptr; 513 int RC; 514 int k = GetTagNo ( TName ); 515 R = 0.0; 516 if (!field) return CIFRC_NoField; 517 if (k<0) return CIFRC_NoTag; 518 if (!field[k]) return CIFRC_NoField; 519 if (field[k][0]==char(2)) return CIFRC_NoData; 520 R = strtod ( field[k],&endptr ); 521 if (endptr==field[k]) RC = CIFRC_WrongFormat; 522 else { 523 RC = 0; 524 if (Remove) { 525 delete[] field[k]; 526 field[k] = NULL; 527 } 528 } 529 return RC; 530 } 531 GetInteger(int & I,cpstr TName,bool Remove)532 int Struct::GetInteger ( int & I, cpstr TName, 533 bool Remove ) { 534 pstr endptr; 535 int RC; 536 int k = GetTagNo ( TName ); 537 I = 0; 538 if (!field) return CIFRC_NoField; 539 if (k<0) return CIFRC_NoTag; 540 if (!field[k]) return CIFRC_NoField; 541 if (field[k][0]==char(2)) { 542 if (field[k][1]=='.') I = MinInt4; 543 return CIFRC_NoData; 544 } 545 I = mround ( strtod(field[k],&endptr) ); 546 if (endptr==field[k]) RC = CIFRC_WrongFormat; 547 else { 548 RC = 0; 549 if (Remove) { 550 delete[] field[k]; 551 field[k] = NULL; 552 } 553 } 554 return RC; 555 } 556 557 PutString(cpstr S,cpstr T,bool NonBlankOnly)558 void Struct::PutString ( cpstr S, cpstr T, 559 bool NonBlankOnly ) { 560 pstr p; 561 if (!S) PutNoData ( CIF_NODATA_QUESTION,T ); 562 else { 563 p = pstr(S); 564 if (NonBlankOnly) 565 while (*p==' ') p++; 566 if (!(*p)) PutNoData ( CIF_NODATA_DOT,T ); 567 else AddField ( S,T,false ); 568 } 569 } 570 PutDate(cpstr T)571 void Struct::PutDate ( cpstr T ) { 572 time_t t; 573 tm * tstruct; 574 char S[100]; 575 t = time ( NULL ); 576 tstruct = localtime(&t); 577 if (tstruct) 578 sprintf ( S,"%4i-%02i-%02i", 579 tstruct->tm_year+1900,tstruct->tm_mon+1,tstruct->tm_mday ); 580 else strcpy ( S,"YYYY-MM-DD" ); 581 AddField ( S,T,false ); 582 } 583 584 PutNoData(int NoDataType,cpstr T)585 void Struct::PutNoData ( int NoDataType, cpstr T ) { 586 char S[10]; 587 S[0] = char(2); 588 if (NoDataType==CIF_NODATA_DOT) S[1] = '.'; 589 else S[1] = '?'; 590 S[2] = char(0); 591 AddField ( S,T,false ); 592 } 593 594 PutReal(realtype R,cpstr T,int prec)595 void Struct::PutReal ( realtype R, cpstr T, int prec ) { 596 char rS[100]; 597 sprintf ( rS,"%.*g",prec,R ); 598 AddField ( rS,T,false ); 599 } 600 PutReal(realtype R,cpstr T,cpstr format)601 void Struct::PutReal ( realtype R, cpstr T, cpstr format ) { 602 char rS[100]; 603 sprintf ( rS,format,R ); 604 AddField ( DelSpaces(rS,' '),T,false ); 605 } 606 PutInteger(int I,cpstr T)607 void Struct::PutInteger ( int I, cpstr T ) { 608 char iS[100]; 609 if (I>MinInt4) { 610 sprintf ( iS,"%i",I ); 611 AddField ( iS,T,false ); 612 } else 613 PutNoData ( CIF_NODATA_DOT,T ); 614 } 615 616 617 618 #define NODATA_Q pstr("?") 619 #define NODATA_P pstr(".") 620 WriteMMCIFStruct(cpstr FName,io::GZ_MODE gzipMode)621 bool Struct::WriteMMCIFStruct ( cpstr FName, 622 io::GZ_MODE gzipMode ) { 623 io::File f; 624 f.assign ( FName,true,false,gzipMode ); 625 if (f.rewrite()) { 626 WriteMMCIF ( f ); 627 f.shut(); 628 return true; 629 } else 630 return false; 631 } 632 633 #define _max_output_line_width 256 634 WriteMMCIF(io::RFile f)635 void Struct::WriteMMCIF ( io::RFile f ) { 636 int i,j,k,l,m,n; 637 pstr F; 638 639 // calculate maximal length of tags 640 l = 0; 641 for (i=0;i<nTags;i++) 642 l = IMax(l,strlen(tag[i])); 643 l += 1; // add one space separator 644 645 // calculate maximal space left for data 646 m = _max_output_line_width - l; 647 // subtract category name width 648 if (name[0]!=char(1)) m -= strlen(name); 649 650 // start outout 651 f.LF(); 652 for (i=0;i<nTags;i++) { // for each tag 653 654 // print category name, if not hidden, and dot 655 if (name[0]!=char(1)) { 656 f.Write ( name ); 657 f.Write ( pstr(".") ); 658 } 659 660 // print tag, checking for duplicate tag flag 661 F = FirstOccurence ( tag[i],'\1' ); 662 if (F) { 663 *F = char(0); 664 f.Write ( tag[i] ); 665 *F = '\1'; 666 } else 667 f.Write ( tag[i] ); 668 669 // print field 670 if (field[i]) { // field is defined 671 F = field[i]; 672 if (FirstOccurence(F,'\n') || strstr(F,"\" ")) { 673 f.Write ( pstr("\n;") ); 674 f.Write ( F ); 675 f.Write ( pstr("\n;\n") ); 676 } else { 677 n = strlen(F); 678 if (n>m) // wrap around if field is too long 679 f.Write ( pstr("\n ") ); 680 else { 681 k = l-strlen(tag[i]); 682 for (j=0;j<k;j++) 683 f.Write ( pstr(" ") ); 684 } 685 if ((((F[0]=='.') || (F[0]=='?')) && (!F[1])) || 686 FirstOccurence(F,' ')) { 687 f.Write ( pstr("\"") ); 688 f.Write ( field[i] ); 689 f.Write ( pstr("\"\n") ); 690 } else if (field[i][0]==char(2)) { 691 f.WriteLine ( &(field[i][1]) ); 692 } else if (!field[i][0]) { 693 f.WriteLine ( NODATA_P ); 694 } else 695 f.WriteLine ( field[i] ); 696 } 697 698 } else { // field if not defined, put question mark 699 700 k = l-strlen(tag[i]); 701 for (j=0;j<k;j++) 702 f.Write ( pstr(" ") ); 703 f.WriteLine ( NODATA_Q ); 704 705 } 706 707 } 708 709 } 710 Copy(PCategory Struct)711 void Struct::Copy ( PCategory Struct ) { 712 int i; 713 Category::Copy ( Struct ); 714 if (nTags>0) { 715 GetVectorMemory ( field,nTags,0 ); 716 for (i=0;i<nTags;i++) { 717 field[i] = NULL; 718 CreateCopy ( field[i],PStruct(Struct)->field[i] ); 719 } 720 } 721 } 722 write(io::RFile f)723 void Struct::write ( io::RFile f ) { 724 int i; 725 Category::write ( f ); 726 for (i=0;i<nTags;i++) 727 f.CreateWrite ( field[i] ); 728 } 729 read(io::RFile f)730 void Struct::read ( io::RFile f ) { 731 int i; 732 Category::read ( f ); 733 if (nTags>0) { 734 GetVectorMemory ( field,nTags,0 ); 735 for (i=0;i<nTags;i++) { 736 field[i] = NULL; 737 f.CreateRead ( field[i] ); 738 } 739 } 740 } 741 742 MakeStreamFunctions(Struct)743 MakeStreamFunctions(Struct) 744 745 746 747 // ====================== Loop ============================== 748 749 750 Loop::Loop() : Category() { 751 InitLoop(); 752 } 753 Loop(cpstr N)754 Loop::Loop ( cpstr N ) : Category(N) { 755 InitLoop(); 756 } 757 Loop(io::RPStream Object)758 Loop::Loop ( io::RPStream Object ) : Category(Object) { 759 InitLoop(); 760 } 761 ~Loop()762 Loop::~Loop() { 763 FreeMemory(); 764 } 765 InitLoop()766 void Loop::InitLoop() { 767 nRows = 0; 768 field = NULL; 769 iColumn = 0; 770 nAllocRows = 0; 771 } 772 FreeMemory()773 void Loop::FreeMemory() { 774 DeleteFields(); 775 Category::FreeMemory(); 776 } 777 Optimize()778 void Loop::Optimize() { 779 int i,j,nT,nR,k,m; 780 bool empty; 781 psmatrix f1; 782 783 if (!field) { 784 Category::Optimize(); // optimize tags 785 return; 786 } 787 788 // first check for empty columns 789 nT = 0; 790 for (i=0;i<nTags;i++) 791 if (!tag[i]) { 792 for (j=0;j<nRows;j++) // delete ith column of field 793 if (field[j]) { 794 if (field[j][i]) 795 delete[] field[j][i]; 796 field[j][i] = NULL; 797 } 798 } else { 799 empty = true; 800 j = 0; 801 while ((j<nRows) && empty) { // check if ith column is empty 802 if (field[j]) 803 empty = !field[j][i]; 804 j++; 805 } 806 if (empty) { // if ith column is empty, delete its tag 807 delete[] tag[i]; 808 tag[i] = NULL; 809 } else // otherwise count ith tag 810 nT++; 811 } 812 813 // now check for empty rows 814 nR = 0; 815 for (j=0;j<nRows;j++) 816 if (field[j]) { 817 i = 0; 818 while ((i<nTags) && (!field[j][i])) i++; 819 if (i>=nTags) { 820 delete[] field[j]; // delete empty row 821 field[j] = NULL; 822 } else 823 nR++; // count non-empty row 824 } 825 if ((nT<=0) || (nR<=0)) 826 FreeMemory(); // the loop is completely empty 827 else if ((nT!=nTags) || (nR!=nAllocRows)) { 828 f1 = new psvector[nR]; 829 m = 0; 830 for (j=0;j<nRows;j++) 831 if (field[j]) { 832 f1[m] = new pstr[nT]; 833 k = 0; 834 for (i=0;i<nTags;i++) 835 if (tag[i]) 836 f1[m][k++] = field[j][i]; 837 m++; 838 delete[] field[j]; 839 } 840 if (field) delete[] field; 841 field = f1; 842 nRows = nR; 843 nAllocRows = nRows; 844 Category::Optimize(); // optimize tags 845 } 846 847 } 848 DeleteFields()849 void Loop::DeleteFields() { 850 int i,j; 851 if (field) { 852 for (i=0;i<nAllocRows;i++) 853 if (field[i]) { 854 for (j=0;j<nTags;j++) 855 if (field[i][j]) delete[] field[i][j]; 856 delete[] field[i]; 857 } 858 delete[] field; 859 field = NULL; 860 nRows = 0; 861 nAllocRows = 0; 862 } 863 } 864 AddLoopTag(cpstr T,bool Remove)865 void Loop::AddLoopTag ( cpstr T, bool Remove ) { 866 psmatrix f1; 867 int i,j,nT1; 868 if (Remove) { 869 DeleteFields(); 870 AddTag ( T ); 871 } else { 872 f1 = field; 873 field = NULL; 874 i = AddTag ( T ); 875 if ((f1) && (i<0)) { 876 // The tag was added on the top of tag array. Create 877 // and fill new fields. 878 field = new psvector[nAllocRows]; 879 nT1 = nTags-1; 880 for (i=0;i<nAllocRows;i++) 881 if (f1[i]) { 882 field[i] = new pstr[nTags]; 883 for (j=0;j<nT1;j++) 884 field[i][j] = f1[i][j]; 885 field[i][nT1] = NULL; 886 f1[i] = NULL; 887 } else 888 field[i] = NULL; 889 delete[] f1; 890 } else 891 // The tag was already in the category. Just restore fields. 892 field = f1; 893 } 894 } 895 896 ExpandRows(int nRowsNew)897 void Loop::ExpandRows ( int nRowsNew ) { 898 int nAR,i; 899 psmatrix field1; 900 if (nRowsNew>nAllocRows) { 901 nAR = nRowsNew + IMin(nAllocRows/2+10,2000); 902 field1 = new psvector[nAR]; 903 for (i=0;i<nAllocRows;i++) 904 field1[i] = field[i]; 905 for (i=nAllocRows;i<nAR;i++) 906 field1[i] = NULL; 907 if (field) delete[] field; 908 field = field1; 909 nAllocRows = nAR; 910 } 911 } 912 AddString(cpstr S,bool NonBlankOnly)913 void Loop::AddString ( cpstr S, bool NonBlankOnly ) { 914 int i; 915 pstr p; 916 if (!S) AddNoData ( CIF_NODATA_QUESTION ); 917 else { 918 p = pstr(S); 919 if (NonBlankOnly) 920 while (*p==' ') p++; 921 if (!(*p)) AddNoData ( CIF_NODATA_DOT ); 922 else { 923 if (iColumn==0) { // start a new row 924 ExpandRows ( nRows+1 ); 925 field[nRows] = new pstr[nTags]; 926 for (i=0;i<nTags;i++) 927 field[nRows][i] = NULL; 928 nRows++; 929 } 930 CreateCopy ( field[nRows-1][iColumn],S ); 931 iColumn++; 932 if (iColumn>=nTags) iColumn = 0; 933 } 934 } 935 } 936 AddNoData(int NoDataType)937 void Loop::AddNoData ( int NoDataType ) { 938 char S[10]; 939 S[0] = char(2); 940 if (NoDataType==CIF_NODATA_DOT) S[1] = '.'; 941 else S[1] = '?'; 942 S[2] = char(0); 943 AddString ( S ); 944 } 945 AddReal(realtype R,int prec)946 void Loop::AddReal ( realtype R, int prec ) { 947 char rS[100]; 948 sprintf ( rS,"%.*g",prec,R ); 949 AddString ( rS ); 950 } 951 AddReal(realtype R,cpstr format)952 void Loop::AddReal ( realtype R, cpstr format ) { 953 char rS[100]; 954 sprintf ( rS,format,R ); 955 AddString ( DelSpaces(rS,' ') ); 956 } 957 AddInteger(int I)958 void Loop::AddInteger ( int I ) { 959 char iS[100]; 960 if (I>MinInt4) { 961 sprintf ( iS,"%i",I ); 962 AddString ( iS ); 963 } else 964 AddNoData ( CIF_NODATA_DOT ); 965 } 966 967 GetField(int rowNo,int tagNo)968 pstr Loop::GetField ( int rowNo, int tagNo ) { 969 if ((tagNo>=0) && (tagNo<nTags) && 970 (rowNo>=0) && (rowNo<nRows)) { 971 if (field[rowNo]) return field[rowNo][tagNo]; 972 } 973 return NULL; 974 } 975 GetString(pstr & S,cpstr TName,int nrow,bool Remove)976 int Loop::GetString ( pstr & S, cpstr TName, int nrow, 977 bool Remove) { 978 int k = GetTagNo ( TName ); 979 if (S) delete[] S; 980 S = NULL; 981 if (k<0) return CIFRC_NoTag; 982 if ((nrow<0) || (nrow>=nRows)) return CIFRC_WrongIndex; 983 if (!field[nrow]) return CIFRC_NoField; 984 if (!field[nrow][k]) return CIFRC_NoField; 985 if (field[nrow][k][0]==char(2)) { 986 if (Remove) { 987 delete[] field[nrow][k]; 988 field[nrow][k] = NULL; 989 } 990 } else if (Remove) { 991 S = field[nrow][k]; 992 field[nrow][k] = NULL; 993 } else 994 CreateCopy ( S,field[nrow][k] ); 995 return 0; 996 } 997 GetString(cpstr TName,int nrow,int & RC)998 pstr Loop::GetString ( cpstr TName, int nrow, int & RC ) { 999 int k = GetTagNo ( TName ); 1000 if (k<0) { 1001 RC = CIFRC_NoTag; 1002 return NULL; 1003 } 1004 if ((nrow<0) || (nrow>=nRows)) { 1005 RC = CIFRC_WrongIndex; 1006 return NULL; 1007 } 1008 if (!field[nrow]) { 1009 RC = CIFRC_NoField; 1010 return NULL; 1011 } 1012 if (!field[nrow][k]) { 1013 RC = CIFRC_NoField; 1014 return NULL; 1015 } 1016 RC = 0; 1017 // char(2) means the field was either '.' or '?' 1018 if (field[nrow][k][0]==char(2)) return NULL; 1019 return field[nrow][k]; 1020 } 1021 1022 // CopyString() does nothing if RC is not 0 CopyString(pstr buf,int maxlength,cpstr TName,int nrow,int & RC)1023 void Loop::CopyString ( pstr buf, int maxlength, 1024 cpstr TName, int nrow, int & RC ) { 1025 pstr p; 1026 int k; 1027 1028 if (RC) return; 1029 1030 k = GetTagNo ( TName ); 1031 if (k<0) { 1032 RC = CIFRC_NoTag; 1033 buf[0] = char(0); 1034 return; 1035 } 1036 if ((nrow<0) || (nrow>=nRows)) { 1037 RC = CIFRC_WrongIndex; 1038 buf[0] = char(0); 1039 return; 1040 } 1041 if (!field[nrow]) { 1042 RC = CIFRC_NoField; 1043 buf[0] = char(0); 1044 return; 1045 } 1046 p = field[nrow][k]; 1047 if (!p) { 1048 RC = CIFRC_NoField; 1049 buf[0] = char(0); 1050 return; 1051 } 1052 1053 // char(2) means the field was either '.' or '?' 1054 if (p[0]==char(2)) { 1055 buf[0] = p[0]; 1056 buf[1] = char(0); 1057 } else 1058 strncpy ( buf,p,IMin(maxlength,strlen(p)+1) ); 1059 1060 } 1061 1062 1063 DeleteField(cpstr TName,int nrow)1064 int Loop::DeleteField ( cpstr TName, int nrow ) { 1065 int k = GetTagNo ( TName ); 1066 if (k<0) return CIFRC_NoTag; 1067 if ((nrow<0) || (nrow>=nRows)) 1068 return CIFRC_WrongIndex; 1069 if (field[nrow]) { 1070 if (field[nrow][k]) delete[] field[nrow][k]; 1071 field[nrow][k] = NULL; 1072 } 1073 return k; 1074 } 1075 DeleteRow(int nrow)1076 int Loop::DeleteRow ( int nrow ) { 1077 int i; 1078 if ((nrow<0) || (nrow>=nRows)) 1079 return CIFRC_WrongIndex; 1080 if (field[nrow]) { 1081 for (i=0;i<nTags;i++) 1082 if (field[nrow][i]) { 1083 delete[] field[nrow][i]; 1084 field[nrow][i] = NULL; 1085 } 1086 delete[] field[nrow]; 1087 field[nrow] = NULL; 1088 } 1089 return 0; 1090 } 1091 GetReal(realtype & R,cpstr TName,int nrow,bool Remove)1092 int Loop::GetReal ( realtype & R, cpstr TName, int nrow, 1093 bool Remove ) { 1094 pstr endptr; 1095 int k = GetTagNo ( TName ); 1096 if (k<0) return CIFRC_NoTag; 1097 if ((nrow<0) || (nrow>=nRows)) 1098 return CIFRC_WrongIndex; 1099 R = 0.0; 1100 if (!field[nrow]) return CIFRC_NoField; 1101 if (!field[nrow][k]) return CIFRC_NoField; 1102 if (field[nrow][k][0]==char(2)) return CIFRC_NoField; 1103 R = strtod ( field[nrow][k],&endptr ); 1104 if (endptr==field[nrow][k]) return CIFRC_WrongFormat; 1105 if (Remove) { 1106 delete[] field[nrow][k]; 1107 field[nrow][k] = NULL; 1108 } 1109 return 0; 1110 } 1111 CopyReal(realtype & R,cpstr TName,int nrow,int & RC)1112 void Loop::CopyReal ( realtype & R, cpstr TName, int nrow, 1113 int & RC ) { 1114 pstr endptr; 1115 int k; 1116 1117 if (RC) return; 1118 1119 // R = 0.0; 1120 k = GetTagNo ( TName ); 1121 1122 if (k<0) RC = CIFRC_NoTag; 1123 else if ((nrow<0) || (nrow>=nRows)) RC = CIFRC_WrongIndex; 1124 else if (!field[nrow]) RC = CIFRC_NoField; 1125 else if (!field[nrow][k]) RC = CIFRC_NoField; 1126 else if (field[nrow][k][0]==char(2)) RC = CIFRC_NoField; 1127 else { 1128 R = strtod ( field[nrow][k],&endptr ); 1129 if (endptr==field[nrow][k]) RC = CIFRC_WrongFormat; 1130 } 1131 1132 } 1133 CopyInteger(int & I,cpstr TName,int nrow,int & RC)1134 void Loop::CopyInteger ( int & I, cpstr TName, int nrow, 1135 int & RC ) { 1136 pstr endptr; 1137 int k; 1138 1139 if (RC) return; 1140 1141 I = 0; 1142 k = GetTagNo ( TName ); 1143 1144 if (k<0) RC = CIFRC_NoTag; 1145 else if ((nrow<0) || (nrow>=nRows)) RC = CIFRC_WrongIndex; 1146 else if (!field[nrow]) RC = CIFRC_NoField; 1147 else if (!field[nrow][k]) RC = CIFRC_NoField; 1148 else if (field[nrow][k][0]==char(2)) RC = CIFRC_NoField; 1149 else { 1150 I = mround ( strtod ( field[nrow][k],&endptr ) ); 1151 if (endptr==field[nrow][k]) RC = CIFRC_WrongFormat; 1152 } 1153 1154 } 1155 GetInteger(int & I,cpstr TName,int nrow,bool Remove)1156 int Loop::GetInteger ( int & I, cpstr TName, int nrow, 1157 bool Remove ) { 1158 pstr endptr; 1159 int k = GetTagNo ( TName ); 1160 if (k<0) return CIFRC_NoTag; 1161 if ((nrow<0) || (nrow>=nRows)) 1162 return CIFRC_WrongIndex; 1163 I = 0; 1164 if (!field[nrow]) return CIFRC_NoField; 1165 if (!field[nrow][k]) return CIFRC_NoField; 1166 if (field[nrow][k][0]==char(2)) { 1167 if (field[nrow][k][1]=='.') I = MinInt4; 1168 return CIFRC_NoField; 1169 } 1170 I = mround ( strtod(field[nrow][k],&endptr) ); 1171 if (endptr==field[nrow][k]) return CIFRC_WrongFormat; 1172 if (Remove) { 1173 delete[] field[nrow][k]; 1174 field[nrow][k] = NULL; 1175 } 1176 return 0; 1177 } 1178 1179 GetSVector(psvector & S,cpstr TName,int i1,int i2,bool Remove)1180 int Loop::GetSVector ( psvector & S, cpstr TName, 1181 int i1, int i2, bool Remove ) { 1182 int j,k,r1,r2; 1183 r1 = IMin(i1,i2); 1184 r2 = IMin(IMax(i1,i2),nRows-1); 1185 if ((r1<0) || (r1>=nRows) || (r2<0)) return CIFRC_WrongIndex; 1186 k = GetTagNo ( TName ); 1187 if (k<0) return CIFRC_NoTag; 1188 if (!S) 1189 GetVectorMemory ( S,r2-r1+1,r1 ); 1190 if (Remove) { 1191 for (j=r1;j<=r2;j++) 1192 if (field[j]) { 1193 S[j] = field[j][k]; 1194 field[j][k] = NULL; 1195 if (S[j]) { 1196 if (S[j][0]==char(2)) { 1197 delete[] S[j]; 1198 S[j] = NULL; 1199 } 1200 } 1201 } else 1202 S[j] = NULL; 1203 } else { 1204 for (j=r1;j<=r2;j++) { 1205 S[j] = NULL; 1206 if (field[j]) { 1207 if (field[j][k]) { 1208 if (field[j][k][0]!=char(2)) 1209 CreateCopy ( S[j],field[j][k] ); 1210 } 1211 } 1212 } 1213 } 1214 return 0; 1215 } 1216 GetRVector(rvector & R,cpstr TName,int i1,int i2,bool Remove)1217 int Loop::GetRVector ( rvector & R, cpstr TName, 1218 int i1, int i2, bool Remove ) { 1219 int j,k,r1,r2,RC; 1220 pstr endptr; 1221 r1 = IMin(i1,i2); 1222 r2 = IMin(IMax(i1,i2),nRows-1); 1223 if ((r1<0) || (r1>=nRows) || (r2<0)) return CIFRC_WrongIndex; 1224 k = GetTagNo ( TName ); 1225 if (k<0) return CIFRC_NoTag; 1226 if (!R) 1227 GetVectorMemory ( R,r2-r1+1,r1 ); 1228 RC = 0; 1229 for (j=r1;j<=r2;j++) { 1230 R[j] = 0.0; 1231 if (field[j]) { 1232 if (field[j][k]) { 1233 R[j] = strtod ( field[j][k],&endptr ); 1234 if (endptr==field[j][k]) RC = CIFRC_WrongFormat; 1235 if (Remove) { 1236 delete[] field[j][k]; 1237 field[j][k] = NULL; 1238 } 1239 } 1240 } 1241 } 1242 return RC; 1243 } 1244 GetIVector(ivector & I,cpstr TName,int i1,int i2,bool Remove)1245 int Loop::GetIVector ( ivector & I, cpstr TName, 1246 int i1, int i2, bool Remove ) { 1247 int j,k,r1,r2,RC; 1248 pstr endptr; 1249 r1 = IMin(i1,i2); 1250 r2 = IMin(IMax(i1,i2),nRows-1); 1251 if ((r1<0) || (r1>=nRows) || (r2<0)) return CIFRC_WrongIndex; 1252 k = GetTagNo ( TName ); 1253 if (k<0) return CIFRC_NoTag; 1254 if (!I) 1255 GetVectorMemory ( I,r2-r1+1,r1 ); 1256 RC = 0; 1257 for (j=r1;j<=r2;j++) { 1258 I[j] = 0; 1259 if (field[j]) { 1260 if (field[j][k]) { 1261 I[j] = mround ( strtod(field[j][k],&endptr) ); 1262 if (endptr==field[j][k]) RC = CIFRC_WrongFormat; 1263 if (Remove) { 1264 delete[] field[j][k]; 1265 field[j][k] = NULL; 1266 } 1267 } 1268 } 1269 } 1270 return RC; 1271 } 1272 1273 PutString(cpstr S,cpstr T,int nrow)1274 void Loop::PutString ( cpstr S, cpstr T, int nrow ) { 1275 psmatrix field1; 1276 int nT,nR,iT,i,j; 1277 nT = nTags; 1278 nR = nRows; 1279 iT = AddTag ( T ); 1280 if (iT<0) iT = nTags-1; 1281 if (nTags>nT) { 1282 // a new tag has been added; all field must be reallocated. 1283 nRows = IMax(nR,nrow+1); // nrow is indexed like 0,1,... 1284 nAllocRows = IMax(nR,nrow+IMin(nR/2+1,2000)); 1285 field1 = new psvector[nAllocRows]; 1286 for (i=0;i<nR;i++) 1287 if (field[i]) { 1288 field1[i] = new pstr[nTags]; 1289 for (j=0;j<nT;j++) 1290 field1[i][j] = field[i][j]; 1291 for (j=nT;j<nTags;j++) 1292 field1[i][j] = NULL; 1293 delete[] field[i]; 1294 } else 1295 field1[i] = NULL; 1296 for (i=nR;i<nRows;i++) 1297 field1[i] = NULL; 1298 if (field) delete[] field; 1299 field = field1; 1300 } else if (nrow>=nR) { 1301 // only new rows are to be added 1302 ExpandRows ( nrow+1 ); 1303 nRows++; 1304 } 1305 if (!field[nrow]) { 1306 field[nrow] = new pstr[nTags]; 1307 for (j=0;j<nTags;j++) 1308 field[nrow][j] = NULL; 1309 } 1310 CreateCopy ( field[nrow][iT],S ); 1311 iColumn = iT+1; 1312 if (iColumn>=nTags) iColumn = 0; 1313 } 1314 1315 PutNoData(int NoDataType,cpstr T,int nrow)1316 void Loop::PutNoData ( int NoDataType, cpstr T, int nrow ) { 1317 char S[10]; 1318 S[0] = char(2); 1319 if (NoDataType==CIF_NODATA_DOT) S[1] = '.'; 1320 else S[1] = '?'; 1321 S[2] = char(0); 1322 PutString ( S,T,nrow ); 1323 } 1324 1325 PutReal(realtype R,cpstr T,int nrow,int prec)1326 void Loop::PutReal ( realtype R, cpstr T, int nrow, int prec ) { 1327 char rS[100]; 1328 sprintf ( rS,"%.*g",prec,R ); 1329 PutString ( rS,T,nrow ); 1330 } 1331 PutReal(realtype R,cpstr T,int nrow,cpstr format)1332 void Loop::PutReal ( realtype R, cpstr T, int nrow, 1333 cpstr format ) { 1334 char rS[100]; 1335 sprintf ( rS,format,R ); 1336 PutString ( DelSpaces(rS,' '),T,nrow ); 1337 } 1338 PutInteger(int I,cpstr T,int nrow)1339 void Loop::PutInteger ( int I, cpstr T, int nrow ) { 1340 char iS[100]; 1341 if (I>MinInt4) { 1342 sprintf ( iS,"%i",I ); 1343 PutString ( iS,T,nrow ); 1344 } else 1345 PutNoData ( CIF_NODATA_DOT,T,nrow ); 1346 } 1347 PutSVector(psvector S,cpstr T,int i1,int i2)1348 void Loop::PutSVector ( psvector S, cpstr T, int i1, int i2 ) { 1349 int i,j,k; 1350 PutString ( S[i2],T,i2 ); 1351 if (iColumn==0) k = nTags-1; 1352 else k = iColumn-1; 1353 for (i=i2-1;i>=i1;i--) { 1354 if (!field[i]) { 1355 field[i] = new pstr[nTags]; 1356 for (j=0;j<nTags;j++) 1357 field[i][j] = NULL; 1358 } 1359 CreateCopy ( field[i][k],S[i] ); 1360 } 1361 } 1362 PutRVector(rvector R,cpstr T,int i1,int i2,int prec)1363 void Loop::PutRVector ( rvector R, cpstr T, 1364 int i1, int i2, int prec ) { 1365 int i,j,k; 1366 char rS[100]; 1367 PutReal ( R[i2],T,i2,prec ); 1368 if (iColumn==0) k = nTags-1; 1369 else k = iColumn-1; 1370 for (i=i2-1;i>=i1;i--) { 1371 if (!field[i]) { 1372 field[i] = new pstr[nTags]; 1373 for (j=0;j<nTags;j++) 1374 field[i][j] = NULL; 1375 } 1376 sprintf ( rS,"%.*g",prec,R[i] ); 1377 CreateCopy ( field[i][k],rS ); 1378 } 1379 } 1380 PutIVector(ivector I,cpstr T,int i1,int i2)1381 void Loop::PutIVector ( ivector I, cpstr T, 1382 int i1, int i2 ) { 1383 int l,j,k; 1384 char iS[100]; 1385 PutInteger ( I[i2],T,i2 ); 1386 if (iColumn==0) k = nTags-1; 1387 else k = iColumn-1; 1388 for (l=i2-1;l>=i1;l--) { 1389 if (!field[l]) { 1390 field[l] = new pstr[nTags]; 1391 for (j=0;j<nTags;j++) 1392 field[l][j] = NULL; 1393 } 1394 sprintf ( iS,"%i",I[l] ); 1395 CreateCopy ( field[l][k],iS ); 1396 } 1397 } 1398 WriteMMCIFLoop(cpstr FName,io::GZ_MODE gzipMode)1399 bool Loop::WriteMMCIFLoop ( cpstr FName, io::GZ_MODE gzipMode ) { 1400 io::File f; 1401 f.assign ( FName,true,false,gzipMode ); 1402 if (f.rewrite()) { 1403 WriteMMCIF ( f ); 1404 f.shut(); 1405 return true; 1406 } else 1407 return false; 1408 } 1409 WriteMMCIF(io::RFile f)1410 void Loop::WriteMMCIF ( io::RFile f ) { 1411 int i,j,k,m,n; 1412 ivector l; 1413 pstr F; 1414 1415 // write loop keyword 1416 f.Write ( pstr("\nloop_\n") ); 1417 1418 GetVectorMemory ( l,nTags,0 ); 1419 k = 0; 1420 for (i=0;i<nTags;i++) { 1421 if (name[0]!=char(1)) { 1422 f.Write ( name ); 1423 f.Write ( pstr(".") ); 1424 } 1425 F = FirstOccurence ( tag[i],'\1' ); 1426 if (F) { 1427 *F = char(0); 1428 f.WriteLine ( tag[i] ); 1429 *F = '\1'; 1430 } else 1431 f.WriteLine ( tag[i] ); 1432 l[i] = 0; 1433 for (j=0;j<nRows;j++) 1434 if (field[j]) { 1435 if (field[j][i]) { 1436 F = field[j][i]; 1437 if (FirstOccurence(F,'\n') || strstr(F,"\" ")) 1438 l[i] = 10001; 1439 else if (F[0]==char(2)) l[i] = IMax(l[i],1); 1440 else if (((F[0]=='.') || (F[0]=='?')) && 1441 (!F[1])) l[i] = IMax(l[i],3); 1442 else { 1443 if (FirstOccurence(F,' ') || FirstOccurence(F,'"') || FirstOccurence(F,'\'')) 1444 m = 2; 1445 else m = 0; 1446 l[i] = IMax(l[i],strlen(F)+m); 1447 } 1448 } 1449 } 1450 l[i] = IMax(l[i],1); 1451 k += l[i]+1; 1452 if (k>_max_output_line_width) { 1453 l[i] = -l[i]; 1454 k = 0; 1455 } 1456 } 1457 for (i=0;i<nRows;i++) { 1458 m = 0; // counts symbols in the string 1459 k = 0; // rest of left-aligned fields to fill with spaces 1460 for (j=0;j<nTags;j++) { 1461 n = k; 1462 k = l[j]; // length of the field 1463 if (k<0) k = -k; 1464 m += k+1; 1465 if (m>_max_output_line_width) { 1466 f.LF(); 1467 m = k+1; 1468 } else 1469 while (n>0) { 1470 f.Write ( pstr(" ") ); 1471 n--; 1472 } 1473 if (field[i]) { 1474 if (field[i][j]) { 1475 F = field[i][j]; 1476 if (k>10000) { 1477 if (F[0]==char(2)) { 1478 f.Write ( pstr(" ") ); 1479 f.WriteLine ( &(F[1]) ); 1480 } else if (!F[0]) { 1481 f.Write ( pstr(" ") ); 1482 f.WriteLine ( NODATA_P ); 1483 } else { 1484 f.Write ( pstr(";") ); 1485 f.WriteLine ( F ); 1486 f.WriteLine ( pstr(";") ); 1487 } 1488 m = 0; 1489 k = 0; 1490 } else if ((((F[0]=='.') || 1491 (F[0]=='?')) && (!F[1])) || 1492 FirstOccurence(F,' ') || 1493 FirstOccurence(F,'"') || 1494 FirstOccurence(F,'\'')) { 1495 f.Write ( pstr(" \"") ); 1496 f.Write ( F ); 1497 f.Write ( pstr("\"") ); 1498 k -= strlen(F)+2; 1499 } else if (F[0]==char(2)) { 1500 f.Write ( pstr(" ") ); 1501 f.Write ( &(F[1]) ); 1502 k--; 1503 } else if (!F[0]) { 1504 f.Write ( pstr(" ") ); 1505 f.Write ( NODATA_P ); 1506 k--; 1507 } else { 1508 f.Write ( pstr(" ") ); 1509 f.Write ( F ); 1510 k -= strlen(F); 1511 } 1512 } else { 1513 f.Write ( pstr(" ") ); 1514 f.Write ( NODATA_Q ); 1515 k--; 1516 } 1517 } else { 1518 f.Write ( pstr(" ") ); 1519 f.Write ( NODATA_Q ); 1520 k--; 1521 } 1522 } 1523 if (m) f.LF(); 1524 } 1525 f.WriteLine ( pstr("#") ); 1526 1527 } 1528 1529 Copy(PCategory Loop)1530 void Loop::Copy ( PCategory Loop ) { 1531 int i,j; 1532 Category::Copy ( Loop ); 1533 nRows = PLoop(Loop)->nRows; 1534 nAllocRows = nRows; 1535 if ((nTags>0) && (nRows>0)) { 1536 field = new psvector[nRows]; 1537 for (i=0;i<nRows;i++) { 1538 if (PLoop(Loop)->field[i]) { 1539 field[i] = new pstr[nTags]; 1540 for (j=0;j<nTags;j++) { 1541 field[i][j] = NULL; 1542 CreateCopy ( field[i][j],PLoop(Loop)->field[i][j] ); 1543 } 1544 } else 1545 field[i] = NULL; 1546 } 1547 } 1548 iColumn = PLoop(Loop)->iColumn; 1549 } 1550 1551 write(io::RFile f)1552 void Loop::write ( io::RFile f ) { 1553 int i,j; 1554 Category::write ( f ); 1555 f.WriteInt ( &nRows ); 1556 if ((nTags>0) && (nRows>0)) { 1557 for (i=0;i<nRows;i++) { 1558 if (field[i]) { 1559 j = 1; 1560 f.WriteInt ( &j ); 1561 for (j=0;j<nTags;j++) 1562 f.CreateWrite ( field[i][j] ); 1563 } else { 1564 j = 0; 1565 f.WriteInt ( &j ); 1566 } 1567 } 1568 } 1569 f.WriteInt ( &iColumn ); 1570 } 1571 read(io::RFile f)1572 void Loop::read ( io::RFile f ) { 1573 int i,j; 1574 Category::read ( f ); 1575 f.ReadInt ( &nRows ); 1576 nAllocRows = nRows; 1577 if ((nTags>0) && (nRows>0)) { 1578 field = new psvector[nRows]; 1579 for (i=0;i<nRows;i++) { 1580 f.ReadInt ( &j ); 1581 if (j) { 1582 field[i] = new pstr[nTags]; 1583 for (j=0;j<nTags;j++) { 1584 field[i][j] = NULL; 1585 f.CreateRead ( field[i][j] ); 1586 } 1587 } else 1588 field[i] = NULL; 1589 } 1590 } 1591 f.ReadInt ( &iColumn ); 1592 } 1593 1594 MakeStreamFunctions(Loop)1595 MakeStreamFunctions(Loop) 1596 1597 1598 1599 // ====================== Data ============================= 1600 1601 1602 Data::Data() : io::Stream() { 1603 InitData(); 1604 } 1605 Data(cpstr N)1606 Data::Data ( cpstr N ) : io::Stream() { 1607 InitData(); 1608 CreateCopy ( name,N ); 1609 } 1610 Data(io::RPStream Object)1611 Data::Data ( io::RPStream Object ) : io::Stream(Object) { 1612 InitData(); 1613 } 1614 ~Data()1615 Data::~Data() { 1616 FreeMemory(0); 1617 } 1618 InitData()1619 void Data::InitData() { 1620 name = NULL; 1621 nCategories = 0; 1622 Category = NULL; 1623 index = NULL; 1624 flags = 0; 1625 Warning = 0; 1626 loopNo = 0; 1627 tagNo = 0; 1628 WrongCat = NULL; 1629 WrongTag = NULL; 1630 nWrongFields = 0; 1631 } 1632 FreeMemory(int key)1633 void Data::FreeMemory ( int key ) { 1634 int i; 1635 if (name) delete[] name; 1636 name = NULL; 1637 if (Category) { 1638 for (i=0;i<nCategories;i++) 1639 if (Category[i]) delete Category[i]; 1640 delete[] Category; 1641 Category = NULL; 1642 } 1643 nCategories = 0; 1644 FreeVectorMemory ( index,0 ); 1645 if (key==0) FreeWrongFields(); 1646 } 1647 FreeWrongFields()1648 void Data::FreeWrongFields() { 1649 int i; 1650 if (WrongCat) { 1651 for (i=0;i<nWrongFields;i++) 1652 if (WrongCat[i]) delete[] WrongCat[i]; 1653 delete[] WrongCat; 1654 } 1655 if (WrongTag) { 1656 for (i=0;i<nWrongFields;i++) 1657 if (WrongTag[i]) delete[] WrongTag[i]; 1658 delete[] WrongTag; 1659 } 1660 WrongCat = NULL; 1661 WrongTag = NULL; 1662 nWrongFields = 0; 1663 } 1664 1665 SetPrintWarnings(bool SPW)1666 void Data::SetPrintWarnings ( bool SPW ) { 1667 if (SPW) SetFlag ( CIFFL_PrintWarnings ); 1668 else RemoveFlag ( CIFFL_PrintWarnings ); 1669 } 1670 SetStopOnWarning(bool SOW)1671 void Data::SetStopOnWarning ( bool SOW ) { 1672 if (SOW) SetFlag ( CIFFL_StopOnWarnings ); 1673 else RemoveFlag ( CIFFL_StopOnWarnings ); 1674 } 1675 SetFlag(CIF_FLAG F)1676 void Data::SetFlag ( CIF_FLAG F ) { 1677 flags |= F; 1678 } 1679 RemoveFlag(CIF_FLAG F)1680 void Data::RemoveFlag ( CIF_FLAG F ) { 1681 flags &= ~F; 1682 } 1683 SetWrongFields(cpstr * cats,cpstr * tags)1684 void Data::SetWrongFields ( cpstr *cats, cpstr *tags ) { 1685 int i,lc,lt; 1686 FreeWrongFields(); 1687 if ((!cats) || (!tags)) return; 1688 lc = 0; 1689 while (cats[lc]) lc++; 1690 lt = 0; 1691 while (tags[lt]) lt++; 1692 nWrongFields = IMax(lc,lt); 1693 if (nWrongFields>0) { 1694 WrongCat = new pstr[nWrongFields]; 1695 WrongTag = new pstr[nWrongFields]; 1696 for (i=0;i<nWrongFields;i++) { 1697 WrongCat[i] = NULL; 1698 WrongTag[i] = NULL; 1699 if (cats[i]) { 1700 if (cats[i][0]) CreateCopy ( WrongCat[i],cats[i] ); 1701 } 1702 if (!WrongCat[i]) { 1703 CreateCopy ( WrongCat[i],pstr(" ") ); 1704 WrongCat[i][0] = char(1); 1705 } 1706 if (tags[i]) CreateCopy ( WrongTag[i],tags[i] ); 1707 else CreateCopy ( WrongTag[i],pstr("") ); 1708 } 1709 } 1710 } 1711 CheckWrongField(cpstr C,cpstr T)1712 bool Data::CheckWrongField ( cpstr C, cpstr T ) { 1713 int i; 1714 for (i=0;i<nWrongFields;i++) 1715 if ((!strcasecmp(C,WrongCat[i])) && 1716 (!strcasecmp(T,WrongTag[i]))) return true; 1717 return false; 1718 } 1719 1720 #define _max_buf_len 500 1721 1722 static char _err_string[_max_buf_len+1]; 1723 static int _err_line; 1724 1725 ReadMMCIFData(cpstr FName,io::GZ_MODE gzipMode)1726 int Data::ReadMMCIFData ( cpstr FName, io::GZ_MODE gzipMode ) { 1727 io::File f; 1728 char S[_max_buf_len+1]; 1729 int RC,lcount; 1730 f.assign ( FName,true,false,gzipMode ); 1731 if (f.reset(true)) { 1732 S[0] = char(0); 1733 lcount = 0; 1734 RC = ReadMMCIFData ( f,S,lcount ); 1735 f.shut(); 1736 return RC; 1737 } else { 1738 _err_string[0] = char(0); 1739 _err_line = 0; 1740 Warning = CIFRC_CantOpenFile; 1741 return CIFRC_CantOpenFile; 1742 } 1743 } 1744 1745 1746 // --------------- General I/O functions 1747 ReadMMCIFData(io::RFile f,pstr S,int & lcount)1748 int Data::ReadMMCIFData ( io::RFile f, pstr S, int & lcount ) { 1749 pstr p; 1750 int i,llen; 1751 pstr L; 1752 1753 FreeMemory(1); 1754 Warning = 0; 1755 loopNo = 0; 1756 tagNo = 0; 1757 1758 // 1. Look for 'data_' tag 1759 do { 1760 p = &(S[0]); 1761 while ((*p==' ') || (*p==char(9))) p++; 1762 if (strncmp(p,"data_",5)) { 1763 f.ReadLine ( S,_max_buf_len ); 1764 lcount++; 1765 p = NULL; 1766 } 1767 } while ((!p) && (!f.FileEnd())); 1768 1769 if (!p) { 1770 strcpy ( _err_string,S ); 1771 _err_line = lcount; 1772 if (flags & CIFFL_PrintWarnings) 1773 printf ( "\n **** mmCIF READ ERROR " 1774 "<<line %i: no 'data_XXXX' tag found>>\n",lcount ); 1775 return CIFRC_NoDataLine; 1776 } 1777 1778 llen = _max_buf_len; 1779 L = new char[llen]; 1780 i = 0; 1781 p += 5; 1782 while ((*p) && (*p!=' ') && (*p!=char(9))) { 1783 L[i++] = *p; 1784 p++; 1785 } 1786 L[i] = char(0); 1787 CreateCopy ( name,L ); 1788 1789 1790 // 2. Loop over tags until next 'data_' or end of file 1791 1792 while (p) { 1793 1794 // skip spaces 1795 while ((*p==' ') || (*p==char(9))) p++; 1796 1797 if ((*p) && (*p!='#')) { // this is not a comment, continue 1798 if (*p=='_') 1799 GetDataItem ( f,S,L,p,lcount,llen ); 1800 else if (!strncmp(p,"loop_",5)) 1801 GetLoop ( f,S,L,p,lcount,llen ); 1802 else if (!strncmp(p,"data_",5)) { 1803 p = NULL; 1804 break; 1805 } else { 1806 // if got to here, the file is corrupted 1807 strcpy ( _err_string,S ); 1808 _err_line = lcount; 1809 Warning |= CIFW_UnrecognizedItems; 1810 if (flags & CIFFL_PrintWarnings) 1811 printf ( "\n **** mmCIF READ WARNING " 1812 "<<line %i: unrecognized string>>\n%s\n", 1813 lcount,S ); 1814 while ((*p) && (*p!=' ') && (*p!=char(9))) 1815 if (*p=='#') *p = char(0); 1816 else p++; 1817 } 1818 } else 1819 *p = char(0); 1820 1821 if (Warning && (flags & CIFFL_StopOnWarnings)) { 1822 if (L) delete[] L; 1823 return Warning; 1824 } 1825 1826 if (!(*p)) { 1827 if (!f.FileEnd()) { 1828 f.ReadLine ( S,_max_buf_len ); 1829 lcount++; 1830 p = &(S[0]); 1831 } else 1832 p = NULL; 1833 } 1834 1835 } 1836 1837 if (L) delete[] L; 1838 1839 Optimize(); // get rid of over-allocated fields. 1840 1841 return Warning; 1842 1843 } 1844 1845 GetDataItem(io::RFile f,pstr S,pstr & L,pstr & p,int & lcount,int & llen)1846 void Data::GetDataItem ( io::RFile f, pstr S, pstr & L, 1847 pstr & p, int & lcount, int & llen ) { 1848 PStruct cifStruct; 1849 char T[100]; 1850 int RC,i; 1851 1852 i = 0; 1853 while ((*p) && (*p!=' ') && (*p!=char(9)) && (*p!='.')) { 1854 if (i<(int)sizeof(T)-1) T[i++] = *p; 1855 p++; 1856 } 1857 T[i] = char(0); 1858 1859 if (*p!='.') { // category name missing 1860 strcpy ( L,T ); // item name 1861 T[0] = char(1); // special 1862 T[1] = char(0); // category name 1863 } 1864 1865 // look for category 1866 i = AddCategory ( T ); 1867 if (i<0) { 1868 // negative value means that the category was not in the list, 1869 // but a place for it has been provided and index updated 1870 cifStruct = new Struct ( T ); 1871 Category[nCategories-1] = cifStruct; 1872 } else { 1873 cifStruct = PStruct(Category[i]); 1874 if (cifStruct->GetCategoryID()!=MMCIF_Struct) { 1875 strcpy ( _err_string,S ); 1876 _err_line = lcount; 1877 Warning |= CIFW_NotAStructure; 1878 if (flags & CIFFL_PrintWarnings) 1879 printf ( "\n **** mmCIF READ WARNING " 1880 "<<line %i: %s was a loop -- replaced>>\n%s\n", 1881 lcount,T,S ); 1882 delete Category[i]; 1883 cifStruct = new Struct ( T ); 1884 Category[i] = cifStruct; 1885 } 1886 } 1887 1888 if (*p=='.') { // get item name 1889 i = 0; 1890 p++; // skip period 1891 while ((*p) && (*p!=' ') && (*p!=char(9))) { 1892 T[i++] = *p; 1893 p++; 1894 } 1895 T[i] = char(0); 1896 } else 1897 strcpy ( T,L ); 1898 1899 if (nWrongFields>0) { 1900 if (CheckWrongField(cifStruct->name,T)) { 1901 GetField ( f,S,L,p,lcount,llen ); 1902 cifStruct->DeleteField ( T ); 1903 return; 1904 } 1905 } 1906 1907 RC = GetField ( f,S,L,p,lcount,llen ); 1908 1909 if (RC) { 1910 strcpy ( _err_string,S ); 1911 _err_line = lcount; 1912 Warning |= CIFW_MissingField; 1913 if (flags & CIFFL_PrintWarnings) 1914 printf ( "\n **** mmCIF READ WARNING " 1915 "<<line %i: expected data field missing>>\n%s\n", 1916 lcount,S ); 1917 } 1918 1919 while ((*p==' ') || (*p==char(9))) p++; 1920 if (*p=='#') *p = char(0); 1921 1922 i = cifStruct->GetTagNo ( T ); 1923 if (i>=0) { 1924 if (flags & CIFFL_SuggestTags) { 1925 tagNo++; 1926 ParamStr ( T,pstr("\1"),tagNo ); 1927 } else { 1928 strcpy ( _err_string,S ); 1929 _err_line = lcount; 1930 Warning |= CIFW_DuplicateTag; 1931 if (flags & CIFFL_PrintWarnings) 1932 printf ( "\n **** mmCIF READ WARNING " 1933 "<<line %i: duplicated tag>>\n%s\n",lcount,S ); 1934 } 1935 } 1936 cifStruct->AddField ( L,T ); 1937 1938 } 1939 GetLoop(io::RFile f,pstr S,pstr & L,pstr & p,int & lcount,int & llen)1940 void Data::GetLoop ( io::RFile f, pstr S, pstr & L, 1941 pstr & p, int & lcount, int & llen ) { 1942 PLoop cifLoop; 1943 pstr p1; 1944 char T[100]; 1945 bool Repeat,WrongField; 1946 int RC,i,nC; 1947 1948 RC = 0; 1949 1950 p += 5; // skip 'loop_' tag 1951 1952 loopNo++; 1953 cifLoop = NULL; 1954 nC = -1; // undefined category number 1955 do { 1956 1957 while ((*p==' ') || (*p==char(9))) p++; 1958 p1 = p; 1959 1960 if (*p=='_') { 1961 1962 // get category name 1963 i = 0; 1964 while ((*p) && (*p!=' ') && (*p!=char(9)) && (*p!='.')) { 1965 if (i<(int)sizeof(T)-1) T[i++] = *p; 1966 p++; 1967 } 1968 T[i] = char(0); 1969 1970 if (*p!='.') { // category name missing 1971 strcpy ( L,T ); // item name 1972 if (flags & CIFFL_SuggestCategories) 1973 sprintf ( T,"X%i",loopNo ); 1974 else strcpy ( T,"X" ); 1975 T[0] = char(1); // special category name 1976 } 1977 1978 if (cifLoop) { 1979 if (strcmp(cifLoop->GetCategoryName(),T)) { 1980 // loop ended, empty 1981 p = p1; // play back to last category 1982 cifLoop = NULL; 1983 } 1984 } else { 1985 // look for category 1986 i = AddCategory ( T ); 1987 if ((i!=nC) && (nC>=0)) { // empty loop; most probably 1988 // a corrupted file 1989 p = p1; // play back to last category 1990 strcpy ( _err_string,S ); 1991 _err_line = lcount; 1992 Warning |= CIFW_EmptyLoop; 1993 if (flags & CIFFL_PrintWarnings) 1994 printf ( "\n **** mmCIF READ WARNING " 1995 "<<line %i: empty loop>>\n%s\n",lcount,S ); 1996 // AddCategory(..) has added a NULL-Category on the top of 1997 // category list; remove it now 1998 DeleteCategory ( nCategories-1 ); 1999 cifLoop = NULL; 2000 // return; 2001 } 2002 if (i<0) { 2003 // negative value means that the category was not in the list, 2004 // but a place for it has been provided and index updated 2005 cifLoop = new Loop ( T ); 2006 Category[nCategories-1] = cifLoop; 2007 nC = nCategories-1; 2008 } 2009 } 2010 /* 2011 else if (Loop) { 2012 if (!strcmp(Loop->GetCategoryName(), 2013 Category[i]->GetCategoryName())) { 2014 if (Loop->GetCategoryID()!=MMCIF_Loop) { 2015 Warning |= CIFW_NotALoop; 2016 if (flags & CIFFL_PrintWarnings) 2017 printf ( "\n **** mmCIF READ WARNING " 2018 "<<line %i: %s was a structure --" 2019 " replaced>>\n%s\n",lcount,T,S ); 2020 delete Category[i]; 2021 Loop = new Loop ( T ); 2022 Category[i] = Loop; 2023 } 2024 } else 2025 Loop = NULL; 2026 } 2027 */ 2028 if (cifLoop) { 2029 2030 if (*p=='.') { // get item name 2031 i = 0; 2032 p++; // skip period 2033 while ((*p) && (*p!=' ') && (*p!=char(9))) { 2034 T[i++] = *p; 2035 p++; 2036 } 2037 T[i] = char(0); 2038 } else 2039 strcpy ( T,L ); 2040 2041 if (nWrongFields>0) 2042 WrongField = CheckWrongField ( cifLoop->name,T ); 2043 else WrongField = false; 2044 2045 if (!WrongField) { 2046 if (cifLoop->AddTag(T)>=0) { 2047 if (flags & CIFFL_SuggestTags) { 2048 tagNo++; 2049 ParamStr ( T,pstr("\1"),tagNo ); 2050 cifLoop->AddTag(T); 2051 } else { 2052 strcpy ( _err_string,S ); 2053 _err_line = lcount; 2054 Warning |= CIFW_DuplicateTag; 2055 if (flags & CIFFL_PrintWarnings) 2056 printf ( "\n **** mmCIF READ WARNING " 2057 "<<line %i: duplicate tag>>\n%s\n",lcount,S ); 2058 } 2059 } 2060 } 2061 Repeat = true; 2062 2063 } else { 2064 2065 p = p1; 2066 Repeat = false; 2067 2068 } 2069 2070 } else if (!(*p) || (*p=='#')) { 2071 Repeat = !f.FileEnd(); 2072 if (Repeat) { 2073 f.ReadLine ( S,_max_buf_len ); 2074 lcount++; 2075 p = &(S[0]); 2076 } else { 2077 strcpy ( _err_string,S ); 2078 _err_line = lcount; 2079 Warning |= CIFW_UnexpectedEOF; 2080 if (flags & CIFFL_PrintWarnings) 2081 printf ( "\n **** mmCIF READ WARNING " 2082 "<<line %i: unexpected end of file>>\n%s\n", 2083 lcount,S ); 2084 } 2085 } else 2086 Repeat = false; 2087 2088 } while (Repeat); 2089 2090 if (cifLoop) { 2091 do { 2092 while ((*p==' ') || (*p==char(9))) p++; 2093 if (!(*p) || (*p=='#')) { 2094 Repeat = !f.FileEnd(); 2095 if (Repeat) { 2096 f.ReadLine ( S,_max_buf_len ); 2097 lcount++; 2098 p = &(S[0]); 2099 } 2100 } else if (*p=='_') Repeat = false; 2101 else if (!strncmp(p,"loop_",5)) Repeat = false; 2102 else if (!strncmp(p,"data_",5)) Repeat = false; 2103 else if (!strncmp(p,"stop_",5)) { 2104 p += 5; 2105 Repeat = false; 2106 } else { 2107 RC = GetField ( f,S,L,p,lcount,llen ); 2108 if (!RC) { 2109 cifLoop->AddString ( L ); 2110 Repeat = true; 2111 } else 2112 Repeat = false; 2113 } 2114 } while (Repeat); 2115 if ((cifLoop->iColumn!=0) || (RC)) { 2116 strcpy ( _err_string,S ); 2117 _err_line = lcount; 2118 Warning |= CIFW_LoopFieldMissing; 2119 if (flags & CIFFL_PrintWarnings) 2120 printf ( "\n **** mmCIF READ WARNING " 2121 "<<line %i: expected loop field missing>>\n%s\n", 2122 lcount,S ); 2123 } 2124 } 2125 2126 } 2127 GetField(io::RFile f,pstr S,pstr & L,pstr & p,int & lcount,int & llen)2128 int Data::GetField ( io::RFile f, pstr S, pstr & L, 2129 pstr & p, int & lcount, int & llen ) { 2130 bool Repeat; 2131 pstr L1; 2132 int i,flen; 2133 char c; 2134 2135 flen = 0; 2136 L[flen] = char(0); 2137 2138 do { 2139 2140 // skip all spaces before the field 2141 while ((*p==' ') || (*p==char(9))) p++; 2142 2143 if ((*p=='#') || (!(*p))) { 2144 // comment or end of line met; the field should be 2145 // found on the next line 2146 Repeat = !f.FileEnd(); 2147 if (Repeat) { 2148 // take the next line 2149 f.ReadLine ( S,_max_buf_len ); 2150 lcount++; 2151 p = &(S[0]); 2152 Repeat = (*p!=';'); 2153 } else { 2154 // end of file and the field is not taken 2155 L[0] = char(0); 2156 return 1; 2157 } 2158 } else 2159 // first symbol of a field is found 2160 Repeat = false; 2161 2162 } while (Repeat); 2163 2164 2165 if (*p==';') { // this is a multiline field 2166 p++; 2167 strcpy ( L,p ); // take first line of the field 2168 flen = strlen(L); 2169 while (!f.FileEnd()) { 2170 f.ReadLine ( S,_max_buf_len ); 2171 lcount++; 2172 p = &(S[0]); 2173 if (*p==';') { // multiline field terminated 2174 p++; 2175 while ((*p==' ') || (*p==char(9))) p++; 2176 return 0; 2177 } else { // multiline field continues -- take next line 2178 flen += strlen(S)+2; 2179 if (flen>=llen) { 2180 llen = flen + IMin(2000,llen); 2181 L1 = new char[llen]; 2182 strcpy ( L1,L ); 2183 delete[] L; 2184 L = L1; 2185 } 2186 strcat ( L,"\n" ); 2187 strcat ( L,S ); 2188 } 2189 } 2190 2191 // end of file -- take the last line of the multiline field 2192 p = &(S[strlen(S)]); 2193 2194 } else { 2195 2196 i = 0; 2197 if (*p!='_') { 2198 if ((*p=='\'') || (*p=='"')) { 2199 c = *p; 2200 // field in quotation marks 2201 do { 2202 p++; 2203 // stop taking characters either on end of line 2204 // or the quotation mark 2205 while ((*p) && (*p!=c)) { 2206 L[i++] = *p; 2207 p++; 2208 } 2209 while (*p==c) { 2210 // it was a quotation mark -- check that it is followed 2211 // by end of line or space 2212 p++; 2213 if ((*p) && (*p!=' ') && (*p!=char(9))) { 2214 // the quotation mark is not a field terminator and 2215 // belongs to the field. 2216 L[i++] = c; // take the quotation mark 2217 if (*p!=c) // take the non-space character 2218 L[i++] = *p; // but check for field terminator 2219 } 2220 } 2221 // terminate the loop only on space or end of line 2222 } while ((*p) && (*p!=' ') && (*p!=char(9))); 2223 if (*p) p++; 2224 L[i] = char(0); 2225 } else { 2226 // a simplest field without spaces 2227 while ((*p) && (*p!=' ') && (*p!=char(9))) { 2228 L[i++] = *p; 2229 p++; 2230 } 2231 L[i] = char(0); 2232 if (((L[0]=='.') || (L[0]=='?')) && (!L[1])) { 2233 // "no data" tokens 2234 L[1] = L[0]; 2235 L[0] = char(2); 2236 L[2] = char(0); 2237 } 2238 } 2239 } 2240 2241 } 2242 2243 return 0; 2244 2245 } 2246 Sort()2247 void Data::Sort() { 2248 int i,k; 2249 psvector cnames; 2250 2251 k = 0; 2252 for (i=0;i<nCategories;i++) 2253 if (Category[i]) { 2254 if (k<i) Category[k] = Category[i]; 2255 k++; 2256 } 2257 for (i=k;i<nCategories;i++) 2258 Category[i] = NULL; 2259 nCategories = k; 2260 2261 FreeVectorMemory ( index ,0 ); 2262 GetVectorMemory ( cnames,nCategories,0 ); 2263 GetVectorMemory ( index ,nCategories,0 ); 2264 2265 for (i=0;i<nCategories;i++) { 2266 Category[i]->Sort(); 2267 cnames[i] = NULL; 2268 CreateCopy ( cnames[i],Category[i]->name ); 2269 } 2270 2271 SortTags ( cnames,nCategories,index ); 2272 2273 for (i=0;i<nCategories;i++) 2274 if (cnames[i]) delete[] cnames[i]; 2275 2276 if (cnames) delete[] cnames; 2277 2278 } 2279 GetCategoryNo(cpstr cname)2280 int Data::GetCategoryNo ( cpstr cname ) { 2281 // Binary search for index of category cname in Category[]. 2282 // Return: 2283 // >=0 : position of the category found 2284 // <0 : the category was not found, it could be inserted before 2285 // (-RC-1)th element, where RC is the return value 2286 int l1,l2,l,k; 2287 2288 if ((!Category) || (nCategories<1)) return -1; 2289 2290 if (!index) Sort(); 2291 2292 if (cname[0]) { 2293 l = 0; 2294 l1 = 0; 2295 l2 = nCategories-1; 2296 k = 1; 2297 while (l1<l2-1) { 2298 l = (l1+l2)/2; 2299 k = strcasecmp ( cname,Category[index[l]]->name ); 2300 if (k<0) l2 = l; 2301 else if (k>0) l1 = l; 2302 else { 2303 l1 = l; 2304 break; 2305 } 2306 } 2307 if (k==0) return index[l]; // is at RCth position 2308 k = strcasecmp(cname,Category[index[l1]]->name); 2309 if (k==0) return index[l1]; // is at RCth position 2310 if (k<0) return -1; // would be at (-RC-1)th position 2311 if (l2!=l1) { 2312 k = strcasecmp(cname,Category[index[l2]]->name); 2313 if (k==0) return index[l2]; // is at RCth position 2314 if (k>0) return -2-l2; // would be at l2+1=(-RC-1)th position 2315 } 2316 return -2-l1; // would be at l1+1=(-RC-1)th position 2317 } else 2318 // 'root' category should be always on top 2319 if (Category[index[0]]->name[0]==char(1)) return index[0]; 2320 2321 return -1; 2322 2323 } 2324 AddCategory(cpstr cname)2325 int Data::AddCategory ( cpstr cname ) { 2326 // return -1: a place for category has been added on the top of array; 2327 // index is added and sorted automatically 2328 // >=0: the category is already in the array -- its position 2329 // is returned 2330 int l1,l; 2331 PPCategory Category1; 2332 ivector index1; 2333 2334 2335 if (!Category) { 2336 Category = new PCategory[1]; 2337 Category[0] = NULL; 2338 GetVectorMemory ( index,1,0 ); 2339 index[0] = 0; 2340 nCategories = 1; 2341 return -nCategories; // the category has been added on the top of array 2342 } 2343 l1 = GetCategoryNo ( cname ); 2344 if (l1>=0) return l1; // non-negative returns mean that 2345 // the category is already in the array 2346 l1 = -l1-1; // otherwise the category has to be added and indexed at here 2347 // put new NULL-category on the top of array and update the index 2348 Category1 = new PCategory[nCategories+1]; 2349 GetVectorMemory ( index1,nCategories+1,0 ); 2350 for (l=0;l<nCategories;l++) 2351 Category1[l] = Category[l]; 2352 Category1[nCategories] = NULL; 2353 for (l=0;l<l1;l++) 2354 index1[l] = index[l]; 2355 index1[l1] = nCategories; 2356 for (l=l1+1;l<=nCategories;l++) 2357 index1[l] = index[l-1]; 2358 delete[] Category; 2359 FreeVectorMemory ( index,0 ); 2360 Category = Category1; 2361 index = index1; 2362 nCategories++; 2363 return -nCategories; // the category has been added on 2364 // the top of array 2365 } 2366 WriteMMCIFData(cpstr FName,io::GZ_MODE gzipMode)2367 bool Data::WriteMMCIFData ( cpstr FName, io::GZ_MODE gzipMode ) { 2368 io::File f; 2369 f.assign ( FName,true,false,gzipMode ); 2370 if (f.rewrite()) { 2371 WriteMMCIF ( f ); 2372 f.shut(); 2373 return true; 2374 } else 2375 return false; 2376 } 2377 WriteMMCIF(io::RFile f)2378 void Data::WriteMMCIF ( io::RFile f ) { 2379 int i; 2380 2381 if (name) { 2382 f.Write ( pstr("\ndata_") ); 2383 f.WriteLine ( name ); 2384 } else 2385 f.WriteLine ( pstr("\ndata_") ); 2386 2387 for (i=0;i<nCategories;i++) 2388 if (Category[i]) 2389 Category[i]->WriteMMCIF ( f ); 2390 2391 } 2392 2393 2394 // --------------- Retrieving data 2395 DeleteCategory(cpstr CName)2396 int Data::DeleteCategory ( cpstr CName ) { 2397 int k; 2398 k = GetCategoryNo ( CName ); 2399 if (k<0) return CIFRC_NoCategory; 2400 return DeleteCategory ( k ); 2401 } 2402 DeleteCategory(int CatNo)2403 int Data::DeleteCategory ( int CatNo ) { 2404 int i; 2405 if (Category[CatNo]) delete Category[CatNo]; 2406 for (i=CatNo+1;i<nCategories;i++) 2407 Category[i-1] = Category[i]; 2408 i = 0; 2409 while ((i<nCategories) && (index[i]!=CatNo)) { 2410 if (index[i]>CatNo) index[i]--; 2411 i++; 2412 } 2413 i++; 2414 while (i<nCategories) { 2415 if (index[i]>CatNo) index[i]--; 2416 index[i-1] = index[i]; 2417 i++; 2418 } 2419 nCategories--; 2420 index [nCategories] = 0; 2421 Category[nCategories] = NULL; 2422 return 0; 2423 } 2424 DeleteStructure(cpstr CName)2425 int Data::DeleteStructure ( cpstr CName ) { 2426 int k; 2427 k = GetCategoryNo ( CName ); 2428 if (k<0) return CIFRC_NoCategory; 2429 if (Category[k]->GetCategoryID()==MMCIF_Struct) 2430 return DeleteCategory ( k ); 2431 else return CIFRC_NotAStructure; 2432 } 2433 DeleteLoop(cpstr CName)2434 int Data::DeleteLoop ( cpstr CName ) { 2435 int k; 2436 k = GetCategoryNo ( CName ); 2437 if (k<0) return CIFRC_NoCategory; 2438 if (Category[k]->GetCategoryID()==MMCIF_Loop) 2439 return DeleteCategory ( k ); 2440 else return CIFRC_NotALoop; 2441 } 2442 GetCategory(int categoryNo)2443 PCategory Data::GetCategory ( int categoryNo ) { 2444 if ((categoryNo>=0) && (categoryNo<nCategories)) 2445 return Category[categoryNo]; 2446 return NULL; 2447 } 2448 GetStructure(cpstr CName)2449 PStruct Data::GetStructure ( cpstr CName ) { 2450 int i; 2451 i = GetCategoryNo ( CName ); 2452 if (i<0) return NULL; 2453 if (Category[i]->GetCategoryID()==MMCIF_Struct) 2454 return PStruct(Category[i]); 2455 else return NULL; 2456 } 2457 GetLoop(cpstr CName)2458 PLoop Data::GetLoop ( cpstr CName ) { 2459 int i; 2460 i = GetCategoryNo ( CName ); 2461 if (i<0) return NULL; 2462 if (Category[i]->GetCategoryID()==MMCIF_Loop) 2463 return PLoop(Category[i]); 2464 else return NULL; 2465 } 2466 FindLoop(cpstr * tagList)2467 PLoop Data::FindLoop ( cpstr * tagList ) { 2468 int i; 2469 for (i=0;i<nCategories;i++) 2470 if (Category[i]) { 2471 if (Category[i]->GetCategoryID()==MMCIF_Loop) { 2472 if (Category[i]->CheckTags(tagList)) 2473 return PLoop(Category[i]); 2474 } 2475 } 2476 return NULL; 2477 } 2478 GetDataName(pstr & dname,bool Remove)2479 void Data::GetDataName ( pstr & dname, bool Remove ) { 2480 if (Remove) { 2481 if (dname) delete[] dname; 2482 dname = name; 2483 name = NULL; 2484 } else 2485 CreateCopy ( dname,name ); 2486 } 2487 CheckData(cpstr CName,cpstr TName)2488 int Data::CheckData ( cpstr CName, cpstr TName ) { 2489 // CheckData(..) returns positive value if the field is in the 2490 // file: 2491 // CIFRC_Structure category CName is a structure 2492 // CIFRC_Loop category CName is a loop 2493 // Negative returns mean: 2494 // CIFRC_StructureNoTag category CName is present, 2495 // it is a structure, but it does not 2496 // have tag TName 2497 // CIFRC_LoopNoTag category CName is present, 2498 // it is a loop, but it does not have 2499 // tag TName 2500 // CIFRC_NoCategory category CName is not present. 2501 // If TName is set to NULL then only the CName is checked and 2502 // possible returns are CIFRC_Structure, CIFRC_Loop and 2503 // CIFRC_NoCategory. 2504 int i,k; 2505 i = GetCategoryNo ( CName ); 2506 if (i<0) return CIFRC_NoCategory; 2507 if (Category[i]->GetCategoryID()==MMCIF_Struct) 2508 k = CIFRC_Structure; 2509 else k = CIFRC_Loop; 2510 if (TName) { 2511 if (Category[i]->GetTagNo(TName)<0) { 2512 if (k==CIFRC_Structure) 2513 k = CIFRC_StructureNoTag; 2514 else k = CIFRC_LoopNoTag; 2515 } 2516 } 2517 return k; 2518 } 2519 Optimize()2520 void Data::Optimize() { 2521 int i,k; 2522 PPCategory C1; 2523 k = 0; 2524 for (i=0;i<nCategories;i++) 2525 if (Category[i]) { 2526 Category[i]->Optimize(); 2527 if (Category[i]->nTags<=0) { 2528 delete Category[i]; 2529 Category[i] = NULL; 2530 } else 2531 k++; 2532 } 2533 if (k>0) { 2534 if (k!=nCategories) { 2535 C1 = new PCategory[k]; 2536 k = 0; 2537 for (i=0;i<nCategories;i++) 2538 if (Category[i]) 2539 C1[k++] = Category[i]; 2540 if (Category) delete[] Category; 2541 Category = C1; 2542 nCategories = k; 2543 FreeVectorMemory ( index,0 ); 2544 Sort(); 2545 } 2546 } else { 2547 if (Category) delete[] Category; 2548 Category = NULL; 2549 nCategories = 0; 2550 } 2551 } 2552 GetString(pstr & Dest,cpstr CName,cpstr TName,bool Remove)2553 int Data::GetString ( pstr & Dest, cpstr CName, 2554 cpstr TName, bool Remove ) { 2555 // GetString(..), GetReal(..) and GetInteger(..) return 0 if the 2556 // requested field was found and successfully converted. Negative 2557 // returns mean: 2558 // CIFRC_WrongFormat the field was found but failed to convert 2559 // due to improper numeric format 2560 // CIFRC_NoTag category CName was found, but it does not 2561 // have tag TName 2562 // CIFRC_NoCategory category CName was not found 2563 // CIFRC_NotAStructure category CName was found, but it is a loop 2564 // rather than a structure. 2565 // GetString(..) will try to dispose Dest unless it is assugned 2566 // NULL value before the call. The string will be then dynamically 2567 // allocated and copied. 2568 int i = GetCategoryNo ( CName ); 2569 if (i<0) return CIFRC_NoCategory; 2570 if (Category[i]->GetCategoryID()!=MMCIF_Struct) 2571 return CIFRC_NotAStructure; 2572 return PStruct(Category[i])->GetString ( Dest,TName,Remove ); 2573 } 2574 GetString(cpstr CName,cpstr TName,int & RC)2575 pstr Data::GetString ( cpstr CName, cpstr TName, int & RC ) { 2576 int i = GetCategoryNo ( CName ); 2577 if (i<0) { 2578 RC = CIFRC_NoCategory; 2579 return NULL; 2580 } 2581 if (Category[i]->GetCategoryID()!=MMCIF_Struct) { 2582 RC = CIFRC_NotAStructure; 2583 return NULL; 2584 } 2585 return PStruct(Category[i])->GetString ( TName,RC ); 2586 } 2587 DeleteField(cpstr CName,cpstr TName)2588 int Data::DeleteField ( cpstr CName, cpstr TName ) { 2589 int i = GetCategoryNo ( CName ); 2590 if (i<0) return CIFRC_NoCategory; 2591 if (Category[i]->GetCategoryID()!=MMCIF_Struct) 2592 return CIFRC_NotAStructure; 2593 return PStruct(Category[i])->DeleteField ( TName ); 2594 } 2595 GetReal(realtype & R,cpstr CName,cpstr TName,bool Remove)2596 int Data::GetReal ( realtype & R, cpstr CName, 2597 cpstr TName, bool Remove ) { 2598 int i = GetCategoryNo ( CName ); 2599 if (i<0) return CIFRC_NoCategory; 2600 if (Category[i]->GetCategoryID()!=MMCIF_Struct) 2601 return CIFRC_NotAStructure; 2602 return PStruct(Category[i])->GetReal ( R,TName,Remove ); 2603 } 2604 GetInteger(int & I,cpstr CName,cpstr TName,bool Remove)2605 int Data::GetInteger ( int & I, cpstr CName, 2606 cpstr TName, bool Remove ) { 2607 int j = GetCategoryNo ( CName ); 2608 if (j<0) return CIFRC_NoCategory; 2609 if (Category[j]->GetCategoryID()!=MMCIF_Struct) 2610 return CIFRC_NotAStructure; 2611 return PStruct(Category[j])->GetInteger ( I,TName,Remove ); 2612 } 2613 GetLoopLength(cpstr CName)2614 int Data::GetLoopLength ( cpstr CName ) { 2615 // GetLoopLength(..) returns CIFRC_NotALoop if the category CName 2616 // is not a loop, CIFRC_NoCategory if the category CName is not 2617 // found. Non-negative returns give the length of the loop (may be 2618 // 0 if the loop is empty). 2619 int i; 2620 i = GetCategoryNo ( CName ); 2621 if (i<0) return CIFRC_NoCategory; 2622 if (Category[i]->GetCategoryID()!=MMCIF_Loop) 2623 return CIFRC_NotALoop; 2624 return PLoop(Category[i])->nRows; 2625 } 2626 GetLoopString(pstr & Dest,cpstr CName,cpstr TName,int nrow,bool Remove)2627 int Data::GetLoopString ( pstr & Dest, cpstr CName, 2628 cpstr TName, int nrow, 2629 bool Remove ) { 2630 // GetLoopString(..), GetLoopReal(..) and GetLoopInteger(..) act 2631 // like GetString(..), GetReal(..) and GetInteger(..) above for 2632 // nrow-th element of the 'loop_' (indexed like 0..N-1 where N 2633 // is obtained through GetLoopLength(..)). They will return 2634 // CIFRC_WrongIndex if nrow is out of range. 2635 int i = GetCategoryNo ( CName ); 2636 if (i<0) return CIFRC_NoCategory; 2637 if (Category[i]->GetCategoryID()!=MMCIF_Loop) 2638 return CIFRC_NotALoop; 2639 return PLoop(Category[i])->GetString ( Dest,TName,nrow,Remove ); 2640 } 2641 GetLoopString(cpstr CName,cpstr TName,int nrow,int & RC)2642 pstr Data::GetLoopString ( cpstr CName, cpstr TName, 2643 int nrow, int & RC ) { 2644 int i = GetCategoryNo ( CName ); 2645 if (i<0) { 2646 RC = CIFRC_NoCategory; 2647 return NULL; 2648 } 2649 if (Category[i]->GetCategoryID()!=MMCIF_Loop) { 2650 RC = CIFRC_NotALoop; 2651 return NULL; 2652 } 2653 return PLoop(Category[i])->GetString ( TName,nrow,RC ); 2654 } 2655 DeleteLoopField(cpstr CName,cpstr TName,int nrow)2656 int Data::DeleteLoopField ( cpstr CName, cpstr TName, 2657 int nrow ) { 2658 int i = GetCategoryNo ( CName ); 2659 if (i<0) return CIFRC_NoCategory; 2660 if (Category[i]->GetCategoryID()!=MMCIF_Loop) 2661 return CIFRC_NotALoop; 2662 return PLoop(Category[i])->DeleteField ( TName,nrow ); 2663 } 2664 GetLoopReal(realtype & R,cpstr CName,cpstr TName,int nrow,bool Remove)2665 int Data::GetLoopReal ( realtype & R, cpstr CName, 2666 cpstr TName, int nrow, 2667 bool Remove ) { 2668 int i = GetCategoryNo ( CName ); 2669 if (i<0) return CIFRC_NoCategory; 2670 if (Category[i]->GetCategoryID()!=MMCIF_Loop) 2671 return CIFRC_NotALoop; 2672 return PLoop(Category[i])->GetReal ( R,TName,nrow,Remove ); 2673 } 2674 GetLoopInteger(int & I,cpstr CName,cpstr TName,int nrow,bool Remove)2675 int Data::GetLoopInteger ( int & I, cpstr CName, 2676 cpstr TName, int nrow, 2677 bool Remove ) { 2678 int j = GetCategoryNo ( CName ); 2679 if (j<0) return CIFRC_NoCategory; 2680 if (Category[j]->GetCategoryID()!=MMCIF_Loop) 2681 return CIFRC_NotALoop; 2682 return PLoop(Category[j])->GetInteger ( I,TName,nrow,Remove ); 2683 } 2684 2685 GetLoopSVector(psvector & S,cpstr CName,cpstr TName,int i1,int i2,bool Remove)2686 int Data::GetLoopSVector ( psvector & S, cpstr CName, 2687 cpstr TName, int i1, int i2, 2688 bool Remove ) { 2689 // GetLoopSVector(..), GetLoopRVector(..) and GetLoopIVector(..) 2690 // read CIF 'loop_' data into allocated vectors of strings, reals and 2691 // integers, correspondingly. The vectors may be deallocated prior 2692 // to call and assigned NULL, in which case they will be allocated 2693 // with offsets of i1, which is also the lower index of the 'loop_' 2694 // data transferred into it. The upper vector index is given by i2 or 2695 // by the loop's length whichever is less. If vectors are not assigned 2696 // NULL prior the call, it is assumed that they are properly (i1-offset, 2697 // i2-i1+1 length) allocated. 2698 // The return codes are same as those of GetLoopString(..), 2699 // GetLoopReal(..) and GetLoopInteger(..). 2700 int i; 2701 i = GetCategoryNo ( CName ); 2702 if (i<0) return CIFRC_NoCategory; 2703 if (Category[i]->GetCategoryID()!=MMCIF_Loop) 2704 return CIFRC_NotALoop; 2705 return PLoop(Category[i])->GetSVector ( S,TName,i1,i2,Remove ); 2706 } 2707 GetLoopRVector(rvector & R,cpstr CName,cpstr TName,int i1,int i2,bool Remove)2708 int Data::GetLoopRVector ( rvector & R, cpstr CName, 2709 cpstr TName, int i1, int i2, 2710 bool Remove ) { 2711 int i; 2712 i = GetCategoryNo ( CName ); 2713 if (i<0) return CIFRC_NoCategory; 2714 if (Category[i]->GetCategoryID()!=MMCIF_Loop) 2715 return CIFRC_NotALoop; 2716 return PLoop(Category[i])->GetRVector ( R,TName,i1,i2,Remove ); 2717 } 2718 GetLoopIVector(ivector & I,cpstr CName,cpstr TName,int i1,int i2,bool Remove)2719 int Data::GetLoopIVector ( ivector & I, cpstr CName, 2720 cpstr TName, int i1, int i2, 2721 bool Remove ) { 2722 int j; 2723 j = GetCategoryNo ( CName ); 2724 if (j<0) return CIFRC_NoCategory; 2725 if (Category[j]->GetCategoryID()!=MMCIF_Loop) 2726 return CIFRC_NotALoop; 2727 return PLoop(Category[j])->GetIVector ( I,TName,i1,i2,Remove ); 2728 } 2729 2730 2731 // --------------- Storing data 2732 PutDataName(cpstr dname)2733 void Data::PutDataName ( cpstr dname ) { 2734 // stores name for 'data_' record 2735 CreateCopy ( name,dname ); 2736 } 2737 PutNoData(int NoDataType,cpstr CName,cpstr TName)2738 int Data::PutNoData ( int NoDataType, cpstr CName, cpstr TName ) { 2739 PStruct cifStruct; 2740 int i,RC; 2741 2742 RC = CIFRC_Ok; 2743 2744 // look for category 2745 i = AddCategory ( CName ); 2746 if (i<0) { 2747 // negative value means that the category was not in the list, 2748 // but a place for it has been provided and index updated 2749 cifStruct = new Struct ( CName ); 2750 Category[nCategories-1] = cifStruct; 2751 } else { 2752 cifStruct = PStruct(Category[i]); 2753 if (cifStruct->GetCategoryID()!=MMCIF_Struct) { 2754 RC = CIFRC_NotAStructure; 2755 delete Category[i]; 2756 cifStruct = new Struct ( CName ); 2757 Category[i] = cifStruct; 2758 } 2759 } 2760 2761 cifStruct->PutNoData ( NoDataType,TName ); 2762 2763 return RC; 2764 2765 } 2766 PutString(cpstr S,cpstr CName,cpstr TName,bool Concatenate)2767 int Data::PutString ( cpstr S, cpstr CName, 2768 cpstr TName, bool Concatenate ) { 2769 // PutString(..), PutReal(..) and PutInteger(..) will put the 2770 // values given into the specified category (CName) under the 2771 // specified tag (TName). The category, tag and field are created 2772 // automatically; the field will be replaced silently if identical 2773 // CName.TName is specified in two calls. Calls of these functions 2774 // may follow in random order; however CIF file will have all tags 2775 // grouped by categories and catgories will follow in the order 2776 // of first appearance in PutString(..), PutReal(..) or 2777 // PutInteger(..). 2778 // Return code - one of CIFRC_Ok or CIFRC_NotAStruct 2779 PStruct cifStruct; 2780 int i,RC; 2781 2782 RC = CIFRC_Ok; 2783 2784 // look for category 2785 i = AddCategory ( CName ); 2786 if (i<0) { 2787 // negative value means that the category was not in the list, 2788 // but a place for it has been provided and index updated 2789 cifStruct = new Struct ( CName ); 2790 Category[nCategories-1] = cifStruct; 2791 } else { 2792 cifStruct = PStruct(Category[i]); 2793 if (cifStruct->GetCategoryID()!=MMCIF_Struct) { 2794 RC = CIFRC_NotAStructure; 2795 delete Category[i]; 2796 cifStruct = new Struct ( CName ); 2797 Category[i] = cifStruct; 2798 } 2799 } 2800 2801 cifStruct->AddField ( S,TName,Concatenate ); 2802 2803 return RC; 2804 2805 } 2806 PutDate(cpstr CName,cpstr TName)2807 int Data::PutDate ( cpstr CName, cpstr TName ) { 2808 PStruct cifStruct; 2809 int i,RC; 2810 2811 RC = CIFRC_Ok; 2812 2813 // look for category 2814 i = AddCategory ( CName ); 2815 if (i<0) { 2816 // negative value means that the category was not in the list, 2817 // but a place for it has been provided and index updated 2818 cifStruct = new Struct ( CName ); 2819 Category[nCategories-1] = cifStruct; 2820 } else { 2821 cifStruct = PStruct(Category[i]); 2822 if (cifStruct->GetCategoryID()!=MMCIF_Struct) { 2823 RC = CIFRC_NotAStructure; 2824 delete Category[i]; 2825 cifStruct = new Struct ( CName ); 2826 Category[i] = cifStruct; 2827 } 2828 } 2829 2830 cifStruct->PutDate ( TName ); 2831 2832 return RC; 2833 2834 } 2835 PutReal(realtype R,cpstr CName,cpstr TName,int prec)2836 int Data::PutReal ( realtype R, cpstr CName, 2837 cpstr TName, int prec ) { 2838 char rS[100]; 2839 sprintf ( rS,"%.*g",prec,R ); 2840 return PutString ( rS,CName,TName,false ); 2841 } 2842 PutInteger(int I,cpstr CName,cpstr TName)2843 int Data::PutInteger ( int I, cpstr CName, 2844 cpstr TName ) { 2845 char iS[100]; 2846 if (I>MinInt4) sprintf ( iS,"%i",I ); 2847 else { 2848 iS[0] = char(2); 2849 iS[1] = '.'; 2850 iS[2] = char(0); 2851 } 2852 return PutString ( iS,CName,TName,false ); 2853 } 2854 2855 AddLoop(cpstr CName,PLoop & cifLoop)2856 int Data::AddLoop ( cpstr CName, PLoop & cifLoop ) { 2857 int i,RC; 2858 2859 RC = CIFRC_Ok; 2860 2861 // look for category 2862 i = AddCategory ( CName ); 2863 if (i<0) { 2864 // negative value means that the category was not in the list, 2865 // but a place for it has been provided and index updated 2866 cifLoop = new Loop ( CName ); 2867 Category[nCategories-1] = cifLoop; 2868 RC = CIFRC_Created; 2869 } else { 2870 cifLoop = PLoop(Category[i]); 2871 if (cifLoop->GetCategoryID()!=MMCIF_Loop) { 2872 RC = CIFRC_NotALoop; 2873 delete Category[i]; 2874 cifLoop = new Loop ( CName ); 2875 Category[i] = cifLoop; 2876 } 2877 } 2878 2879 return RC; 2880 2881 } 2882 AddStructure(cpstr CName,PStruct & cifStruct)2883 int Data::AddStructure ( cpstr CName, PStruct & cifStruct ) { 2884 int i,RC; 2885 2886 RC = CIFRC_Ok; 2887 2888 // look for category 2889 i = AddCategory ( CName ); 2890 if (i<0) { 2891 // negative value means that the category was not in the list, 2892 // but a place for it has been provided and index updated 2893 cifStruct = new Struct ( CName ); 2894 Category[nCategories-1] = cifStruct; 2895 RC = CIFRC_Created; 2896 } else { 2897 cifStruct = PStruct(Category[i]); 2898 if (cifStruct->GetCategoryID()!=MMCIF_Struct) { 2899 RC = CIFRC_NotAStructure; 2900 delete Category[i]; 2901 cifStruct = new Struct ( CName ); 2902 Category[i] = cifStruct; 2903 } 2904 } 2905 2906 return RC; 2907 2908 } 2909 2910 PutLoopNoData(int NoDataType,cpstr CName,cpstr TName,int nrow)2911 int Data::PutLoopNoData ( int NoDataType, cpstr CName, 2912 cpstr TName, int nrow ) { 2913 PLoop cifLoop; 2914 int i,RC; 2915 2916 RC = CIFRC_Ok; 2917 2918 // look for category 2919 i = AddCategory ( CName ); 2920 if (i<0) { 2921 // negative value means that the category was not in the list, 2922 // but a place for it has been provided and index updated 2923 cifLoop = new Loop ( CName ); 2924 Category[nCategories-1] = cifLoop; 2925 } else { 2926 cifLoop = PLoop(Category[i]); 2927 if (cifLoop->GetCategoryID()!=MMCIF_Loop) { 2928 RC = CIFRC_NotALoop; 2929 delete Category[i]; 2930 cifLoop = new Loop ( CName ); 2931 Category[i] = cifLoop; 2932 } 2933 } 2934 2935 cifLoop->PutNoData ( NoDataType,TName,nrow ); 2936 2937 return RC; 2938 2939 } 2940 2941 PutLoopString(cpstr S,cpstr CName,cpstr TName,int nrow)2942 int Data::PutLoopString ( cpstr S, cpstr CName, 2943 cpstr TName, int nrow ) { 2944 // PutLoopString(..), PutLoopReal(..) and PutLoopInteger(..) act 2945 // like PutString(..), PutReal(..) and PutInteger(..) above for 2946 // nrow-th element of the 'loop_' CName (indexed begining from 0). 2947 // In consequitive calls, given values of nrow does not have to be 2948 // ordered; the most efficient way is to start with HIGHEST value 2949 // for nrow in the loop and move down to 0. The least efficient way 2950 // is to start with nrow=0 and move up. 2951 PLoop cifLoop; 2952 int i,RC; 2953 2954 RC = CIFRC_Ok; 2955 2956 // look for category 2957 i = AddCategory ( CName ); 2958 if (i<0) { 2959 // negative value means that the category was not in the list, 2960 // but a place for it has been provided and index updated 2961 cifLoop = new Loop ( CName ); 2962 Category[nCategories-1] = cifLoop; 2963 } else { 2964 cifLoop = PLoop(Category[i]); 2965 if (cifLoop->GetCategoryID()!=MMCIF_Loop) { 2966 RC = CIFRC_NotALoop; 2967 delete Category[i]; 2968 cifLoop = new Loop ( CName ); 2969 Category[i] = cifLoop; 2970 } 2971 } 2972 2973 cifLoop->PutString ( S,TName,nrow ); 2974 2975 return RC; 2976 2977 } 2978 PutLoopReal(realtype R,cpstr CName,cpstr TName,int nrow,int prec)2979 int Data::PutLoopReal ( realtype R, cpstr CName, 2980 cpstr TName, int nrow, int prec ) { 2981 char rS[100]; 2982 sprintf ( rS,"%.*g",prec,R ); 2983 return PutLoopString ( rS,CName,TName,nrow ); 2984 } 2985 PutLoopInteger(int I,cpstr CName,cpstr TName,int nrow)2986 int Data::PutLoopInteger ( int I, cpstr CName, 2987 cpstr TName, int nrow ) { 2988 char iS[100]; 2989 sprintf ( iS,"%i",I ); 2990 return PutLoopString ( iS,CName,TName,nrow ); 2991 } 2992 2993 PutLoopSVector(psvector S,cpstr CName,cpstr TName,int i1,int i2)2994 int Data::PutLoopSVector ( psvector S, cpstr CName, 2995 cpstr TName, int i1, int i2 ) { 2996 // PutLoopSVector(..), PutLoopRVector(..) and PutLoopIVector(..) 2997 // put vectors of values into specified loop fields. Parameters i1 2998 // and i2 give the range of indices of values which are to be 2999 // transfered. To transfer an entire vector allocated as [0..N-1] 3000 // i1 shoudl be set to 0 and i2 - to N-1. Note that the loop is 3001 // always indexed as starting form 0 on, therefore negative i1 and 3002 // i2 are not allowed, and specifying i1>0 will leave first i1 3003 // elements of the CIF loop for the corresponding tag undefined 3004 // (will be output like '?'). 3005 PLoop cifLoop; 3006 int i,RC; 3007 3008 RC = CIFRC_Ok; 3009 3010 // look for category 3011 i = AddCategory ( CName ); 3012 if (i<0) { 3013 // negative value means that the category was not in the list, 3014 // but a place for it has been provided and index updated 3015 cifLoop = new Loop ( CName ); 3016 Category[nCategories-1] = cifLoop; 3017 } else { 3018 cifLoop = PLoop(Category[i]); 3019 if (cifLoop->GetCategoryID()!=MMCIF_Loop) { 3020 RC = CIFRC_NotALoop; 3021 delete Category[i]; 3022 cifLoop = new Loop ( CName ); 3023 Category[i] = cifLoop; 3024 } 3025 } 3026 3027 cifLoop->PutSVector ( S,TName,i1,i2 ); 3028 3029 return RC; 3030 3031 } 3032 PutLoopRVector(rvector R,cpstr CName,cpstr TName,int i1,int i2,int prec)3033 int Data::PutLoopRVector ( rvector R, cpstr CName, 3034 cpstr TName, 3035 int i1, int i2, int prec ) { 3036 PLoop cifLoop; 3037 int i,RC; 3038 3039 RC = CIFRC_Ok; 3040 3041 // look for category 3042 i = AddCategory ( CName ); 3043 if (i<0) { 3044 // negative value means that the category was not in the list, 3045 // but a place for it has been provided and index updated 3046 cifLoop = new Loop ( CName ); 3047 Category[nCategories-1] = cifLoop; 3048 } else { 3049 cifLoop = PLoop(Category[i]); 3050 if (cifLoop->GetCategoryID()!=MMCIF_Loop) { 3051 RC = CIFRC_NotALoop; 3052 delete Category[i]; 3053 cifLoop = new Loop ( CName ); 3054 Category[i] = cifLoop; 3055 } 3056 } 3057 3058 cifLoop->PutRVector ( R,TName,i1,i2,prec ); 3059 3060 return RC; 3061 3062 } 3063 PutLoopIVector(ivector I,cpstr CName,cpstr TName,int i1,int i2)3064 int Data::PutLoopIVector ( ivector I, cpstr CName, 3065 cpstr TName, 3066 int i1, int i2 ) { 3067 PLoop cifLoop; 3068 int j,RC; 3069 3070 RC = CIFRC_Ok; 3071 3072 // look for category 3073 j = AddCategory ( CName ); 3074 if (j<0) { 3075 // negative value means that the category was not in the list, 3076 // but a place for it has been provided and index updated 3077 cifLoop = new Loop ( CName ); 3078 Category[nCategories-1] = cifLoop; 3079 } else { 3080 cifLoop = PLoop(Category[j]); 3081 if (cifLoop->GetCategoryID()!=MMCIF_Loop) { 3082 RC = CIFRC_NotALoop; 3083 delete Category[j]; 3084 cifLoop = new Loop ( CName ); 3085 Category[j] = cifLoop; 3086 } 3087 } 3088 3089 cifLoop->PutIVector ( I,TName,i1,i2 ); 3090 3091 return RC; 3092 3093 } 3094 3095 RenameCategory(cpstr CName,cpstr newCName)3096 int Data::RenameCategory ( cpstr CName, 3097 cpstr newCName ) { 3098 int i,RC; 3099 i = GetCategoryNo ( CName ); 3100 if (i>=0) { 3101 Category[i]->PutCategoryName ( newCName ); 3102 Sort(); 3103 RC = CIFRC_Ok; 3104 } else 3105 RC = CIFRC_NoCategory; 3106 return RC; 3107 } 3108 3109 Copy(PData Data)3110 void Data::Copy ( PData Data ) { 3111 int i; 3112 FreeMemory(0); 3113 CreateCopy ( name,Data->name ); 3114 nCategories = Data->nCategories; 3115 if (nCategories>0) { 3116 Category = new PCategory[nCategories]; 3117 GetVectorMemory ( index,nCategories,0 ); 3118 for (i=0;i<nCategories;i++) { 3119 if (Data->Category[i]) { 3120 if (Data->Category[i]->GetCategoryID()==MMCIF_Struct) 3121 Category[i] = new Struct(); 3122 else Category[i] = new Loop(); 3123 Category[i]->Copy ( Data->Category[i] ); 3124 } else 3125 Category[i] = NULL; 3126 index[i] = Data->index[i]; 3127 } 3128 } 3129 flags = Data->flags; 3130 Warning = Data->Warning; 3131 } 3132 3133 CopyCategory(PData Data,cpstr CName,cpstr newCName)3134 int Data::CopyCategory ( PData Data, cpstr CName, 3135 cpstr newCName ) { 3136 PCategory Cat; 3137 int i,di,dc,RC; 3138 3139 di = Data->GetCategoryNo ( CName ); 3140 3141 if (di>=0) { 3142 3143 RC = CIFRC_Ok; 3144 dc = Data->Category[di]->GetCategoryID(); 3145 3146 // look for category 3147 i = AddCategory ( CName ); 3148 if (i<0) { 3149 // negative value means that the category was not in the list, 3150 // but a place for it has been provided and index updated 3151 if (dc==MMCIF_Loop) Cat = new Loop ( CName ); 3152 else Cat = new Struct ( CName ); 3153 Category[nCategories-1] = Cat; 3154 } else { 3155 Cat = Category[i]; 3156 if (Cat->GetCategoryID()!=dc) { 3157 RC = CIFRC_NotAStructure; 3158 delete Category[i]; 3159 if (dc==MMCIF_Loop) Cat = new Loop ( CName ); 3160 else Cat = new Struct ( CName ); 3161 Category[i] = Cat; 3162 } 3163 } 3164 3165 Cat->Copy ( Data->Category[di] ); 3166 if (newCName) { 3167 Cat->PutCategoryName ( newCName ); 3168 Sort(); 3169 } 3170 3171 } else 3172 RC = CIFRC_NoCategory; 3173 3174 return RC; 3175 3176 } 3177 PrintCategories()3178 void Data::PrintCategories() { 3179 // for debuging only 3180 int i; 3181 printf ( " Total %i categories:\n",nCategories ); 3182 for (i=0;i<nCategories;i++) 3183 if (Category[i]) { 3184 printf ( " %5i. ",i+1 ); 3185 if (Category[i]->GetCategoryID()==MMCIF_Loop) 3186 printf ( "Loop %s\n",Category[i]->name ); 3187 else printf ( "Structure %s\n",Category[i]->name ); 3188 } 3189 } 3190 3191 write(io::RFile f)3192 void Data::write ( io::RFile f ) { 3193 int i,k; 3194 if (!index) Sort(); 3195 f.CreateWrite ( name ); 3196 f.WriteInt ( &nCategories ); 3197 for (i=0;i<nCategories;i++) { 3198 if (Category[i]) { 3199 k = Category[i]->GetCategoryID(); 3200 f.WriteInt ( &k ); 3201 Category[i]->write ( f ); 3202 } else { 3203 k = -1; 3204 f.WriteInt ( &k ); 3205 } 3206 f.WriteInt ( &(index[i]) ); 3207 } 3208 f.WriteInt ( &flags ); 3209 f.WriteInt ( &Warning ); 3210 } 3211 3212 read(io::RFile f)3213 void Data::read ( io::RFile f ) { 3214 int i,k; 3215 FreeMemory(0); 3216 f.CreateRead ( name ); 3217 f.ReadInt ( &nCategories ); 3218 if (nCategories>0) { 3219 Category = new PCategory[nCategories]; 3220 GetVectorMemory ( index,nCategories,0 ); 3221 for (i=0;i<nCategories;i++) { 3222 f.ReadInt ( &k ); 3223 if (k>=0) { 3224 if (k==MMCIF_Struct) Category[i] = new Struct(); 3225 else Category[i] = new Loop(); 3226 Category[i]->read ( f ); 3227 } else 3228 Category[i] = NULL; 3229 f.ReadInt ( &(index[i]) ); 3230 } 3231 } 3232 f.ReadInt ( &flags ); 3233 f.ReadInt ( &Warning ); 3234 } 3235 3236 MakeStreamFunctions(Data)3237 MakeStreamFunctions(Data) 3238 3239 3240 3241 // ====================== File ============================= 3242 3243 3244 File::File() : io::Stream() { 3245 InitFile(); 3246 } 3247 File(cpstr FName,io::GZ_MODE gzipMode)3248 File::File ( cpstr FName, io::GZ_MODE gzipMode ) : io::Stream() { 3249 InitFile (); 3250 ReadMMCIFFile ( FName,gzipMode ); 3251 } 3252 File(io::RPStream Object)3253 File::File ( io::RPStream Object ) : io::Stream(Object) { 3254 InitFile(); 3255 } 3256 ~File()3257 File::~File() { 3258 FreeMemory(); 3259 } 3260 InitFile()3261 void File::InitFile() { 3262 nData = 0; 3263 nAllocData = 0; 3264 data = NULL; 3265 index = NULL; 3266 PrintWarnings = false; 3267 StopOnWarning = false; 3268 } 3269 FreeMemory()3270 void File::FreeMemory() { 3271 int i; 3272 for (i=0;i<nData;i++) 3273 if (data[i]) delete data[i]; 3274 if (data) delete[] data; 3275 data = NULL; 3276 FreeVectorMemory ( index,0 ); 3277 nData = 0; 3278 nAllocData = 0; 3279 } 3280 3281 GetMMCIFInputBuffer(int & LineNo)3282 pstr GetMMCIFInputBuffer ( int & LineNo ) { 3283 LineNo = _err_line; 3284 _err_string[sizeof(_err_string)-1] = char(0); 3285 return _err_string; 3286 } 3287 ReadMMCIFFile(cpstr FName,io::GZ_MODE gzipMode)3288 int File::ReadMMCIFFile ( cpstr FName, io::GZ_MODE gzipMode ) { 3289 io::File f; 3290 PData CIF; 3291 char S[500]; 3292 int RC,lcount; 3293 3294 FreeMemory(); 3295 3296 CIF = NULL; 3297 f.assign ( FName,true,false,gzipMode ); 3298 if (f.reset(true)) { 3299 S[0] = char(0); 3300 lcount = 0; 3301 RC = 0; 3302 while ((!RC) && (!f.FileEnd())) { 3303 if (!CIF) CIF = new Data(); 3304 CIF->SetPrintWarnings ( PrintWarnings ); 3305 CIF->SetStopOnWarning ( StopOnWarning ); 3306 RC = CIF->ReadMMCIFData ( f,S,lcount ); 3307 if (!RC) { 3308 ExpandData ( nData+1 ); 3309 data[nData] = CIF; 3310 nData++; 3311 CIF = NULL; 3312 } 3313 } 3314 if (CIF) delete CIF; 3315 f.shut(); 3316 if (RC==CIFRC_NoDataLine) { 3317 if (nData>0) RC = 0; 3318 } 3319 Sort(); 3320 return RC; 3321 } else 3322 return CIFRC_CantOpenFile; 3323 3324 } 3325 WriteMMCIFFile(cpstr FName,io::GZ_MODE gzipMode)3326 int File::WriteMMCIFFile ( cpstr FName, io::GZ_MODE gzipMode ) { 3327 io::File f; 3328 f.assign ( FName,true,false,gzipMode ); 3329 if (f.rewrite()) { 3330 WriteMMCIF ( f ); 3331 f.shut(); 3332 return 0; 3333 } else 3334 return CIFRC_CantOpenFile; 3335 } 3336 WriteMMCIF(io::RFile f)3337 void File::WriteMMCIF ( io::RFile f ) { 3338 int i; 3339 for (i=0;i<nData;i++) 3340 if (data[i]) 3341 data[i]->WriteMMCIF ( f ); 3342 } 3343 3344 Sort()3345 void File::Sort() { 3346 psvector tag; 3347 int i; 3348 if (nData>0) { 3349 FreeVectorMemory ( index,0 ); 3350 GetVectorMemory ( index,nData,0 ); 3351 GetVectorMemory ( tag ,nData,0 ); 3352 for (i=0;i<nData;i++) { 3353 tag[i] = NULL; 3354 CreateCopy ( tag[i],data[i]->name ); 3355 } 3356 SortTags ( tag,nData,index ); 3357 for (i=0;i<nData;i++) 3358 if (tag[i]) { 3359 delete[] tag[i]; 3360 tag[i] = NULL; 3361 } 3362 FreeVectorMemory ( tag,0 ); 3363 } 3364 } 3365 GetCIFDataNo(cpstr DName)3366 int File::GetCIFDataNo ( cpstr DName ) { 3367 // Binary search for index of DName ttag in data[]. 3368 // Return: 3369 // >=0 : position of the DName found 3370 // <0 : the DName was not found, it could be inserted before 3371 // (-RC-1)th element, where RC is the return value 3372 int l1,l2,l,k; 3373 3374 if (!data) return -1; 3375 if (!index) Sort(); 3376 3377 l = 0; 3378 l1 = 0; 3379 l2 = nData-1; 3380 k = 1; 3381 while (l1<l2-1) { 3382 l = (l1+l2)/2; 3383 k = strcasecmp ( DName,data[index[l]]->name ); 3384 if (k<0) l2 = l; 3385 else if (k>0) l1 = l; 3386 else { 3387 l1 = l; 3388 break; 3389 } 3390 } 3391 3392 if (k==0) return index[l]; // is at RCth position 3393 k = strcasecmp ( DName,data[index[l1]]->name ); 3394 if (k==0) return index[l1]; // is at RCth position 3395 if (k<0) return -1; // would be at (-RC-1)th position 3396 if (l2!=l1) { 3397 k = strcasecmp ( DName,data[index[l2]]->name ); 3398 if (k==0) return index[l2]; // is at RCth position 3399 if (k>0) return -2-l2; // would be at l2+1=(-RC-1)th position 3400 } 3401 3402 return -2-l1; // would be at l1+1=(-RC-1)th position 3403 3404 } 3405 GetCIFData(int dataNo)3406 PData File::GetCIFData ( int dataNo ) { 3407 if ((dataNo>=0) && (dataNo<nData)) return data[dataNo]; 3408 else return NULL; 3409 } 3410 GetCIFData(cpstr DName)3411 PData File::GetCIFData ( cpstr DName ) { 3412 int l; 3413 l = GetCIFDataNo ( DName ); 3414 if (l>=0) return data[l]; 3415 else return NULL; 3416 } 3417 ExpandData(int nDataNew)3418 void File::ExpandData ( int nDataNew ) { 3419 int i,nAD; 3420 PPData data1; 3421 ivector index1; 3422 if (nDataNew>nAllocData) { 3423 nAD = nDataNew + IMin(nAllocData/2+1,100); 3424 data1 = new PData[nAD]; 3425 GetVectorMemory ( index1,nAD,0 ); 3426 for (i=0;i<nAllocData;i++) { 3427 data1 [i] = data [i]; 3428 index1[i] = index[i]; 3429 } 3430 for (i=nAllocData;i<nAD;i++) { 3431 data1 [i] = NULL; 3432 index1[i] = i; 3433 } 3434 if (data) delete[] data; 3435 FreeVectorMemory ( index,0 ); 3436 data = data1; 3437 index = index1; 3438 nAllocData = nAD; 3439 } 3440 } 3441 AddCIFData(cpstr DName)3442 int File::AddCIFData ( cpstr DName ) { 3443 // return -1: the CIF data structure has been added on the 3444 // top of data array; the index is added and sorted 3445 // automatically 3446 // >=0: the CIF data structure is already in the array 3447 // -- its position is returned 3448 int i1,i; 3449 if (!data) { 3450 ExpandData ( 3 ); // get space for first 3 CIF data structures 3451 data[0] = new Data ( DName ); 3452 nData = 1; 3453 return -nData; // the CIF data structure has been added 3454 // "on the top" of array 3455 } 3456 i1 = GetCIFDataNo ( DName ); 3457 if (i1>=0) return i1; // non-negative returns mean that the CIF 3458 // data structure is already in the array 3459 i1 = -i1-1; // otherwise the data has to be added and indexed at here 3460 // put new CIF data structure on the top of array and update index 3461 ExpandData ( nData+1 ); 3462 data[nData] = new Data ( DName ); 3463 for (i=nData;i>i1;i--) 3464 index[i] = index[i-1]; 3465 index[i1] = nData; 3466 nData++; 3467 return -nData; // the tag has been added on the top of array 3468 } 3469 3470 DeleteCIFData(cpstr DName)3471 int File::DeleteCIFData ( cpstr DName ) { 3472 int dataNo = GetCIFDataNo ( DName ); 3473 3474 if (dataNo>=0) return DeleteCIFData ( dataNo ); 3475 return dataNo; 3476 3477 } 3478 DeleteCIFData(int dataNo)3479 int File::DeleteCIFData ( int dataNo ) { 3480 int i; 3481 3482 if ((0<=dataNo) && (dataNo<nData)) { 3483 3484 if (data[dataNo]) delete data[dataNo]; 3485 for (i=dataNo+1;i<nData;i++) 3486 data[i-1] = data[i]; 3487 nData--; 3488 3489 Sort(); 3490 3491 return 0; 3492 3493 } 3494 3495 return -nData; 3496 3497 } 3498 Copy(PFile File)3499 void File::Copy ( PFile File ) { 3500 int i; 3501 FreeMemory(); 3502 nData = File->nData; 3503 nAllocData = nData; 3504 if (nData>0) { 3505 data = new PData[nData]; 3506 for (i=0;i<nData;i++) { 3507 if (File->data[i]) { 3508 data[i] = new Data(); 3509 data[i]->Copy ( File->data[i] ); 3510 } else 3511 data[i] = NULL; 3512 } 3513 } 3514 } 3515 3516 write(io::RFile f)3517 void File::write ( io::RFile f ) { 3518 int i,k; 3519 f.WriteInt ( &nData ); 3520 for (i=0;i<nData;i++) 3521 if (data[i]) { 3522 k = 1; 3523 f.WriteInt ( &k ); 3524 data[i]->write ( f ); 3525 } else { 3526 k = 0; 3527 f.WriteInt ( &k ); 3528 } 3529 } 3530 read(io::RFile f)3531 void File::read ( io::RFile f ) { 3532 int i,k; 3533 FreeMemory(); 3534 f.ReadInt ( &nData ); 3535 nAllocData = nData; 3536 if (nData>0) { 3537 data = new PData[nData]; 3538 for (i=0;i<nData;i++) { 3539 f.ReadInt ( &k ); 3540 if (k) { 3541 data[i] = new Data(); 3542 data[i]->read ( f ); 3543 } else 3544 data[i] = NULL; 3545 } 3546 } 3547 } 3548 3549 MakeStreamFunctions(File)3550 MakeStreamFunctions(File) 3551 3552 3553 int isCIF ( cpstr FName, io::GZ_MODE gzipMode ) { 3554 io::File f; 3555 int rc; 3556 3557 f.assign ( FName,true,false,gzipMode ); 3558 if (f.reset(true)) { 3559 rc = isCIF ( f ); 3560 f.shut(); 3561 } else 3562 rc = -1; 3563 3564 return rc; 3565 3566 } 3567 isCIF(io::RFile f)3568 int isCIF ( io::RFile f ) { 3569 char S[_max_buf_len+1]; 3570 bool Done; 3571 pstr p; 3572 3573 f.ReadLine ( S,_max_buf_len ); 3574 S[_max_buf_len] = char(0); 3575 Done = false; 3576 while (!Done) { 3577 p = &(S[0]); 3578 while ((*p==' ') || (*p==char(9))) p++; 3579 Done = !strncmp(p,"data_",5); 3580 if (!Done) { 3581 if (f.FileEnd()) { 3582 Done = true; 3583 p = NULL; 3584 } else { 3585 f.ReadLine ( S,_max_buf_len ); 3586 S[_max_buf_len] = char(0); 3587 } 3588 } 3589 } 3590 3591 if (!p) return 1; 3592 if (!strncmp(p,"data_",5)) return 0; 3593 else return 1; 3594 3595 } 3596 3597 GetCIFMessage(pstr M,int RC)3598 pstr GetCIFMessage ( pstr M, int RC ) { 3599 int LineNo; 3600 pstr InputLine; 3601 3602 InputLine = GetMMCIFInputBuffer ( LineNo ); 3603 3604 if (RC>10) { 3605 if (RC & CIFW_UnrecognizedItems) 3606 sprintf ( M,"unrecognized items found on %ith line\n%s", 3607 LineNo,InputLine ); 3608 else if (RC & CIFW_MissingField) 3609 sprintf ( M,"expected data field not found; line %i reads\n%s", 3610 LineNo,InputLine ); 3611 else if (RC & CIFW_EmptyLoop) 3612 sprintf ( M,"empty loop ('loop_') on %ith line\n%s", 3613 LineNo,InputLine ); 3614 else if (RC & CIFW_UnexpectedEOF) 3615 sprintf ( M,"unexpected end of file; line %i reads\n%s", 3616 LineNo,InputLine ); 3617 else if (RC & CIFW_LoopFieldMissing) 3618 sprintf ( M,"expected data field in a loop not found; " 3619 "line %i reads\n%s", LineNo,InputLine ); 3620 else if (RC & CIFW_LoopFieldMissing) 3621 sprintf ( M,"expected data field in a loop not found; " 3622 "line %i reads\n%s", LineNo,InputLine ); 3623 else if (RC & CIFW_NotAStructure) 3624 sprintf ( M,"a loop is used as a structure on line %i\n%s", 3625 LineNo,InputLine ); 3626 else if (RC & CIFW_NotALoop) 3627 sprintf ( M,"a structure is used as a loop on line %i\n%s", 3628 LineNo,InputLine ); 3629 else if (RC & CIFW_DuplicateTag) 3630 sprintf ( M,"duplicate tag was found on line %i\n%s", 3631 LineNo,InputLine ); 3632 else 3633 sprintf ( M,"undocumented warning issued for line %i\n%s", 3634 LineNo,InputLine ); 3635 } else if (RC<0) 3636 switch (RC) { 3637 case CIFRC_StructureNoTag : strcpy(M,"tag of a structure not " 3638 "found"); 3639 break; 3640 case CIFRC_LoopNoTag : strcpy(M,"tag of a loop not found"); 3641 break; 3642 case CIFRC_NoCategory : strcpy(M,"category not found"); 3643 break; 3644 case CIFRC_WrongFormat : strcpy(M,"wrong format of a number"); 3645 break; 3646 case CIFRC_NoTag : strcpy(M,"tag not found"); 3647 break; 3648 case CIFRC_NotAStructure : strcpy(M,"category is not a " 3649 "structure"); 3650 break; 3651 case CIFRC_NotALoop : strcpy(M,"category is not a loop"); 3652 break; 3653 case CIFRC_WrongIndex : strcpy(M,"index outside the loop's " 3654 "limits"); 3655 break; 3656 case CIFRC_NoField : strcpy(M,"data is absent"); 3657 break; 3658 case CIFRC_Created : strcpy(M,"category created"); 3659 break; 3660 case CIFRC_CantOpenFile : strcpy(M,"can't open CIF file"); 3661 break; 3662 case CIFRC_NoDataLine : strcpy(M,"'data_' tag not found." ); 3663 break; 3664 default : strcpy(M,"undocumented return code"); 3665 } 3666 3667 return M; 3668 3669 } 3670 3671 } // namespace mmcif 3672 3673 } // namespace mmdb 3674