1 //  $Id: mmdb_utils.cpp $
2 //  =================================================================
3 //
4 //   CCP4 Coordinate Library: support of coordinate-related
5 //   functionality in protein crystallography applications.
6 //
7 //   Copyright (C) Eugene Krissinel 2000-2008.
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 //    27.02.17   <--  Date of Last Modification.
26 //                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
27 //  -----------------------------------------------------------------
28 //
29 //  **** Module  :   MMDBF_Utils <implementation>
30 //       ~~~~~~~~~
31 //  **** Project :   MacroMolecular Data Base (MMDB)
32 //       ~~~~~~~~~
33 //
34 //  **** Classes :   mmdb::ContainerClass ( containered class template )
35 //       ~~~~~~~~~   mmdb::ContString     ( containered string         )
36 //                   mmdb::ClassContainer ( container of classes       )
37 //                   mmdb::AtomPath       ( atom path ID               )
38 //                   mmdb::QuickSort      ( quick sort of integers     )
39 //
40 //  **** Functions : Date9to11  ( DD-MMM-YY   -> DD-MMM-YYYY          )
41 //       ~~~~~~~~~~~ Date11to9  ( DD-MMM-YYYY -> DD-MMM-YY            )
42 //                   Date9toCIF ( DD-MMM-YY   -> YYYY-MM-DD           )
43 //                   Date11toCIF( DD-MMM-YYYY -> YYYY-MM-DD           )
44 //                   DateCIFto9 ( YYYY-MM-DD  -> DD-MMM-YY            )
45 //                   DateCIFto11( YYYY-MM-DD  -> DD-MMM-YYYY          )
46 //                   GetInteger ( reads integer from a string         )
47 //                   GetReal    ( reads real from a string            )
48 //                   GetIntIns  ( reads integer and insert code       )
49 //                   PutInteger ( writes integer into a string        )
50 //                   PutRealF   ( writes real in F-form into a string )
51 //                   PutIntIns  ( writes integer and insert code      )
52 //                   CIFGetInteger ( reads and deletes int from CIF   )
53 //                   CIFGetReal    ( reads and deletes real from CIF  )
54 //                   CIFGetString  ( reads and deletes string from CIF)
55 //                   CIFGetInteger1 (reads and del-s int from CIF loop)
56 //                   CIFGetReal1    (reads and del-s int from CIF loop)
57 //                   Mat4Inverse    ( inversion of 4x4 matrices       )
58 //                   GetErrorDescription (ascii line to an Error_XXXXX)
59 //                   ParseAtomID    ( parses atom ID line             )
60 //                   ParseResID     ( parses residue ID line          )
61 //                   ParseAtomPath  ( parses full atom path           )
62 //
63 //   (C) E. Krissinel  2000-2017
64 //
65 //  =================================================================
66 //
67 
68 #include <string.h>
69 #include <math.h>
70 #include <stdlib.h>
71 
72 #include "mmdb_utils.h"
73 #include "hybrid_36.h"
74 
75 namespace mmdb  {
76 
77   // ====================== Date functions  =======================
78 
79   static cpstr Month[12] = {
80     "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
81     "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"
82   };
83 
84   static cpstr nMonth[12] = {
85     "01", "02", "03", "04", "05", "06",
86     "07", "08", "09", "10", "11", "12"
87   };
88 
Date9to11(cpstr Date9,pstr Date11)89   void  Date9to11 ( cpstr Date9, pstr Date11 )  {
90   // converts  DD-MMM-YY to DD-MMM-YYYY
91   int i;
92     i = 0;
93     while ((i<12) && (strncmp(Month[i],&(Date9[3]),3)))  i++;
94     if (i<12)  {   // DD-MMM-YY -> DD-MMM-YYYY
95       strncpy ( Date11,Date9,7 );
96       if (Date9[7]!='0')  strncpy ( &(Date11[7]),"19",2 );
97                     else  strncpy ( &(Date11[7]),"20",2 );
98       strncpy ( &(Date11[9]),&(Date9[7]),2 );
99       Date11[2]  = '-';
100       Date11[6]  = '-';
101       Date11[11] = char(0);
102     } else  {     // DD-MM-YY -> DD-MMM-YYYY
103       strncpy ( Date11,Date9,3 );
104       i = 0;
105       while ((i<12) && (strncmp(nMonth[i],&(Date9[3]),2)))  i++;
106       if (i<12)  {
107         strncpy ( &(Date11[3]),Month[i],3 );
108           if (Date9[6]!='0')  strncpy ( &(Date11[7]),"19",2 );
109                     else  strncpy ( &(Date11[7]),"20",2 );
110         strncpy ( &(Date11[9]),&(Date9[6]),2 );
111         Date11[2]  = '-';
112         Date11[6]  = '-';
113         Date11[11] = char(0);
114       } else
115         strcpy ( Date11,"           " );
116     }
117   }
118 
Date11to9(cpstr Date11,pstr Date9)119   void  Date11to9 ( cpstr Date11, pstr Date9 )  {
120   // converts DD-MMM-YYYY to DD-MMM-YY
121   int i;
122     i = 0;
123     while ((i<12) && (strncmp(Month[i],&(Date11[3]),3)))  i++;
124     if (i<12)  {   // DD-MMM-YYYY -> DD-MMM-YY
125       strncpy ( Date9,Date11,7 );
126       strncpy ( &(Date9[7]),&(Date11[9]),2 );
127       Date9[2] = '-';
128       Date9[6] = '-';
129     } else  {      // DD-MM-YYYY -> DD-MMM-YY
130       strncpy ( Date9,Date11,3 );
131       i = 0;
132       while ((i<12) && (strncmp(nMonth[i],&(Date11[3]),2)))  i++;
133       if (i<12)  {
134         strncpy ( &(Date9[3]),Month[i],3 );
135         strncpy ( &(Date9[7]),&(Date11[8]),2 );
136         Date9[2] = '-';
137         Date9[6] = '-';
138       } else
139         strcpy ( Date9,"         " );
140     }
141   }
142 
Date9toCIF(cpstr Date9,pstr DateCIF)143   void  Date9toCIF ( cpstr Date9, pstr DateCIF )  {
144   //  DD-MMM-YY -> YYYY-MM-DD             )
145   int  i;
146     i = 0;
147     while ((i<12) && (strncmp(Month[i],&(Date9[3]),3)))  i++;
148     if (i<12)  {   //  DD-MMM-YY  -> YYYY-MM-DD
149       if (Date9[7]!='0')  strcpy ( DateCIF,"19" );
150                     else  strcpy ( DateCIF,"20" );
151       strncpy ( &(DateCIF[2]),&(Date9[7]),2 );
152       strncpy ( &(DateCIF[5]),nMonth[i],2 );
153     } else  {      //  DD-MM-YY  ->  YYYY-MM-DD
154       if (Date9[6]!='0')  strcpy ( DateCIF,"19" );
155                     else  strcpy ( DateCIF,"20" );
156       strncpy ( &(DateCIF[2]),&(Date9[6]),2 );
157       strncpy ( &(DateCIF[5]),&(Date9[3]),2 );
158     }
159     DateCIF[4] = '-';
160     DateCIF[7] = '-';
161     strncpy ( &(DateCIF[8]),Date9,2 );
162     DateCIF[10] = char(0);
163   }
164 
Date11toCIF(cpstr Date11,pstr DateCIF)165   void  Date11toCIF ( cpstr Date11, pstr DateCIF )  {
166   //  DD-MMM-YYYY -> YYYY-MM-DD
167   int  i;
168     i = 0;
169     while ((i<12) && (strncmp(Month[i],&(Date11[3]),3)))  i++;
170     if (i<12) {
171       strncpy ( DateCIF,&(Date11[7]),4 );
172       strncpy ( &(DateCIF[5]),nMonth[i],2 );
173     } else  {
174       strncpy ( DateCIF,&(Date11[6]),4 );
175       strncpy ( &(DateCIF[5]),&(Date11[3]),2 );
176     }
177     DateCIF[4] = '-';
178     DateCIF[7] = '-';
179     strncpy ( &(DateCIF[8]),Date11,2 );
180     DateCIF[10] = char(0);
181   }
182 
DateCIFto9(cpstr DateCIF,pstr Date9)183   void  DateCIFto9 ( cpstr DateCIF, pstr Date9 )  {
184   //  YYYY-MM-DD -> DD-MMM-YY
185   int  i;
186     strncpy ( Date9,&(DateCIF[8]),2 );
187     Date9[2] = '-';
188     i = 0;
189     while ((i<12) && (strncmp(nMonth[i],&(DateCIF[5]),2)))  i++;
190     if (i<12) strncpy ( &(Date9[3]),Month[i],3 );
191     else  {
192       strncpy ( &(Date9[3]),&(DateCIF[5]),2 );
193       Date9[5] = 'X';
194     }
195     Date9[6] = '-';
196     strncpy ( &(Date9[7]),&(DateCIF[2]),2 );
197   //  DateCIF[9] = char(0);
198   }
199 
DateCIFto11(cpstr DateCIF,pstr Date11)200   void  DateCIFto11 ( cpstr DateCIF, pstr Date11 )  {
201   //  YYYY-MM-DD  -> DD-MMM-YYYY
202   int  i;
203     strncpy ( Date11,&(DateCIF[8]),2 );
204     Date11[2] = '-';
205     i = 0;
206     while ((i<12) && (strncmp(nMonth[i],&(DateCIF[5]),2)))  i++;
207     if (i<12) strncpy ( &(Date11[3]),Month[i],3 );
208     else  {
209       strncpy ( &(Date11[3]),&(DateCIF[5]),2 );
210       Date11[5] = 'X';
211     }
212     Date11[6] = '-';
213     strncpy ( &(Date11[7]),DateCIF,4 );
214   //  DateCIF[11] = char(0);
215   }
216 
217 
218   //  =============== Format functions  ===================
219 
GetInteger(int & N,cpstr S,int M)220   bool GetInteger ( int & N, cpstr S, int M )  {
221   //   Returns true if S contains an integer number in its
222   // first M characters. This number is returned in N.
223   //   The return is false if no integer number may be
224   // recognized. In this case, N is assigned MinInt4 value.
225   pstr endptr;
226   char L[50];
227     strncpy ( L,S,M );
228     L[M] = char(0);
229     N    = mround(strtod(L,&endptr));
230     if ((N==0) && (endptr==L))  {
231       N = MinInt4;  // no number
232       return false;
233     } else
234       return true;
235   }
236 
GetReal(realtype & R,cpstr S,int M)237   bool GetReal ( realtype & R, cpstr S, int M )  {
238   //   Returns true if S contains a real number in its
239   // first M characters. This number is returned in R.
240   //   The return is false if no real number may be
241   // recognized. In this case, R is assigned -MaxReal value.
242   pstr endptr;
243   char L[50];
244     strncpy ( L,S,M );
245     L[M] = char(0);
246     R    = strtod(L,&endptr);
247     if ((R==0.0) && (endptr==L))  {
248       R = -MaxReal;  // no number
249       return false;
250     } else
251       return true;
252   }
253 
GetIntIns(int & N,pstr ins,cpstr S,int M)254   bool  GetIntIns ( int & N, pstr ins, cpstr S, int M )  {
255   //   Returns true if S contains an integer number in its
256   // first M characters. This number is returned in N. In addition
257   // to that, GetIntIns() retrieves the insertion code which may
258   // follow the integer and returns it in "ins" (1 character +
259   // terminating 0).
260   //   The return is false if no integer number may be
261   // recognized. In this case, N is assigned MinInt4 value,
262   // "ins" just returns (M+1)th symbol of S (+terminating 0).
263   pstr endptr;
264   char L[50];
265 
266     if (S[M]!=' ')  {
267       ins[0] = S[M];
268       ins[1] = char(0);
269     } else
270       ins[0] = char(0);
271 
272     strncpy ( L,S,M );
273     L[M] = char(0);
274     if ((M==4) && ((S[0]>='A') || ((S[0]=='-') && (S[1]>='A'))))
275       hy36decode ( M,L,M,&N);
276     else  {
277       endptr = NULL;
278       N      = mround(strtod(L,&endptr));
279       if ((N==0) && (endptr==L))  {
280         N = MinInt4;  // no number
281         return false;
282       }
283     }
284 
285     return true;
286 
287   }
288 
PutInteger(pstr S,int N,int M)289   void  PutInteger ( pstr S, int N, int M )  {
290   //  Integer N is converted into ASCII string of length M
291   // and pasted onto first M characters of string S. No
292   // terminating zero is added.
293   //  If N is set to MinInt4, then first M characters of
294   // string S are set to the space character.
295   char L[50];
296   int  i;
297     if (N==MinInt4)
298       for (i=0;i<M;i++)
299         S[i] = ' ';
300     else  {
301       sprintf ( L,"%*i",M,N );
302       strncpy ( S,L,M );
303     }
304   }
305 
PutRealF(pstr S,realtype R,int M,int L)306   void  PutRealF ( pstr S, realtype R, int M, int L )  {
307   //  Real R is converted into ASCII string of length M
308   // and pasted onto first M characters of string S. No
309   // terminating zero is added. The conversion is done
310   // according to fixed format FM.L
311   //  If R is set to -MaxReal, then first M characters of
312   // string S are set to the space character.
313   char N[50];
314   int  i;
315     if (R==-MaxReal)
316       for (i=0;i<M;i++)
317         S[i] = ' ';
318     else  {
319       sprintf ( N,"%*.*f",M,L,R );
320       strncpy ( S,N,M );
321     }
322   }
323 
CIFGetIntegerD(int & I,mmcif::PLoop Loop,cpstr Tag,int defValue)324   ERROR_CODE CIFGetIntegerD ( int & I, mmcif::PLoop Loop, cpstr Tag,
325                              int defValue )  {
326   int        Signal;
327   ERROR_CODE RC;
328     Signal = 0;
329     RC = CIFGetInteger ( I,Loop,Tag,Signal );
330     if (RC)
331       I = defValue;
332     return RC;
333   }
334 
CIFGetInteger(int & I,mmcif::PLoop Loop,cpstr Tag,int & Signal)335   ERROR_CODE CIFGetInteger ( int & I, mmcif::PLoop Loop, cpstr Tag,
336                              int & Signal )  {
337   pstr F;
338   int  RC;
339     RC = Loop->GetInteger ( I,Tag,Signal,true );
340     if (RC==mmcif::CIFRC_WrongFormat)  {
341       F = Loop->GetString ( Tag,Signal,RC );
342       if (F) sprintf ( CIFErrorLocation,"loop %s.%s row %i data %s",
343                        Loop->GetCategoryName(),Tag,Signal,F );
344         else sprintf ( CIFErrorLocation,"loop %s.%s row %i data [NULL]",
345                        Loop->GetCategoryName(),Tag,Signal );
346       Signal = -Error_UnrecognizedInteger-1;
347       return Error_UnrecognizedInteger;
348     }
349     if (RC==mmcif::CIFRC_WrongIndex)  {
350       Signal = -1;
351       return Error_NoData;
352     }
353     if (RC)  {
354       F = Loop->GetString ( Tag,Signal,RC );
355       if (F) sprintf ( CIFErrorLocation,"loop %s.%s row %i data %s",
356                        Loop->GetCategoryName(),Tag,Signal,F );
357         else sprintf ( CIFErrorLocation,"loop %s.%s row %i data [NULL]",
358                        Loop->GetCategoryName(),Tag,Signal );
359       Signal = -Error_NoData-1;
360       return Error_NoData;
361     }
362     return Error_NoError;
363   }
364 
365 
CIFGetInteger1(int & I,mmcif::PLoop Loop,cpstr Tag,int nrow)366   ERROR_CODE CIFGetInteger1 ( int & I, mmcif::PLoop Loop, cpstr Tag,
367                               int nrow )  {
368   pstr F;
369   int  RC;
370     RC = Loop->GetInteger ( I,Tag,nrow,true );
371     if (RC==mmcif::CIFRC_WrongFormat)  {
372       F = Loop->GetString ( Tag,nrow,RC );
373       if (F) sprintf ( CIFErrorLocation,"loop %s.%s row %i data %s",
374                        Loop->GetCategoryName(),Tag,nrow,F );
375         else sprintf ( CIFErrorLocation,"loop %s.%s row %i data [NULL]",
376                        Loop->GetCategoryName(),Tag,nrow );
377       return Error_UnrecognizedInteger;
378     }
379     if (RC==mmcif::CIFRC_WrongIndex)
380       return Error_NoData;
381     if (RC)  {
382       F = Loop->GetString ( Tag,nrow,RC );
383       if (F) sprintf ( CIFErrorLocation,"loop %s.%s row %i data %s",
384                        Loop->GetCategoryName(),Tag,nrow,F );
385         else sprintf ( CIFErrorLocation,"loop %s.%s row %i data [NULL]",
386                        Loop->GetCategoryName(),Tag,nrow );
387       return Error_NoData;
388     }
389     return Error_NoError;
390   }
391 
392 
CIFGetReal(realtype & R,mmcif::PLoop Loop,cpstr Tag,int & Signal)393   ERROR_CODE CIFGetReal ( realtype & R, mmcif::PLoop Loop, cpstr Tag,
394                           int & Signal )  {
395   pstr F;
396   int  RC;
397     RC = Loop->GetReal ( R,Tag,Signal,true );
398     if (RC==mmcif::CIFRC_WrongFormat)  {
399       F = Loop->GetString ( Tag,Signal,RC );
400       if (F) sprintf ( CIFErrorLocation,"loop %s.%s row %i data %s",
401                        Loop->GetCategoryName(),Tag,Signal,F );
402         else sprintf ( CIFErrorLocation,"loop %s.%s row %i data [NULL]",
403                        Loop->GetCategoryName(),Tag,Signal );
404       Signal = -Error_UnrecognizedReal-1;
405       return Error_UnrecognizedReal;
406     }
407     if (RC==mmcif::CIFRC_WrongIndex)  {
408       Signal = -1;
409       return Error_NoData;
410     }
411     if (RC)  {
412       F = Loop->GetString ( Tag,Signal,RC );
413       if (F) sprintf ( CIFErrorLocation,"loop %s.%s row %i data %s",
414                        Loop->GetCategoryName(),Tag,Signal,F );
415         else sprintf ( CIFErrorLocation,"loop %s.%s row %i data [NULL]",
416                        Loop->GetCategoryName(),Tag,Signal );
417       Signal = -Error_NoData-1;
418       return Error_NoData;
419     }
420     return Error_NoError;
421   }
422 
423 
CIFGetReal1(realtype & R,mmcif::PLoop Loop,cpstr Tag,int nrow)424   ERROR_CODE CIFGetReal1 ( realtype & R, mmcif::PLoop Loop, cpstr Tag,
425                            int nrow )  {
426   pstr F;
427   int  RC;
428     RC = Loop->GetReal ( R,Tag,nrow,true );
429     if (RC==mmcif::CIFRC_WrongFormat)  {
430       F = Loop->GetString ( Tag,nrow,RC );
431       if (F) sprintf ( CIFErrorLocation,"loop %s.%s row %i data %s",
432                        Loop->GetCategoryName(),Tag,nrow,F );
433         else sprintf ( CIFErrorLocation,"loop %s.%s row %i data [NULL]",
434                        Loop->GetCategoryName(),Tag,nrow );
435       return Error_UnrecognizedReal;
436     }
437     if (RC==mmcif::CIFRC_WrongIndex)
438       return Error_NoData;
439     if (RC)  {
440       F = Loop->GetString ( Tag,nrow,RC );
441       if (F) sprintf ( CIFErrorLocation,"loop %s.%s row %i data %s",
442                        Loop->GetCategoryName(),Tag,nrow,F );
443         else sprintf ( CIFErrorLocation,"loop %s.%s row %i data [NULL]",
444                        Loop->GetCategoryName(),Tag,nrow );
445       return Error_NoData;
446     }
447     return Error_NoError;
448   }
449 
450 
CIFGetString(pstr S,mmcif::PLoop Loop,cpstr Tag,int row,int SLen,cpstr DefS)451   ERROR_CODE CIFGetString ( pstr S, mmcif::PLoop Loop, cpstr Tag,
452                             int row, int SLen, cpstr DefS )  {
453   pstr F;
454   int RC;
455     F = Loop->GetString ( Tag,row,RC );
456     if ((!RC) && F)  {
457       strncpy ( S,F,SLen-1 );
458       Loop->DeleteField ( Tag,row );
459       return Error_NoError;
460     } else  {
461       strcpy ( S,DefS );
462       return Error_EmptyCIFLoop;
463     }
464   }
465 
466 
CIFGetInteger(int & I,mmcif::PStruct Struct,cpstr Tag,bool Remove)467   ERROR_CODE CIFGetInteger ( int & I, mmcif::PStruct Struct, cpstr Tag,
468                              bool Remove )  {
469   pstr F;
470   int  RC;
471     RC = Struct->GetInteger ( I,Tag,Remove );
472     if (RC==mmcif::CIFRC_WrongFormat)  {
473       F = Struct->GetString ( Tag,RC );
474       if (F) sprintf ( CIFErrorLocation,"structure %s.%s data %s",
475                        Struct->GetCategoryName(),Tag,F );
476         else sprintf ( CIFErrorLocation,"structure %s.%s data [NULL]",
477                        Struct->GetCategoryName(),Tag );
478       return Error_UnrecognizedInteger;
479     }
480     if (RC)  {
481       F = Struct->GetString ( Tag,RC );
482       if (F) sprintf ( CIFErrorLocation,"structure %s.%s data %s",
483                        Struct->GetCategoryName(),Tag,F );
484         else sprintf ( CIFErrorLocation,"structure %s.%s data [NULL]",
485                        Struct->GetCategoryName(),Tag );
486       return Error_NoData;
487     }
488     return Error_NoError;
489   }
490 
CIFGetReal(realtype & R,mmcif::PStruct Struct,cpstr Tag,bool Remove)491   ERROR_CODE CIFGetReal ( realtype & R, mmcif::PStruct Struct, cpstr Tag,
492                           bool Remove )  {
493   pstr F;
494   int RC;
495     RC = Struct->GetReal ( R,Tag,Remove );
496     if (RC==mmcif::CIFRC_WrongFormat)  {
497       F = Struct->GetString ( Tag,RC );
498       if (F) sprintf ( CIFErrorLocation,"structure %s.%s data %s",
499                        Struct->GetCategoryName(),Tag,F );
500         else sprintf ( CIFErrorLocation,"structure %s.%s data [NULL]",
501                        Struct->GetCategoryName(),Tag );
502       return Error_UnrecognizedReal;
503     }
504     if (RC)  {
505       F = Struct->GetString ( Tag,RC );
506       if (F) sprintf ( CIFErrorLocation,"structure %s.%s data %s",
507                        Struct->GetCategoryName(),Tag,F );
508         else sprintf ( CIFErrorLocation,"structure %s.%s data [NULL]",
509                        Struct->GetCategoryName(),Tag );
510       return Error_NoData;
511     }
512     return Error_NoError;
513   }
514 
CIFGetString(pstr S,mmcif::PStruct Struct,cpstr Tag,int SLen,cpstr DefS,bool Remove)515   ERROR_CODE CIFGetString ( pstr S, mmcif::PStruct Struct, cpstr Tag,
516                             int SLen, cpstr DefS, bool Remove )  {
517   pstr F;
518   int  RC;
519     F = Struct->GetString ( Tag,RC );
520     if ((!RC) && F)  {
521       strcpy_n0 ( S,F,SLen-1 );
522       if (Remove)  Struct->DeleteField ( Tag );
523       return Error_NoError;
524     } else  {
525       strcpy ( S,DefS );
526       return Error_EmptyCIFStruct;
527     }
528   }
529 
530 
PutIntIns(pstr S,int N,int M,cpstr ins)531   void  PutIntIns ( pstr S, int N, int M, cpstr ins )  {
532   //  Integer N is converted into ASCII string of length M
533   // and pasted onto first M characters of string S. No
534   // terminating zero is added. The insert code ins is put
535   // immediately after the integer.
536   //  If N is set to MinInt4, then first M+1 characters of
537   // string S are set to space, and no insert code are
538   // appended.
539   char L[50];
540   int  i;
541 
542     if (N==MinInt4)  {
543       for (i=0;i<=M;i++)
544         S[i] = ' ';
545     } else  {
546       if ((M!=4) || ((N>=-999) && (N<=9999)))
547            sprintf    ( L,"%*i",M,N );
548       else hy36encode ( M,N,L );
549       strcpy_n1 ( S,L,M );
550       if (ins[0]) S[M] = ins[0];
551     }
552 
553   }
554 
555 
Mat4Inverse(const mat44 & A,mat44 & AI)556   void  Mat4Inverse ( const mat44 & A, mat44 & AI )  {
557   //       ***  FORMER RBRINV(A,AI)  ***
558   //   Function to invert 4*4 matrices (AI=A^{-1})
559   mat44    c;
560   mat33    x;
561   realtype s,s1;
562   int      ii,jj,i,i1,j,j1;
563 
564   // ---- Get cofactors of 'a' in array 'c'
565 
566     s1 = 1.0;
567     for (ii=0;ii<4;ii++)  {
568       s = s1;
569       for (jj=0;jj<4;jj++)  {
570         i = -1;
571         for (i1=0;i1<4;i1++)
572           if (i1!=ii)  {
573             i++;
574             j = -1;
575             for (j1=0;j1<4;j1++)
576               if (j1!=jj)  {
577                 j++;
578                 x[i][j] = A[i1][j1];
579               }
580           }
581         c[ii][jj] = s*(x[0][0]*(x[1][1]*x[2][2]-x[1][2]*x[2][1]) +
582                        x[0][1]*(x[1][2]*x[2][0]-x[1][0]*x[2][2]) +
583                        x[0][2]*(x[1][0]*x[2][1]-x[1][1]*x[2][0]));
584         s = -s;
585       }
586       s1 = -s1;
587     }
588 
589   // ---- Calculate determinant
590 
591     s = 0.0;
592     for (i=0;i<4;i++)
593       s += A[i][0]*c[i][0];
594 
595   // ---- Get inverse matrix
596 
597     if (s!=0.0)
598       for (i=0;i<4;i++)
599         for (j=0;j<4;j++)
600           AI[i][j] = c[j][i]/s;
601 
602   }
603 
Mat3Inverse(const mat33 & A,mat33 & AI)604   realtype Mat3Inverse ( const mat33 & A, mat33 & AI )  {
605   mat33    c,x;
606   realtype s;
607   int      ii,jj,i,i1,j,j1;
608 
609     // Get cofactors of 'a' in array 'c'
610 
611     s = 1.0;
612     for (ii=0;ii<3;ii++)
613       for (jj=0;jj<3;jj++)  {
614         i = -1;
615         for (i1=0;i1<3;i1++)
616           if (i1!=ii)  {
617             i++;
618             j = -1;
619             for (j1=0;j1<3;j1++)
620               if (j1!=jj)  {
621                 j++;
622                 x[i][j] = A[i1][j1];
623               }
624           }
625         c[ii][jj] = s*(x[0][0]*x[1][1]-x[0][1]*x[1][0]);
626         s = -s;
627       }
628 
629     // Calculate determinant
630 
631     s = 0.0;
632     for (i=0;i<3;i++)
633       s += A[i][0]*c[i][0];
634 
635     // Get inverse matrix
636 
637     if (s!=0.0)
638       for (i=0;i<3;i++)
639         for (j=0;j<3;j++)
640           AI[i][j] = c[j][i]/s;
641 
642     return s;
643 
644   }
645 
Mat4Mult(mat44 & A,const mat44 & B,const mat44 & C)646   void  Mat4Mult ( mat44 & A, const mat44 & B, const mat44 & C )  {
647   //  Calculates A=B*C
648   int i,j,k;
649     for (i=0;i<4;i++)
650       for (j=0;j<4;j++)  {
651         A[i][j] = 0.0;
652         for (k=0;k<4;k++)
653           A[i][j] += B[i][k]*C[k][j];
654       }
655   }
656 
Mat4Div1(mat44 & A,const mat44 & B,const mat44 & C)657   void  Mat4Div1 ( mat44 & A, const mat44 & B, const mat44 & C )  {
658   //  Calculates A=B^{-1}*C
659   mat44 B1;
660   int   i,j,k;
661     B1[0][0] = 1.0; // in order to supress warnings from some
662                     // stupid compilers
663     Mat4Inverse ( B,B1 );
664     for (i=0;i<4;i++)
665       for (j=0;j<4;j++)  {
666         A[i][j] = 0.0;
667         for (k=0;k<4;k++)
668           A[i][j] += B1[i][k]*C[k][j];
669       }
670   }
671 
Mat4Div2(mat44 & A,const mat44 & B,const mat44 & C)672   void  Mat4Div2 ( mat44 & A, const mat44 & B, const mat44 & C )  {
673   //  Calculates A=B*C^{-1}
674   mat44 C1;
675   int   i,j,k;
676     C1[0][0] = 1.0; // in order to supress warnings from some
677                     // stupid compilers
678     Mat4Inverse ( C,C1 );
679     for (i=0;i<4;i++)
680       for (j=0;j<4;j++)  {
681         A[i][j] = 0.0;
682         for (k=0;k<4;k++)
683           A[i][j] += B[i][k]*C1[k][j];
684       }
685   }
686 
Mat4Init(mat44 & A)687   void  Mat4Init ( mat44 & A )  {
688   int i,j;
689     for (i=0;i<4;i++)  {
690       for (j=0;j<4;j++)
691         A[i][j] = 0.0;
692       A[i][i] = 1.0;
693     }
694   }
695 
Mat4RotDet(const mat44 & T)696   realtype Mat4RotDet ( const mat44 & T )  {
697   //  returns determinant of the rotation part
698     return T[0][0]*T[1][1]*T[2][2] +
699            T[0][1]*T[1][2]*T[2][0] +
700            T[1][0]*T[2][1]*T[0][2] -
701            T[0][2]*T[1][1]*T[2][0] -
702            T[0][0]*T[1][2]*T[2][1] -
703            T[2][2]*T[0][1]*T[1][0];
704   }
705 
isMat4Unit(const mat44 & A,realtype eps,bool rotOnly)706   bool isMat4Unit ( const mat44 & A, realtype eps, bool rotOnly )  {
707   // returns true if A is a unit 4x4 matrix
708   int     i,j,k;
709   bool B;
710 
711     if (rotOnly)  k = 3;
712             else  k = 4;
713 
714     B = true;
715     for (i=0;(i<k) && B;i++)
716       for (j=0;(j<k) && B;j++)
717         if (i==j)  B = (fabs(1.0-A[i][j])<eps);
718              else  B = (fabs(A[i][j])<eps);
719 
720     return B;
721 
722   }
723 
Mat3Init(mat33 & A)724   void  Mat3Init ( mat33 & A )  {
725   int i,j;
726     for (i=0;i<3;i++)  {
727       for (j=0;j<3;j++)
728         A[i][j] = 0.0;
729       A[i][i] = 1.0;
730     }
731   }
732 
Mat4Copy(const mat44 & A,mat44 & ACopy)733   void  Mat4Copy ( const mat44 & A, mat44 & ACopy )  {
734   int i,j;
735     for (i=0;i<4;i++)
736       for (j=0;j<4;j++)
737         ACopy[i][j] = A[i][j];
738   }
739 
Mat3Copy(const mat33 & A,mat33 & ACopy)740   void  Mat3Copy ( const mat33 & A, mat33 & ACopy )  {
741   int i,j;
742     for (i=0;i<3;i++)
743       for (j=0;j<3;j++)
744         ACopy[i][j] = A[i][j];
745   }
746 
isMat4Eq(const mat44 & A,const mat44 & B,realtype eps,bool rotOnly)747   bool isMat4Eq ( const mat44 & A, const mat44 & B, realtype eps,
748                   bool rotOnly )  {
749   // returns true if A is equal to B within precision eps
750   int  i,j,k;
751   bool Eq;
752 
753     if (rotOnly)  k = 3;
754             else  k = 4;
755 
756     Eq = true;
757     for (i=0;(i<k) && Eq;i++)
758       for (j=0;(j<k) && Eq;j++)
759         Eq = (fabs(A[i][j]-B[i][j])<eps);
760 
761     return Eq;
762 
763   }
764 
765 
TransformXYZ(const mat44 & T,realtype & X,realtype & Y,realtype & Z)766   void TransformXYZ ( const mat44 & T, realtype & X, realtype & Y,
767                                                      realtype & Z )  {
768   realtype x1,y1,z1;
769     x1 = T[0][0]*X + T[0][1]*Y + T[0][2]*Z + T[0][3];
770     y1 = T[1][0]*X + T[1][1]*Y + T[1][2]*Z + T[1][3];
771     z1 = T[2][0]*X + T[2][1]*Y + T[2][2]*Z + T[2][3];
772     X = x1;
773     Y = y1;
774     Z = z1;
775   }
776 
TransformX(const mat44 & T,realtype X,realtype Y,realtype Z)777   realtype TransformX ( const mat44 & T, realtype X, realtype Y,
778                                                      realtype Z )  {
779     return  T[0][0]*X + T[0][1]*Y + T[0][2]*Z + T[0][3];
780   }
781 
TransformY(const mat44 & T,realtype X,realtype Y,realtype Z)782   realtype TransformY ( const mat44 & T, realtype X, realtype Y,
783                                                      realtype Z )  {
784     return  T[1][0]*X + T[1][1]*Y + T[1][2]*Z + T[1][3];
785   }
786 
TransformZ(const mat44 & T,realtype X,realtype Y,realtype Z)787   realtype TransformZ ( const mat44 & T, realtype X, realtype Y,
788                                                      realtype Z )  {
789     return  T[2][0]*X + T[2][1]*Y + T[2][2]*Z + T[2][3];
790   }
791 
792 
793 
794 
795   char CIFErrorLocation[200] = "no error";
796 
797   static cpstr msWrongSection =
798     "Wrong section. The sections in PDB file may be put in wrong order.";
799   static cpstr msWrongChainID =
800     "Wrong chain ID. The input may have changed to another chain.";
801   static cpstr msWrongEntryID =
802     "Entry ID does not match the header.";
803 
804   static cpstr msSEQRES_serNum   =
805     "Serial numbers of SEQRES records do not increment by 1.";
806   static cpstr msSEQRES_numRes   =
807     "Different SEQRES records show different numbers of residues.";
808   static cpstr msSEQRES_extraRes =
809     "SEQRES records contain more residues than specified.";
810 
811   static cpstr msNCSM_Unrecognized =
812     "Unrecognized numerical input in MTRIXn.";
813   static cpstr msNCSM_AlreadySet   =
814     "Duplicate MTRIXn record.";
815   static cpstr msNCSM_WrongSerial  =
816     "Serial number in MTRIXn record is wrong.";
817   static cpstr msNCSM_UnmatchIG    =
818     "Different MTRIXn record show different iGiven flag.";
819 
820   static cpstr msATOM_Unrecognized =
821     "Numerical information in ATOM record is not recognized.";
822   static cpstr msATOM_AlreadySet   =
823     "Atom is already in the system.";
824   static cpstr msATOM_NoResidue    =
825     "No residue is found for atom.";
826   static cpstr msATOM_Unmatch      =
827     "Unmatch in different records for the same atom.";
828 
829   static cpstr msCantOpenFile        = "File can not be opened.";
830   static cpstr msUnrecognizedInteger =
831     "Wrong ASCII format of an integer.";
832   static cpstr msWrongModelNo        = "Wrong model number.";
833   static cpstr msDuplicatedModel     = "Duplicate model number.";
834   static cpstr msNoModel             = "No model defined.";
835   static cpstr msForeignFile         =
836     "Attempt to read unknown-type file.";
837   static cpstr msWrongEdition        =
838     "Attempt to read a higher-version file.";
839 
840   static cpstr msNoData              = "Expected data field not found.";
841   static cpstr msUnrecognizedReal    = "Wrong ASCII format of a real.";
842   static cpstr msNotACIFFile         =
843     "Not a CIF file ('data_' missing).";
844   static cpstr msUnrecognCIFItems    =
845     "Unrecognized item(s) in CIF file.";
846   static cpstr msMissingCIFField     = "Expected CIF item(s) missing.";
847   static cpstr msEmptyCIFLoop        = "Empty CIF loop encountered.";
848   static cpstr msUnexpEndOfCIF       = "Unexpected end of CIF file.";
849   static cpstr msMissgCIFLoopField   = "Inconsistent CIF loop.";
850   static cpstr msNotACIFStructure    =
851     "Wrong use of CIF structure (as a loop?).";
852   static cpstr msNotACIFLoop         =
853     "Wrong use of CIF loop (as a structure?).";
854 
855   static cpstr msNoSheetID           = "No Sheet ID on PDB ASCII card.";
856   static cpstr msWrongSheetID        = "Wrong Sheet ID.";
857   static cpstr msWrongStrandNo       =
858     "Wrong Strand number on PDB SHEET card.";
859 
860   static cpstr msWrongNumberOfStrands =
861     "Wrong number of strands in CIF file.";
862   static cpstr msWrongSheetOrder     = "Incomplete _struct_sheet_order.";
863   static cpstr msHBondInconsistency  =
864     "Inconsistency in _struct_sheet_hbond.";
865 
866   static cpstr msEmptyResidueName    =
867           "No residue name on PDB ATOM or TER card.";
868   static cpstr msDuplicateSeqNum     =
869           "Duplicate sequence number and insertion code.";
870 
871   static cpstr msEmptyFile           = "Non-existent or empty file.";
872 
873   static cpstr msNoLogicalName       = "Logical file name not found.";
874 
875 
GetErrorDescription(ERROR_CODE ErrorCode)876   cpstr  GetErrorDescription ( ERROR_CODE ErrorCode )  {
877 
878     switch (ErrorCode)  {
879 
880       case Error_NoError              :  return "No errors.";
881 
882       case Error_WrongSection         :  return msWrongSection;
883       case Error_WrongChainID         :  return msWrongChainID;
884       case Error_WrongEntryID         :  return msWrongEntryID;
885 
886       case Error_SEQRES_serNum        :  return msSEQRES_serNum;
887       case Error_SEQRES_numRes        :  return msSEQRES_numRes;
888       case Error_SEQRES_extraRes      :  return msSEQRES_extraRes;
889 
890       case Error_NCSM_Unrecognized    :  return msNCSM_Unrecognized;
891       case Error_NCSM_AlreadySet      :  return msNCSM_AlreadySet;
892       case Error_NCSM_WrongSerial     :  return msNCSM_WrongSerial;
893       case Error_NCSM_UnmatchIG       :  return msNCSM_UnmatchIG;
894 
895       case Error_ATOM_Unrecognized    :  return msATOM_Unrecognized;
896       case Error_ATOM_AlreadySet      :  return msATOM_AlreadySet;
897       case Error_ATOM_NoResidue       :  return msATOM_NoResidue;
898       case Error_ATOM_Unmatch         :  return msATOM_Unmatch;
899 
900       case Error_CantOpenFile         :  return msCantOpenFile;
901       case Error_UnrecognizedInteger  :  return msUnrecognizedInteger;
902       case Error_WrongModelNo         :  return msWrongModelNo;
903       case Error_DuplicatedModel      :  return msDuplicatedModel;
904       case Error_NoModel              :  return msNoModel;
905       case Error_ForeignFile          :  return msForeignFile;
906       case Error_WrongEdition         :  return msWrongEdition;
907 
908       case Error_NoData               :  return msNoData;
909       case Error_UnrecognizedReal     :  return msUnrecognizedReal;
910       case Error_NotACIFFile          :  return msNotACIFFile;
911       case Error_UnrecognCIFItems     :  return msUnrecognCIFItems;
912       case Error_MissingCIFField      :  return msMissingCIFField;
913       case Error_EmptyCIFLoop         :  return msEmptyCIFLoop;
914       case Error_UnexpEndOfCIF        :  return msUnexpEndOfCIF;
915       case Error_MissgCIFLoopField    :  return msMissgCIFLoopField;
916       case Error_NotACIFStructure     :  return msNotACIFStructure;
917       case Error_NotACIFLoop          :  return msNotACIFLoop;
918 
919       case Error_NoSheetID            :  return msNoSheetID;
920       case Error_WrongSheetID         :  return msWrongSheetID;
921       case Error_WrongStrandNo        :  return msWrongStrandNo;
922 
923       case Error_WrongNumberOfStrands :  return msWrongNumberOfStrands;
924       case Error_WrongSheetOrder      :  return msWrongSheetOrder;
925       case Error_HBondInconsistency   :  return msHBondInconsistency;
926 
927       case Error_EmptyResidueName     :  return msEmptyResidueName;
928       case Error_DuplicateSeqNum      :  return msDuplicateSeqNum;
929 
930       case Error_EmptyFile            :  return msEmptyFile;
931 
932       case Error_NoLogicalName        :  return msNoLogicalName;
933 
934       default                         :  return "Unknown error.";
935 
936     }
937   }
938 
939 
940   //  ==============  ContainerClass  ====================
941 
ContainerClass()942   ContainerClass::ContainerClass() : io::Stream()  {
943     ContinuationNo = 0;
944   }
945 
ContainerClass(io::RPStream Object)946   ContainerClass::ContainerClass ( io::RPStream Object )
947                  : io::Stream(Object)  {
948     ContinuationNo = 0;
949   }
950 
Append(PContainerClass CC)951   bool  ContainerClass::Append ( PContainerClass CC )  {
952     return  (CC->ContinuationNo>1);
953   }
954 
955 
956   //  ===================  ContString  =====================
957 
ContString()958   ContString::ContString() : ContainerClass()  {
959     InitString();
960   }
961 
ContString(cpstr S)962   ContString::ContString ( cpstr S ) : ContainerClass()  {
963     InitString();
964     ConvertPDBASCII ( S );
965   }
966 
ContString(io::RPStream Object)967   ContString::ContString ( io::RPStream Object )
968              : ContainerClass(Object)  {
969     InitString();
970   }
971 
~ContString()972   ContString::~ContString() {
973     if (Line)        delete[] Line;
974     if (CIFCategory) delete[] CIFCategory;
975     if (CIFTag)      delete[] CIFTag;
976   }
977 
InitString()978   void  ContString::InitString()  {
979     Line        = NULL;
980     CIFCategory = NULL;
981     CIFTag      = NULL;
982   }
983 
ConvertPDBASCII(cpstr S)984   ERROR_CODE ContString::ConvertPDBASCII ( cpstr S )  {
985     CreateCopy ( Line,S );
986     return Error_NoError;
987   }
988 
PDBASCIIDump(pstr S,int)989   void  ContString::PDBASCIIDump ( pstr S, int )  {
990     if (Line)  strcpy ( S,Line );
991          else  strcpy ( S,""   );
992   }
993 
PDBASCIIDump1(io::RFile f)994   bool ContString::PDBASCIIDump1 ( io::RFile f )  {
995     if (Line)  f.WriteLine ( Line );
996          else  f.LF();
997     return true;
998   }
999 
1000 /*
1001   void ContString::GetCIF1 ( mmcif::PData CIF, ERROR_CODE & Signal,
1002                              int & pos )  {
1003   pstr F;
1004   int  i,RC;
1005   char c;
1006     if ((!CIFCategory) || (!CIFTag))  {
1007       Signal = Error_EmptyCIF;
1008       return;
1009     }
1010     F = CIF->GetString ( CIFCategory,CIFTag,RC );
1011     if (RC || (!F))  {
1012       Signal = Error_EmptyCIF;
1013       return;
1014     }
1015     if (Signal>=(int)strlen(F))  {
1016       CIF->DeleteField ( CIFCategory,CIFTag );
1017       Signal = Error_EmptyCIF;
1018       return;
1019     }
1020 //    i = Signal;
1021 //    while (F[i] && (F[i]!='\n') && (F[i]!='\r'))  i++;
1022 //    if ((Signal==0) && (i==0))  {
1023 //      i++;
1024 //      if (((F[Signal]=='\n') && (F[i]=='\r')) ||
1025 //          ((F[Signal]=='\r') && (F[i]=='\n')))  i++;
1026 //      Signal = i;
1027 //      while (F[i] && (F[i]!='\n') && (F[i]!='\r'))  i++;
1028 //    }
1029 //    c = F[i];
1030 //    F[i] = char(0);
1031 //    CreateCopy ( Line,&(F[Signal]) );
1032 //    if (c)  {
1033 //      F[i]   = c;
1034 //      Signal = i+1;
1035 //      if (((c=='\n') && (F[Signal]=='\r')) ||
1036 //          ((c=='\r') && (F[Signal]=='\n')))  Signal++;
1037 //    } else
1038 //      CIF->DeleteField ( CIFCategory,CIFTag );
1039     i = pos;
1040     while (F[i] && (F[i]!='\n') && (F[i]!='\r'))  i++;
1041     if ((pos==0) && (i==0))  {
1042       i++;
1043       if (((F[pos]=='\n') && (F[i]=='\r')) ||
1044           ((F[pos]=='\r') && (F[i]=='\n')))  i++;
1045       pos = i;
1046       while (F[i] && (F[i]!='\n') && (F[i]!='\r'))  i++;
1047     }
1048     c = F[i];
1049     F[i] = char(0);
1050     CreateCopy ( Line,&(F[pos]) );
1051     if (c)  {
1052       F[i] = c;
1053       pos  = i+1;
1054       if (((c=='\n') && (F[pos]=='\r')) ||
1055           ((c=='\r') && (F[pos]=='\n')))  pos++;
1056     } else
1057       CIF->DeleteField ( CIFCategory,CIFTag );
1058   }
1059 */
1060 
MakeCIF(mmcif::PData CIF,int N)1061   void  ContString::MakeCIF ( mmcif::PData CIF, int N )  {
1062   pstr S;
1063     if ((!CIFCategory) || (!CIFTag))  return;
1064     S = new char[strlen(Line)+5];
1065     strcpy ( S,"\n" );
1066     strcat ( S,Line );
1067     CIF->PutString ( S,CIFCategory,CIFTag,(N!=0) );
1068     delete[] S;
1069   }
1070 
Append(PContainerClass CC)1071   bool  ContString::Append ( PContainerClass CC )  {
1072     if (ContainerClass::Append(CC))  {
1073       if (!Line)  {
1074         Line = PContString(CC)->Line;
1075         PContString(CC)->Line = NULL;
1076       } else
1077         CreateConcat ( Line,pstr("\n"),PContString(CC)->Line );
1078       return true;
1079     }
1080     return false;
1081   }
1082 
Copy(PContainerClass CString)1083   void  ContString::Copy ( PContainerClass CString )  {
1084     CreateCopy ( Line,PContString(CString)->Line );
1085   }
1086 
write(io::RFile f)1087   void  ContString::write ( io::RFile f )  {
1088   byte Version=1;
1089     f.WriteByte   ( &Version    );
1090     f.CreateWrite ( Line        );
1091     f.CreateWrite ( CIFCategory );
1092     f.CreateWrite ( CIFTag      );
1093   }
1094 
read(io::RFile f)1095   void  ContString::read ( io::RFile f )  {
1096   byte Version;
1097     f.ReadByte   ( &Version    );
1098     f.CreateRead ( Line        );
1099     f.CreateRead ( CIFCategory );
1100     f.CreateRead ( CIFTag      );
1101   }
1102 
1103   MakeStreamFunctions(ContString)
1104 
1105 
1106 
1107   //  ==============  ClassContainer  ====================
1108 
MakeStreamFunctions(ContainerClass)1109   MakeStreamFunctions(ContainerClass)
1110 
1111   ClassContainer::ClassContainer() : io::Stream()  {
1112     Init();
1113   }
1114 
ClassContainer(io::RPStream Object)1115   ClassContainer::ClassContainer ( io::RPStream Object )
1116                   : io::Stream(Object)  {
1117     Init();
1118   }
1119 
Init()1120   void ClassContainer::Init()  {
1121     length    = 0;
1122     Container = NULL;
1123   }
1124 
~ClassContainer()1125   ClassContainer::~ClassContainer()  {
1126     FreeContainer();
1127   }
1128 
FreeContainer()1129   void  ClassContainer::FreeContainer()  {
1130   int i;
1131     if (Container)  {
1132       for (i=0;i<length;i++)
1133         if (Container[i])
1134           delete Container[i];
1135       delete[] Container;
1136     }
1137     Container = NULL;
1138     length    = 0;
1139   }
1140 
AddData(PContainerClass Data)1141   void  ClassContainer::AddData ( PContainerClass Data )  {
1142   int               i;
1143   PPContainerClass C1;
1144     if (!Data)  return;
1145     if (length>0)  {
1146       i = length-1;
1147       while (i>=0)  {
1148         if (!Container[i])  i--;
1149         else if (Container[i]->GetClassID()!=Data->GetClassID())  i--;
1150         else break;
1151       }
1152       if (i>=0)  {
1153         if (Container[i]->Append(Data))  {
1154           delete Data;
1155           return;
1156         }
1157       }
1158     }
1159     C1 = new PContainerClass[length+1];
1160     for (i=0;i<length;i++)
1161       C1[i] = Container[i];
1162     C1[length] = Data;
1163     if (Container)  delete[] Container;
1164     Container = C1;
1165     length++;
1166   }
1167 
PDBASCIIDump(io::RFile f)1168   void  ClassContainer::PDBASCIIDump ( io::RFile f )  {
1169   char S[500];
1170   int  i,j;
1171     for (i=0;i<length;i++)
1172       if (Container[i])  {
1173         if (!Container[i]->PDBASCIIDump1(f))  {
1174           Container[i]->PDBASCIIDump ( S,i );
1175           j = strlen(S);
1176           while (j<80)  S[j++] = ' ';
1177           S[80] = char(0);
1178           f.WriteLine ( S );
1179         }
1180       }
1181   }
1182 
GetCIF(mmcif::PData CIF,int ClassID)1183   ERROR_CODE ClassContainer::GetCIF ( mmcif::PData CIF, int ClassID )  {
1184   PContainerClass ContainerClass;
1185   int             n;
1186   ERROR_CODE      rc;
1187     n = -1;
1188     do  {
1189       ContainerClass = MakeContainerClass ( ClassID );
1190       rc = ContainerClass->GetCIF ( CIF,n );
1191       if (rc==Error_NoError)
1192         AddData ( ContainerClass );
1193     } while (rc==Error_NoError);
1194     delete ContainerClass;
1195     if (rc==Error_EmptyCIF)
1196       rc = Error_NoError;
1197     return rc;
1198   }
1199 
MakeCIF(mmcif::PData CIF)1200   void  ClassContainer::MakeCIF ( mmcif::PData CIF )  {
1201   int i;
1202     for (i=0;i<length;i++)
1203       if (Container[i])
1204         Container[i]->MakeCIF ( CIF,i );
1205   }
1206 
write(io::RFile f)1207   void  ClassContainer::write ( io::RFile f )  {
1208   int  i,ClassID;
1209   byte Version=1;
1210     f.WriteByte ( &Version );
1211     f.WriteInt  ( &length  );
1212     for (i=0;i<length;i++)
1213       if (Container[i])  {
1214         ClassID = Container[i]->GetClassID();
1215         f.WriteInt ( &ClassID );
1216         Container[i]->write ( f );
1217       } else  {
1218         ClassID = -1;
1219         f.WriteInt ( &ClassID );
1220       }
1221   }
1222 
MakeContainerClass(int ClassID)1223   PContainerClass ClassContainer::MakeContainerClass ( int ClassID )  {
1224     if (ClassID==ClassID_String)  return new ContString();
1225     return new ContainerClass();
1226   }
1227 
GetContainerClass(int ContClassNo)1228   PContainerClass ClassContainer::GetContainerClass (int ContClassNo) {
1229     if ((ContClassNo<0) || (ContClassNo>=length))  return NULL;
1230     return Container[ContClassNo];
1231   }
1232 
Copy(PClassContainer CContainer)1233   void  ClassContainer::Copy ( PClassContainer CContainer )  {
1234   int i;
1235     FreeContainer();
1236     if (CContainer)  {
1237       length = CContainer->length;
1238       if (length>0)  {
1239         Container = new PContainerClass[length];
1240         for (i=0;i<length;i++)
1241           if (CContainer->Container[i])  {
1242             Container[i] = MakeContainerClass (
1243                               CContainer->Container[i]->GetClassID() );
1244             Container[i]->Copy ( CContainer->Container[i] );
1245           } else
1246             Container[i] = NULL;
1247       }
1248     }
1249   }
1250 
read(io::RFile f)1251   void  ClassContainer::read ( io::RFile f )  {
1252   int  i,ClassID;
1253   byte Version;
1254     FreeContainer();
1255     f.ReadByte ( &Version );
1256     f.ReadInt  ( &length  );
1257     if (length>0)  {
1258       Container = new PContainerClass[length];
1259       for (i=0;i<length;i++)  {
1260         f.ReadInt ( &ClassID );
1261         if (ClassID>=0)  {
1262           Container[i] = MakeContainerClass ( ClassID );
1263           Container[i]->read ( f );
1264         } else
1265           Container[i] = NULL;
1266       }
1267     }
1268   }
1269 
MakeStreamFunctions(ClassContainer)1270   MakeStreamFunctions(ClassContainer)
1271 
1272 
1273 
1274   //  ======================  ID parsers  ==========================
1275 
1276 
1277   AtomPath::AtomPath() : io::Stream()  {
1278     InitAtomPath();
1279   }
1280 
AtomPath(cpstr ID)1281   AtomPath::AtomPath ( cpstr ID ) : io::Stream()  {
1282     InitAtomPath();
1283     SetPath ( ID );
1284   }
1285 
AtomPath(io::RPStream Object)1286   AtomPath::AtomPath  ( io::RPStream Object ) : io::Stream(Object) {
1287     InitAtomPath();
1288   }
1289 
~AtomPath()1290   AtomPath::~AtomPath() {}
1291 
InitAtomPath()1292   void AtomPath::InitAtomPath()  {
1293     modelNo     = 0;
1294     chainID [0] = char(0);
1295     seqNum      = MinInt4;
1296     insCode [0] = char(0);
1297     resName [0] = char(0);
1298     atomName[0] = char(0);
1299     element [0] = char(0);
1300     altLoc  [0] = char(0);
1301     isSet       = 0;
1302   }
1303 
SetPath(cpstr ID)1304   int AtomPath::SetPath ( cpstr ID )  {
1305   //  1. If ID starts with '/':
1306   //   /mdl/chn/seq(res).i/atm[elm]:a
1307   //
1308   //  2. If ID starts with a letter:
1309   //        chn/seq(res).i/atm[elm]:a
1310   //
1311   //  3. If ID starts with a number:
1312   //            seq(res).i/atm[elm]:a
1313   //
1314   //  4. If ID contains colon ':' then
1315   //     it may be just
1316   //                       atm[elm]:a
1317   //
1318   //  All spaces are ignored. isSet
1319   // sets bit for each element present.
1320   // Any element may be a wildcard '*'.
1321   // Wildcard for model will set modelNo=0,
1322   // for sequence number will set
1323   // seqNum=MinInt4.
1324   //
1325   // Returns:
1326   //   0   <-> Ok
1327   //   -1  <-> wrong numerical format for model
1328   //   -2  <-> wrong numerical format for sequence number
1329   //
1330   char N[100];
1331   pstr p,p1;
1332   int  i,k;
1333 
1334     isSet = 0;  // clear all bits.
1335 
1336     p = pstr(ID);
1337     while (*p==' ')  p++;
1338 
1339     if (!(*p))  return 0;
1340 
1341     if (*p=='/')  {
1342       //  model number
1343       p++;
1344       i = 0;
1345       while ((*p) && (*p!='/'))  {
1346         if (*p!=' ')  N[i++] = *p;
1347         p++;
1348       }
1349       N[i] = char(0);
1350       if ((!N[0]) || (N[0]=='*'))  modelNo = 0;
1351       else {
1352         modelNo = mround(strtod(N,&p1));
1353         if ((modelNo==0) && (p1==N))  return -1;
1354       }
1355       isSet |= APATH_ModelNo;
1356       if (*p!='/')  return 0;
1357       p++;
1358       while (*p==' ')  p++;
1359     }
1360 
1361     if ((*p<'0') || (*p>'9'))  {
1362       //  chain ID
1363       i = 0;
1364       k = sizeof(ChainID)-1;
1365       while ((*p) && (*p!='/'))  {
1366         if ((*p!=' ') && (i<k))  chainID[i++] = *p;
1367         p++;
1368       }
1369       chainID[i] = char(0);
1370       if (!chainID[0])  {
1371         chainID[0] = '*';
1372         chainID[1] = char(0);
1373       }
1374       isSet |= APATH_ChainID;
1375       if (*p!='/')  return 0;
1376       p++;
1377       while (*p==' ')  p++;
1378     }
1379 
1380     if (((*p>='0') && (*p<='9')) || (*p=='-') ||
1381          (*p=='(') || (*p=='.'))  {
1382       //  sequence number, residue name and insertion code
1383       i = 0;
1384       while ((*p) && (*p!='/'))  {
1385         if (*p!=' ')  N[i++] = *p;
1386         p++;
1387       }
1388       N[i] = char(0);
1389       i    = ParseResID ( N,seqNum,insCode,resName );
1390       if (i==2)  return -2;
1391       isSet |= APATH_SeqNum | APATH_InsCode | APATH_ResName;
1392       if (*p!='/')  return 0;
1393       p++;
1394       while (*p==' ')  p++;
1395     }
1396 
1397     if (FirstOccurence(p,':') || FirstOccurence(p,'['))  {
1398       // atom name, chemical element and alternative location
1399       i = 0;
1400       while (*p)  {
1401         if (*p!=' ')  N[i++] = *p;
1402         p++;
1403       }
1404       N[i] = char(0);
1405       ParseAtomID ( N,atomName,element,altLoc );
1406       isSet |= APATH_AtomName | APATH_Element | APATH_AltLoc;
1407     }
1408 
1409     return 0;
1410 
1411   }
1412 
write(io::RFile f)1413   void AtomPath::write ( io::RFile f )  {
1414   byte Version=1;
1415     f.WriteByte ( &Version );
1416     io::Stream::write ( f );
1417     f.WriteInt  ( &modelNo );
1418     f.WriteInt  ( &seqNum  );
1419     f.WriteInt  ( &isSet   );
1420     f.WriteTerLine ( chainID ,false );
1421     f.WriteTerLine ( insCode ,false );
1422     f.WriteTerLine ( resName ,false );
1423     f.WriteTerLine ( atomName,false );
1424     f.WriteTerLine ( element ,false );
1425     f.WriteTerLine ( altLoc  ,false );
1426   }
1427 
read(io::RFile f)1428   void AtomPath::read ( io::RFile f )  {
1429   byte Version;
1430     f.ReadByte ( &Version );
1431     io::Stream::read ( f );
1432     f.ReadInt  ( &modelNo );
1433     f.ReadInt  ( &seqNum  );
1434     f.ReadInt  ( &isSet   );
1435     f.ReadTerLine ( chainID ,false );
1436     f.ReadTerLine ( insCode ,false );
1437     f.ReadTerLine ( resName ,false );
1438     f.ReadTerLine ( atomName,false );
1439     f.ReadTerLine ( element ,false );
1440     f.ReadTerLine ( altLoc  ,false );
1441   }
1442 
1443 
MakeStreamFunctions(AtomPath)1444   MakeStreamFunctions(AtomPath)
1445 
1446 
1447 
1448   //  --------------------------------------------------------
1449 
1450   QuickSort::QuickSort() : io::Stream()  {
1451     selSortLimit = 15;
1452     data         = NULL;
1453     dlen         = 0;
1454   }
1455 
QuickSort(io::RPStream Object)1456   QuickSort::QuickSort ( io::RPStream Object )
1457             : io::Stream(Object)  {
1458     selSortLimit = 15;
1459     data         = NULL;
1460     dlen         = 0;
1461   }
1462 
Compare(int i,int j)1463   int QuickSort::Compare ( int i, int j )  {
1464   // sort by increasing data[i]
1465     if (((ivector)data)[i]<((ivector)data)[j])  return -1;
1466     if (((ivector)data)[i]>((ivector)data)[j])  return  1;
1467     return 0;
1468   }
1469 
Swap(int i,int j)1470   void QuickSort::Swap ( int i, int j )  {
1471   int b;
1472     b = ((ivector)data)[i];
1473     ((ivector)data)[i] = ((ivector)data)[j];
1474     ((ivector)data)[j] = b;
1475   }
1476 
SelectionSort(int left,int right)1477   void QuickSort::SelectionSort ( int left, int right )  {
1478   int i,j,imin;
1479     for (i=left;i<right;i++) {
1480       imin = i;
1481       for (j=i+1;j<=right;j++)
1482         if (Compare(j,imin)<0)  imin = j;
1483       Swap ( i,imin );
1484     }
1485   }
1486 
Partition(int left,int right)1487   int QuickSort::Partition ( int left, int right )  {
1488   int lv = left;
1489   int lm = left-1;
1490   int rm = right+1;
1491     do  {
1492       do
1493         rm--;
1494       while ((rm>0) && (Compare(rm,lv)>0));
1495       do
1496         lm++;
1497       while ((lm<dlen) && (Compare(lm,lv)<0));
1498       if (lm<rm)  {
1499         if (lv==lm)  lv = rm;
1500         else if (lv==rm)  lv = lm;
1501         Swap ( lm,rm );
1502       }
1503     } while (lm<rm);
1504     return rm;
1505   }
1506 
Quicksort(int left,int right)1507   void QuickSort::Quicksort ( int left, int right )  {
1508   int split_pt;
1509     if (left<(right-selSortLimit)) {
1510       split_pt = Partition ( left,right );
1511       Quicksort ( left,split_pt    );
1512       Quicksort ( split_pt+1,right );
1513     } else
1514       SelectionSort ( left,right );
1515   }
1516 
Sort(void * sortdata,int data_len)1517   void QuickSort::Sort ( void * sortdata, int data_len )  {
1518     data = sortdata;
1519     dlen = data_len-1;
1520     if (data)  Quicksort ( 0,data_len-1 );
1521   }
1522 
1523   //  --------------------------------------------------------
1524 
takeWord(pstr & p,pstr wrd,cpstr ter,int l)1525   void  takeWord ( pstr & p, pstr wrd, cpstr ter, int l )  {
1526   pstr p1;
1527   int  i;
1528     p1 = strpbrk ( p,ter );
1529     if (!p1)
1530       p1 = p + strlen(p);
1531     i = 0;
1532     while ((p!=p1) && (i<l))  {
1533       wrd[i++] = *p;
1534       p++;
1535     }
1536     if (i>=l)  i = l-1;
1537     wrd[i] = char(0);
1538     p      = p1;
1539   }
1540 
1541 
ParseAtomID(cpstr ID,AtomName aname,Element elname,AltLoc aloc)1542   void ParseAtomID ( cpstr ID, AtomName aname, Element elname,
1543                                AltLoc   aloc )  {
1544   pstr p;
1545 
1546     p = pstr(ID);
1547     while (*p==' ')  p++;
1548 
1549     strcpy ( aname ,"*" );
1550     strcpy ( elname,"*" );
1551     if (*p)  aloc[0] = char(0);
1552        else  strcpy ( aloc,"*" );
1553 
1554     takeWord ( p,aname,pstr("[: "),sizeof(AtomName) );
1555 
1556     if (*p=='[')  {
1557       p++;
1558       takeWord ( p,elname,pstr("]: "),sizeof(Element) );
1559       if (*p==']')  p++;
1560     }
1561 
1562     if (*p==':')  {
1563       p++;
1564       takeWord ( p,aloc,pstr(" "),sizeof(AltLoc) );
1565     }
1566 
1567   }
1568 
ParseResID(cpstr ID,int & sn,InsCode inscode,ResName resname)1569   int ParseResID ( cpstr ID, int & sn, InsCode inscode,
1570                                        ResName resname )  {
1571   int  RC;
1572   pstr p,p1;
1573   char N[100];
1574 
1575     RC = 0;
1576 
1577     p = pstr(ID);
1578     while (*p==' ')  p++;
1579 
1580     sn = ANY_RES;
1581     strcpy ( inscode,"*" );
1582     strcpy ( resname,"*" );
1583 
1584     N[0] = char(0);
1585     takeWord ( p,N,pstr("(./ "),sizeof(N) );
1586     if ((!N[0]) || (N[0]=='*'))  {
1587       sn = ANY_RES;
1588       RC = 1;
1589     }
1590     if (!RC)  {
1591       sn = mround(strtod(N,&p1));
1592       if (p1==N)  RC = 2;
1593             else  inscode[0] = char(0);
1594     }
1595 
1596     if (*p=='(')  {
1597       p++;
1598       takeWord ( p,resname,pstr(")./ "),sizeof(ResName) );
1599       if (*p==')')  p++;
1600     }
1601 
1602     if (*p=='.')  {
1603       p++;
1604       takeWord ( p,inscode,pstr("/ "),sizeof(InsCode) );
1605     }
1606 
1607     return RC;
1608 
1609   }
1610 
ParseAtomPath(cpstr ID,int & mdl,ChainID chn,int & sn,InsCode ic,ResName res,AtomName atm,Element elm,AltLoc aloc,PAtomPath DefPath)1611   int ParseAtomPath ( cpstr      ID,
1612                       int &      mdl,
1613                       ChainID    chn,
1614                       int &      sn,
1615                       InsCode    ic,
1616                       ResName    res,
1617                       AtomName   atm,
1618                       Element    elm,
1619                       AltLoc     aloc,
1620                       PAtomPath DefPath )  {
1621   //   /mdl/chn/seq(res).i/atm[elm]:a, may be partial
1622   char    N[100];
1623   pstr    p,p1;
1624   int     i,RC;
1625   bool wasRes;
1626 
1627     wasRes = false;
1628 
1629     RC = 0;
1630 
1631     p = pstr(ID);
1632     while (*p==' ')  p++;
1633 
1634     mdl = 0;
1635     if (*p=='/')  {
1636       p++;
1637       N[0] = char(0);
1638       takeWord ( p,N,pstr("/"),sizeof(N) );
1639       if ((!N[0]) || (N[0]=='*'))  mdl = 0;
1640       else {
1641         mdl = mround(strtod(N,&p1));
1642         if ((mdl==0) && (p1==N))  return -1;
1643       }
1644     } else if (DefPath)  {
1645       if (DefPath->isSet & APATH_ModelNo)
1646         mdl = DefPath->modelNo;
1647     }
1648 
1649     strcpy ( chn,"*" );
1650     if ((*p<'0') || (*p>'9') || (*p=='/'))  {
1651       if (*p=='/')  p++;
1652       p1 = p;
1653       chn[0] = char(0);
1654       takeWord ( p,chn,pstr("/"),sizeof(ChainID) );
1655       if (strpbrk(chn,"(.[:-"))  { // this was not a chain ID!
1656         if (DefPath)  {
1657           if (DefPath->isSet & APATH_ChainID)
1658             strcpy ( chn,DefPath->chainID );
1659         } else
1660           strcpy ( chn,"*" );
1661         p = p1;
1662       }
1663     } else if (DefPath)  {
1664       if (DefPath->isSet & APATH_ChainID)
1665         strcpy ( chn,DefPath->chainID );
1666     }
1667 
1668     if (*p=='/')  p++;
1669     sn = ANY_RES;
1670     strcpy ( ic ,"*" );
1671     strcpy ( res,"*" );
1672     if (((*p>='0') && (*p<='9')) || (*p=='-') ||
1673          (*p=='(') || (*p=='.'))  {
1674       wasRes = true;
1675       N[0] = char(0);
1676       takeWord ( p,N,pstr("/"),sizeof(N) );
1677       i = ParseResID ( N,sn,ic,res );
1678       if (i==2)  return -2;
1679     } else if (DefPath)  {
1680       wasRes = (*p=='/');
1681       if (DefPath->isSet & APATH_SeqNum)
1682         sn = DefPath->seqNum;
1683       if (DefPath->isSet & APATH_InsCode)
1684         strcpy ( ic,DefPath->insCode );
1685       if (DefPath->isSet & APATH_ResName)
1686         strcpy ( res,DefPath->resName );
1687     }
1688 
1689     if (*p=='/')  p++;
1690     strcpy ( atm ,"*" );
1691     strcpy ( elm ,"*" );
1692     strcpy ( aloc,"*" );
1693     if (wasRes || FirstOccurence(p,':') || FirstOccurence(p,'['))  {
1694       ParseAtomID ( p,atm,elm,aloc );
1695     } else if (DefPath)  {
1696       if (DefPath->isSet & APATH_AtomName)
1697         strcpy ( atm,DefPath->atomName );
1698       if (DefPath->isSet & APATH_Element)
1699         strcpy ( elm,DefPath->element );
1700       if (DefPath->isSet & APATH_ResName)
1701         strcpy ( aloc,DefPath->altLoc );
1702     }
1703 
1704     if (mdl<=0)       RC |= APATH_WC_ModelNo;
1705     if (chn[0]=='*')  RC |= APATH_WC_ChainID;
1706     if (sn==ANY_RES)  RC |= APATH_WC_SeqNum;
1707     if (ic[0]=='*')   RC |= APATH_WC_InsCode;
1708     if (res[0]=='*')  RC |= APATH_WC_ResName;
1709     if (atm[0]=='*')  RC |= APATH_WC_AtomName;
1710     if (elm[0]=='*')  RC |= APATH_WC_Element;
1711     if (aloc[0]=='*') RC |= APATH_WC_AltLoc;
1712 
1713     if (RC & (APATH_WC_ModelNo  | APATH_WC_ChainID |
1714               APATH_WC_SeqNum   | APATH_WC_InsCode |
1715               APATH_WC_AtomName | APATH_WC_AltLoc))
1716       RC |= APATH_Incomplete;
1717 
1718     return RC;
1719 
1720   }
1721 
1722 
ParseSelectionPath(cpstr CID,int & iModel,pstr Chains,int & sNum1,InsCode ic1,int & sNum2,InsCode ic2,pstr RNames,pstr ANames,pstr Elements,pstr altLocs)1723   int  ParseSelectionPath (
1724                cpstr   CID,
1725                int &   iModel,
1726                pstr    Chains,
1727                int &   sNum1,
1728                InsCode ic1,
1729                int &   sNum2,
1730                InsCode ic2,
1731                pstr    RNames,
1732                pstr    ANames,
1733                pstr    Elements,
1734                pstr    altLocs
1735                           )  {
1736   int     l,j;
1737   pstr    p,p1;
1738   pstr    N;
1739   int     seqNum [2];
1740   InsCode insCode[2];
1741   pstr    ID;
1742   bool wasModel,wasChain,wasRes,haveNeg;
1743 
1744     l  = IMax(10,strlen(CID))+1;
1745     ID = new char[l];
1746     N  = new char[l];
1747 
1748     p  = pstr(CID);
1749     p1 = ID;
1750     while (*p)  {
1751       if (*p!=' ')  {
1752         *p1 = *p;
1753         p1++;
1754       }
1755       p++;
1756     }
1757     *p1 = char(0);
1758 
1759     p = ID;
1760 
1761     iModel = 0;
1762     strcpy ( Chains,"*" );
1763     seqNum[0] = ANY_RES;
1764     seqNum[1] = ANY_RES;
1765     strcpy ( insCode[0],"*" );
1766     strcpy ( insCode[1],"*" );
1767     strcpy ( RNames    ,"*" );
1768     strcpy ( ANames    ,"*" );
1769     strcpy ( Elements  ,"*" );
1770     strcpy ( altLocs   ,"*" );
1771 
1772     wasModel = false;
1773     wasChain = false;
1774     wasRes   = false;
1775 
1776     if (*p=='/')  {
1777       //  CID starts with the slash -- take model number first
1778       p++;
1779       N[0] = char(0);
1780       takeWord ( p,N,pstr("/"),l );
1781       if ((!N[0]) || (N[0]=='*'))  iModel = 0;
1782       else {
1783         iModel = mround(strtod(N,&p1));
1784         if ((iModel==0) && (p1==N))  return -1;
1785       }
1786       if (*p=='/')  p++;
1787       wasModel = true;
1788     }
1789 
1790     if ((*p) && (wasModel || (*p<'0') || (*p>'9')))  {
1791       p1 = p;
1792       Chains[0] = char(0);
1793       takeWord ( p,Chains,pstr("/"),l );
1794       if (strpbrk(Chains,"(.[:-"))  {  // this was not a chain ID!
1795         strcpy ( Chains,"*" );
1796         p = p1;
1797       } else
1798         wasChain = true;
1799       if (*p=='/')  p++;
1800     }
1801 
1802     if ((*p) && (wasChain  || ((*p>='0') && (*p<='9')) || (*p=='-') ||
1803                  (*p=='(') || (*p=='.')  || (*p=='*')))  {
1804       j = 0;
1805       do  {
1806         // take the sequence number
1807         haveNeg  = false;
1808         if (*p=='-') {
1809           haveNeg = true;
1810           p++;
1811         }
1812         N[0] = char(0);
1813         takeWord ( p,N,pstr("(.-/"),l );
1814         if ((!N[0]) || (N[0]=='*'))
1815           seqNum[j] = ANY_RES;
1816         else  {
1817           seqNum[j] = mround(strtod(N,&p1));
1818           if (p1==N)   return -2;
1819           if (haveNeg) seqNum[j] = - seqNum[j];
1820         }
1821         // take the residue list
1822         if (*p=='(')  {
1823           p++;
1824           takeWord ( p,RNames,pstr(").-/"),l );
1825           if (*p==')')  p++;
1826         }
1827         // take the insertion code
1828         if (seqNum[j]!=ANY_RES)
1829           insCode[j][0] = char(0);
1830         if (*p=='.')  {
1831           p++;
1832           takeWord ( p,insCode[j],pstr("-/"),sizeof(InsCode) );
1833         }
1834         if (*p=='-')  {
1835           p++;
1836           j++;
1837         } else  {
1838           if (j==0)  {
1839             seqNum[1] = seqNum[0];
1840             strcpy ( insCode[1],insCode[0] );
1841           }
1842           j = 10;
1843         }
1844       } while (j<2);
1845       wasRes = true;
1846     } else
1847       wasRes = (*p=='/');
1848 
1849     if (*p=='/')  p++;
1850     if ((*p) && (wasRes || FirstOccurence(p,':') || FirstOccurence(p,'[')))  {
1851       if (*p)  altLocs[0] = char(0);
1852       takeWord ( p,ANames,pstr("[:"),l );
1853       if (!ANames[0])  strcpy ( ANames,"*" );
1854       if (*p=='[')  {
1855         p++;
1856         takeWord ( p,Elements,pstr("]:"),l );
1857         if (*p==']')  p++;
1858       }
1859       if (*p==':')  {
1860         p++;
1861         takeWord ( p,altLocs,pstr(" "),l );
1862       }
1863     }
1864 
1865     /*
1866     printf ( "  iModel   = %i\n"
1867              "  Chains   = '%s'\n"
1868              "  seqNum1  = %i\n"
1869              "  insCode1 = '%s'\n"
1870              "  seqNum2  = %i\n"
1871              "  insCode2 = '%s'\n"
1872              "  RNames   = '%s'\n"
1873              "  ANames   = '%s'\n"
1874              "  Elements = '%s'\n"
1875              "  altLocs  = '%s'\n",
1876              iModel,Chains,seqNum[0],insCode[0],
1877              seqNum[1],insCode[1],RNames,ANames,
1878              Elements,altLocs );
1879     */
1880 
1881     sNum1 = seqNum[0];
1882     sNum2 = seqNum[1];
1883     strcpy ( ic1,insCode[0] );
1884     strcpy ( ic2,insCode[1] );
1885 
1886     delete[] ID;
1887     delete[] N;
1888 
1889     return 0;
1890 
1891   }
1892 
1893 
MakeSelectionPath(pstr CID,int iModel,cpstr Chains,int sNum1,const InsCode ic1,int sNum2,const InsCode ic2,cpstr RNames,cpstr ANames,cpstr Elements,cpstr altLocs)1894   void MakeSelectionPath (
1895                pstr       CID,
1896                int        iModel,
1897                cpstr      Chains,
1898                int        sNum1,
1899                const InsCode ic1,
1900                int        sNum2,
1901                const InsCode ic2,
1902                cpstr      RNames,
1903                cpstr      ANames,
1904                cpstr      Elements,
1905                cpstr      altLocs
1906                           )  {
1907   char S[100];
1908   int  k;
1909 
1910     if (iModel>0)  {
1911       sprintf ( CID,"/%i",iModel );
1912       k = 1;
1913     } else  {
1914       CID[0] = char(0);
1915       k = 0;
1916     }
1917 
1918     if (Chains[0]!='*')  {
1919       if (k>0)  strcat ( CID,"/"    );
1920       strcat ( CID,Chains );
1921       k = 2;
1922     }
1923 
1924     if ((sNum1!=-MaxInt4) || (ic1[0]!='*'))  {
1925       if (k>0)  {
1926         if (k<2)  strcat ( CID,"/*" );
1927         strcat  ( CID,"/" );
1928       }
1929       if (sNum1>-MaxInt4)  sprintf ( S,"%i",sNum1 );
1930                      else  strcpy  ( S,"*" );
1931       if (ic1[0]!='*')  {
1932         strcat ( S,"." );
1933         strcat ( S,ic1 );
1934       }
1935       strcat ( CID,S );
1936 
1937       if ((sNum2!=-MaxInt4) || (ic2[0]!='*'))  {
1938         strcat ( CID,"-" );
1939         if (sNum1>-MaxInt4)  sprintf ( S,"%i",sNum2 );
1940                        else  strcpy  ( S,"*" );
1941         if (ic2[0]!='*')  {
1942           strcat ( S,"." );
1943           strcat ( S,ic2 );
1944         }
1945         strcat ( CID,S );
1946       }
1947 
1948       k = 3;
1949 
1950     }
1951 
1952     if (RNames[0]!='*')  {
1953       if      (k<1)  strcat ( CID,"("    );
1954       else if (k<2)  strcat ( CID,"*/*(" );
1955       else if (k<3)  strcat ( CID,"/*("  );
1956       strcat ( CID,RNames );
1957       strcat ( CID,")"    );
1958       k = 4;
1959     }
1960 
1961     if (ANames[0]!='*')  {
1962       if      (k<1)  strcat ( CID,"/*/*/*/" );  // full path
1963       else if (k<2)  strcat ( CID,"/*/*/"   );  // /mdl + /*/*/
1964       else if (k<3)  strcat ( CID,"/*/"     );  // /mdl/chn + /*/
1965       else if (k<4)  strcat ( CID,"/"       );  // /mdl/chn/res + /
1966       strcat ( CID,ANames );
1967       strcat ( CID,")"    );
1968       k = 5;
1969     }
1970 
1971     if (Elements[0]!='*')  {
1972       if      (k<1)  strcat ( CID,"["       );
1973       else if (k<2)  strcat ( CID,"/*/*/*[" );
1974       else if (k<3)  strcat ( CID,"/*/*["   );
1975       else if (k<4)  strcat ( CID,"/*["     );
1976       else if (k<5)  strcat ( CID,"["       );
1977       strcat ( CID,Elements );
1978       strcat ( CID,"]"    );
1979       k = 6;
1980     }
1981 
1982     if (altLocs[0]!='*')  {
1983       if      (k<1)  strcat ( CID,":"       );
1984       else if (k<2)  strcat ( CID,"/*/*/*:" );
1985       else if (k<3)  strcat ( CID,"/*/*:"   );
1986       else if (k<4)  strcat ( CID,"/*:"     );
1987       else if (k<6)  strcat ( CID,":"       );
1988       strcat ( CID,altLocs );
1989     }
1990 
1991   }
1992 
1993 } // namespace mmdb
1994 
1995