Next version of JABA
[jabaws.git] / binaries / src / clustalw / src / fileInput / ClustalFileParser.cpp
1 /**
2  * Author: Mark Larkin
3  * 
4  * Copyright (c) 2007 Des Higgins, Julie Thompson and Toby Gibson.  
5  */
6 /**
7  * Changes:
8  *
9  * 10-02-07,Nigel Brown(EMBL): changed ifstream to InFileStream to handle
10  * cross-platform end-of-lines.
11  *
12  * 27-4-2007, Mark Larkin (UCD): Made 2 small changes to getSecStructure function. There 
13  * was a problem with the secondary structure info in windows.
14  */
15
16 #ifdef HAVE_CONFIG_H
17     #include "config.h"
18 #endif
19 #include "ClustalFileParser.h"
20
21 namespace clustalw
22 {
23
24 ClustalFileParser::ClustalFileParser(string filePath)
25 {
26     fileName = filePath; 
27     fillCharTab();
28     _fileIn = 0;
29 }
30         
31 ClustalFileParser::~ClustalFileParser()
32 {
33     
34 }
35
36
37     vector<Sequence> ClustalFileParser::getSeqRange(int firstSeq, int no, string *offendingSeq)
38 {
39     vector<Sequence> seqRangeVector;
40     int i;
41
42     for (i=0; i<no; i++)
43     { 
44         Sequence tempSeq = getSeq(firstSeq + i, offendingSeq);
45         if (parseExitCode!=OK) {
46             seqRangeVector.clear();
47             return seqRangeVector;
48         }
49         seqRangeVector.push_back(tempSeq);
50     }
51     return seqRangeVector;
52 }
53
54
55     Sequence ClustalFileParser::getSeq(int seqNum, string *offendingSeq)
56 {
57     char line[MAXLINE + 1];
58     line[0] = EOS;
59     char tseq[MAXLINE + 1];
60     tseq[0] = '\0';
61     char sname[MAXNAMES + 150];
62
63     for(int i = 1; i < MAXNAMES + 1; i++)
64     {
65         line[i] = tseq[i] = sname[i] = '0';
66     }
67     string characterSeq = "";
68     string name = "";
69     string title = ""; // Nothing happens it here!!!
70
71     int i, j;
72     unsigned char c;
73     string blank = "";
74     
75     try
76     {
77         _fileIn = new InFileStream;  //nige
78         _fileIn->open(fileName.c_str());  //nige
79         _fileIn->seekg(0, std::ios::beg); // start at the beginning
80              
81         _fileIn->getline(line, MAXLINE + 1); // read the title line...ignore it
82     
83         while (_fileIn->getline(line, MAXLINE + 1))  //nige
84         {
85             if (!clustalBlankline(line))
86             {
87
88                 for (i = 1; i < seqNum; i++)
89                 {
90                     _fileIn->getline(line, MAXLINE + 1);  //nige
91                 }
92                 for (j = 0; j <= (int)strlen(line); j++)
93                     if (line[j] != ' ')
94                     {
95                         break;
96                     }
97                 string _tempStr = string(line);
98
99                 sscanf(_tempStr.c_str(), "%s%s", sname, tseq);
100                 for (j = 0; j < MAXNAMES; j++)
101                 {
102                     if (sname[j] == ' ')
103                     {
104                         break;
105                     }
106                 }
107                 sname[j] = EOS;
108                 utilityObject->rTrim(sname);
109                 utilityObject->blankToUnderscore(sname); // replace blanks with '_'
110                 name = string(sname);           
111                
112                 for (i = 0; i <= MAXLINE; i++)
113                 {
114                     c = tseq[i];
115                     if (isspace(c) || c == EOS)
116                     {
117                         break;
118                     }
119                     // EOL 
120                     c = chartab[c];
121                     if (c)
122                     {
123                         characterSeq += c; // Add the character to the sequence
124                     }
125                 }
126
127                 for (i = 0;; i++)
128                 {
129                     if (!_fileIn->getline(line, MAXLINE + 1)) // If we cant get another line!
130                     {
131                         freeFileResources(_fileIn);
132                         if ((int)characterSeq.length() > userParameters->getMaxAllowedSeqLength())
133                             {
134                                 parseExitCode=SEQUENCETOOBIG;
135                                 if (offendingSeq!=NULL)
136                                     offendingSeq->assign(name);
137                                 // return empty seq
138                                 return Sequence(blank, blank, blank);
139                             }
140                      return Sequence(characterSeq, name, title);
141                     }
142                     if (clustalBlankline(line))
143                     {
144                         break;
145                     }
146                 }
147             }
148         }
149         freeFileResources(_fileIn);
150
151         if ((int)characterSeq.length() > userParameters->getMaxAllowedSeqLength())
152         {
153             parseExitCode=SEQUENCETOOBIG;
154             if (offendingSeq!=NULL)
155                 offendingSeq->assign(name);
156
157             // return empty seq
158             return Sequence(blank, blank, blank);
159         }
160         return Sequence(characterSeq, name, title);
161     }
162     catch(...)
163     {
164         freeFileResources(_fileIn);
165         cerr << "An exception has occured in the function ClustalFileParser::getSeq()\n"
166              << "Program needs to terminate.\nPlease contact the Clustal developers\n";
167         exit(1);
168     }
169 }
170         
171 /*
172  * The function countSeqs tells us how many sequences are in a clustal format file.
173  * Need to check if the file is open!
174  */
175 int ClustalFileParser::countSeqs()
176 {
177     char line[MAXLINE + 1];
178     int _nseqs;
179     
180     try
181     {
182         _fileIn = new InFileStream;  //nige
183         _fileIn->open(fileName.c_str());  //nige
184     
185         if(!_fileIn->is_open())
186         {
187             freeFileResources(_fileIn);            
188             return 0; // No sequences found!
189         }
190
191
192         while (_fileIn->getline(line, MAXLINE + 1))
193         {
194             if (!utilityObject->blankLine(line))
195             {
196                 break;
197             }
198         }
199     
200         // This gets us to the begining of the sequence lines!
201         while (_fileIn->getline(line, MAXLINE + 1))
202         {
203             if (!clustalBlankline(line))
204             {
205                 break;
206             }
207         }
208         _nseqs = 1;
209
210         while (_fileIn->getline(line, MAXLINE + 1))
211         {
212             if (clustalBlankline(line))
213             {
214                 freeFileResources(_fileIn);
215                 return _nseqs;
216             }
217             _nseqs++;
218         }
219         freeFileResources(_fileIn);
220         return (int)0; // if you got to here-funny format/no seqs.
221     }
222     catch(...)
223     {
224         freeFileResources(_fileIn);
225         cerr << "An exception has occured in the function ClustalFileParser::countSeqs()\n"
226              << "Program needs to terminate.\nPlease contact the Clustal developers\n";
227         exit(1);    
228     }    
229 }
230
231 /*
232  * This function is to get the secondary structure for a Clustal format file.
233  * I am aware that I am using some C and some C++ here, and this may seem like
234  * bad style, but I think it is better to use the C functions for processing the
235  * strings as they are already working.
236  */        
237 void ClustalFileParser::getSecStructure(vector<char>& gapPenaltyMask, 
238       vector<char>& secStructMask, string& secStructName, int &structPenalties, int length)
239 {
240     char title[MAXLINE + 1];
241     title[0] = '\0';
242     char line[MAXLINE + 1];
243     line[0] = '\0';
244     char lin2[MAXLINE + 1];
245     lin2[0] = '\0';
246     char tseq[MAXLINE + 1];
247     tseq[0] = '\0';
248     char sname[MAXNAMES + 1];
249     sname[0] = '\0';
250     
251     for(int i = 1; i < MAXNAMES + 1; i++)
252     {
253         title[i] = line[i] = lin2[i] = tseq[i] = sname[i] ='0';
254     }
255     
256     int i, j, len, ix, struct_index = 0;
257     char c;
258     
259     try
260     {
261         _fileIn = new InFileStream;  //nige
262         _fileIn->open(fileName.c_str());  //nige
263         _fileIn->seekg(0, std::ios::beg);
264
265         // NOTE clear out the masks
266         gapPenaltyMask.clear();
267         secStructMask.clear();
268         
269         len = 0; // initialise length to zero 
270     
271         if (!_fileIn->getline(line, MAXLINE + 1))
272         {
273             freeFileResources(_fileIn);
274             return ;
275         }
276         // read the title line...ignore it 
277
278         if (!_fileIn->getline(line, MAXLINE + 1))
279         {
280             freeFileResources(_fileIn);
281             return ;
282         }
283         // read the next line...
284         // skip any blank lines 
285         for (;;)
286         {
287             if (!_fileIn->getline(line, MAXLINE + 1))
288             {
289                 freeFileResources(_fileIn);   
290                 return ;
291             }
292             if (!utilityObject->blankLine(line))
293             {
294                 break;
295             }
296         }
297
298         // look for structure table lines
299         ix =  -1;
300         for (;;)
301         {
302             if (line[0] != '!')
303             {
304                 break;
305             }
306             if (strncmp(line, "!SS", 3) == 0)
307             {
308                 ix++;
309                 sscanf(line + 4, "%s%s", sname, tseq);
310                 for (j = 0; j < MAXNAMES; j++)
311                 {
312                     if (sname[j] == ' ')
313                     {
314                         break;
315                     }
316                 }
317                 sname[j] = EOS;
318                 utilityObject->rTrim(sname);
319                 utilityObject->blankToUnderscore(sname);
320             
321                 if (userParameters->getInteractive())
322                 {
323                     strcpy(title, "Found secondary structure in alignment file: ");
324                     strcat(title, sname);
325                     (*lin2) = utilityObject->promptForYesNo(title,
326                         "Use it to set local gap penalties ");
327                 }
328                 else
329                 {
330                     (*lin2) = 'y';
331                 }
332                 if ((*lin2 != 'n') && (*lin2 != 'N'))
333                 {
334                     structPenalties = SECST;
335                     struct_index = ix;
336                     for (i = 0; i < length; i++)
337                     {
338                         secStructMask.push_back('.');
339                         gapPenaltyMask.push_back('.');
340                     }
341                 
342                     secStructName = string(sname);
343                 
344                     for (i = 0; len < length; i++)
345                     {
346                         c = tseq[i];
347                         if (c == '\n' || c == EOS)
348                         {
349                             break;
350                         }
351                         // EOL
352                         if (!isspace(c))
353                         {
354                             if(len < (int)secStructMask.size())
355                             {
356                                 secStructMask[len++] = c; // NOTE array notation = BAD
357                             }
358                         }
359                     }
360                 }
361             }
362             else if (strncmp(line, "!GM", 3) == 0)
363             {
364                 ix++;
365                 sscanf(line + 4, "%s%s", sname, tseq);
366                 for (j = 0; j < MAXNAMES; j++)
367                 {
368                     if (sname[j] == ' ')
369                     {
370                         break;
371                     }
372                 }
373                 sname[j] = EOS;
374                 utilityObject->rTrim(sname);
375                 utilityObject->blankToUnderscore(sname);
376             
377                 if (userParameters->getInteractive())
378                 {
379                     strcpy(title, "Found gap penalty mask in alignment file: ");
380                     strcat(title, sname);
381                     (*lin2) = utilityObject->promptForYesNo(title,
382                         "Use it to set local gap penalties ");
383                 }
384                 else
385                 {
386                     (*lin2) = 'y';
387                 }
388                 if ((*lin2 != 'n') && (*lin2 != 'N'))
389                 {
390                     structPenalties = GMASK;
391                     struct_index = ix;
392                     for (i = 0; i < length; i++)
393                     {
394                         gapPenaltyMask.push_back('1');
395                     }
396                 
397                     secStructName = string(sname);
398                 
399                     for (i = 0; len < length; i++)
400                     {
401                         c = tseq[i];
402                         if (c == '\n' || c == EOS)
403                         {
404                             break;
405                         }
406                         // EOL
407                         if (!isspace(c))
408                         {
409                             if(len < (int)gapPenaltyMask.size())
410                             {                            
411                                 gapPenaltyMask[len++] = c;
412                             }
413                         }
414                     }
415                 }
416             }
417             if (structPenalties != NONE)
418             {
419                 break;
420             }
421             if (!_fileIn->getline(line, MAXLINE + 1))
422             {
423                 freeFileResources(_fileIn);   
424                 return ;
425             }
426         }
427         if (structPenalties == NONE)
428         {
429             freeFileResources(_fileIn);    
430             return ;
431         }
432
433         // skip any more comment lines
434         while (line[0] == '!')
435         {
436             if (!_fileIn->getline(line, MAXLINE + 1))
437             {
438                 freeFileResources(_fileIn);   
439                 return ;
440             }
441         }
442
443         // skip the sequence lines and any comments after the alignment 
444         for (;;)
445         {
446             if (isspace(line[0]) || line[0] == '\0') // Mark change 27-4-2007
447             {
448                 break;
449             }
450             if (!_fileIn->getline(line, MAXLINE + 1))
451             {
452                 freeFileResources(_fileIn);   
453                 return ;
454             }
455         }
456
457
458         // read the rest of the alignment
459
460         for (;;)
461         {
462             // skip any blank lines
463             for (;;)
464             {
465                 if (!utilityObject->blankLine(line))
466                 {
467                     break;
468                 }
469                 if (!_fileIn->getline(line, MAXLINE + 1))
470                 {
471                     freeFileResources(_fileIn);    
472                     return ;
473                 }
474             }
475             // get structure table line 
476             for (ix = 0; ix < struct_index; ix++)
477             {
478                 if (line[0] != '!')
479                 {
480                     if (structPenalties == SECST)
481                     {
482                         utilityObject->error("bad secondary structure format\n");
483                     }
484                     else
485                     {
486                         utilityObject->error("bad gap penalty mask format\n");
487                     }
488                     structPenalties = NONE;
489                     freeFileResources(_fileIn);    
490                     return ;
491                 }
492                 if (!_fileIn->getline(line, MAXLINE + 1))
493                 {
494                     freeFileResources(_fileIn);    
495                     return ;
496                 }
497             }
498             if (structPenalties == SECST)
499             {
500                 if (strncmp(line, "!SS", 3) != 0)
501                 {
502                     utilityObject->error("bad secondary structure format\n");
503                     structPenalties = NONE;
504                     freeFileResources(_fileIn);    
505                     return ;
506                 }
507                 sscanf(line + 4, "%s%s", sname, tseq);
508                 for (i = 0; len < length; i++)
509                 {
510                     c = tseq[i];
511                     if (c == '\n' || c == EOS)
512                     {
513                         break;
514                     }
515                     // EOL
516                     if (!isspace(c))
517                     {
518                         secStructMask[len++] = c;
519                     }
520                 }
521             }
522             else if (structPenalties == GMASK)
523             {
524                 if (strncmp(line, "!GM", 3) != 0)
525                 {
526                     utilityObject->error("bad gap penalty mask format\n");
527                     structPenalties = NONE;
528                     freeFileResources(_fileIn);    
529                     return ;
530                 }
531                 sscanf(line + 4, "%s%s", sname, tseq);
532                 for (i = 0; len < length; i++)
533                 {
534                     c = tseq[i];
535                     if (c == '\n' || c == EOS)
536                 {
537                     break;
538                 }
539                 // EOL
540                 if (!isspace(c))
541                 {
542                     gapPenaltyMask[len++] = c;
543                 }
544             }
545         }
546
547         // skip any more comment lines
548         while (line[0] == '!')
549         {
550             if (!_fileIn->getline(line, MAXLINE + 1))
551             {
552                 freeFileResources(_fileIn);   
553                 return ;
554             }
555         }
556
557             // skip the sequence lines
558             for (;;)
559             {
560                 if (isspace(line[0]) || line[0] == '\0') // Mark change 27-4-2007
561                 {
562                     break;
563                 }
564                 if (!_fileIn->getline(line, MAXLINE + 1))
565                 {
566                     freeFileResources(_fileIn);    
567                     return ;
568                 }
569             }
570         }
571         freeFileResources(_fileIn);
572     }
573     catch(...)
574     {
575         freeFileResources(_fileIn);
576         cerr << "An exception has occured in the function ClustalFileParser::getSecStructure()\n"
577              << "Program needs to terminate.\nPlease contact the Clustal developers\n";
578         exit(1);    
579     }
580 }
581
582 bool ClustalFileParser::clustalBlankline(char* line)
583 {
584     int i;
585
586     if (line[0] == '!')
587     {
588         return true;
589     }
590
591     for (i = 0; line[i] != '\n' && line[i] != EOS; i++)
592     {
593         if (isdigit(line[i]) || isspace(line[i]) || (line[i] == '*') ||
594             (line[i] == ':') || (line[i] == '.'))
595             ;
596         else
597         {
598             return false;
599         }
600     }
601     return true;
602 }
603
604 }