~ubuntu-branches/ubuntu/quantal/clustalo/quantal

« back to all changes in this revision

Viewing changes to src/squid/msf.c

  • Committer: Package Import Robot
  • Author(s): Olivier Sallou
  • Date: 2011-12-14 11:21:56 UTC
  • Revision ID: package-import@ubuntu.com-20111214112156-y3chwm0t4yn2nevm
Tags: upstream-1.0.3
ImportĀ upstreamĀ versionĀ 1.0.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*****************************************************************
 
2
 * SQUID - a library of functions for biological sequence analysis
 
3
 * Copyright (C) 1992-2002 Washington University School of Medicine
 
4
 * 
 
5
 *     This source code is freely distributed under the terms of the
 
6
 *     GNU General Public License. See the files COPYRIGHT and LICENSE
 
7
 *     for details.
 
8
 *****************************************************************/
 
9
 
 
10
/* msf.c
 
11
 * SRE, Sun Jul 11 16:17:32 1993
 
12
 * 
 
13
 * Import/export of GCG MSF multiple sequence alignment
 
14
 * formatted files. Designed using format specifications
 
15
 * kindly provided by Steve Smith of Genetics Computer Group.
 
16
 * 
 
17
 * RCS $Id: msf.c 217 2011-03-19 10:27:10Z andreas $ (Original squid RCS Id: msf.c,v 1.4 2001/04/23 00:35:33 eddy Exp)
 
18
 */
 
19
 
 
20
#include <stdio.h>
 
21
#include <stdlib.h>
 
22
#include <string.h>
 
23
#include <ctype.h>
 
24
#include  <time.h>
 
25
#include "squid.h"
 
26
#include "msa.h"
 
27
 
 
28
#ifdef TESTDRIVE_MSF
 
29
/*****************************************************************
 
30
 * msf.c test driver: 
 
31
 * cc -DTESTDRIVE_MSF -g -O2 -Wall -o test msf.c msa.c gki.c sqerror.c sre_string.c file.c hsregex.c sre_math.c sre_ctype.c sqio.c alignio.c selex.c interleaved.c types.c -lm
 
32
 * 
 
33
 */
 
34
int
 
35
main(int argc, char **argv)
 
36
{
 
37
  MSAFILE *afp;
 
38
  MSA     *msa;
 
39
  char    *file;
 
40
  
 
41
  file = argv[1];
 
42
 
 
43
  if ((afp = MSAFileOpen(file, MSAFILE_STOCKHOLM, NULL)) == NULL)
 
44
    Die("Couldn't open %s\n", file);
 
45
 
 
46
  while ((msa = ReadMSF(afp)) != NULL)
 
47
    {
 
48
      WriteMSF(stdout, msa);
 
49
      MSAFree(msa); 
 
50
    }
 
51
  
 
52
  MSAFileClose(afp);
 
53
  exit(0);
 
54
}
 
55
/******************************************************************/
 
56
#endif /* testdrive_msf */
 
57
 
 
58
 
 
59
 
 
60
/* Function: ReadMSF()
 
61
 * Date:     SRE, Tue Jun  1 08:07:22 1999 [St. Louis]
 
62
 *
 
63
 * Purpose:  Parse an alignment read from an open MSF format
 
64
 *           alignment file. (MSF is a single-alignment format.)
 
65
 *           Return the alignment, or NULL if we've already
 
66
 *           read the alignment.
 
67
 *           
 
68
 * Args:     afp  - open alignment file
 
69
 *
 
70
 * Returns:  MSA * - an alignment object
 
71
 *                   caller responsible for an MSAFree()
 
72
 *           NULL if no more alignments
 
73
 *
 
74
 * Diagnostics: 
 
75
 *           Will Die() here with a (potentially) useful message
 
76
 *           if a parsing error occurs.
 
77
 */
 
78
MSA *
 
79
ReadMSF(MSAFILE *afp)
 
80
{
 
81
  MSA    *msa;
 
82
  char   *s;
 
83
  int     alleged_alen;
 
84
  int     alleged_type;
 
85
  int     alleged_checksum;
 
86
  char   *tok;
 
87
  char   *sp;
 
88
  int     slen;
 
89
  int     sqidx;
 
90
  char   *name;
 
91
  char   *seq;
 
92
 
 
93
  if (feof(afp->f)) return NULL;
 
94
  if ((s = MSAFileGetLine(afp)) == NULL) return NULL;
 
95
 
 
96
  /* The first line is the header.
 
97
   * This is a new-ish GCG feature. Don't count on it, so
 
98
   * we can be a bit more tolerant towards non-GCG software
 
99
   * generating "MSF" files.
 
100
   */
 
101
  msa = MSAAlloc(10, 0);
 
102
  if      (strncmp(s, "!!AA_MULTIPLE_ALIGNMENT", 23) == 0) {
 
103
    msa->type = kAmino;
 
104
    if ((s = MSAFileGetLine(afp)) == NULL) return NULL;
 
105
  } else if (strncmp(s, "!!NA_MULTIPLE_ALIGNMENT", 23) == 0) {
 
106
    msa->type = kRNA;
 
107
    if ((s = MSAFileGetLine(afp)) == NULL) return NULL;
 
108
  }
 
109
 
 
110
  /* Now we're in the free text comment section of the MSF file.
 
111
   * It ends when we see the "MSF: Type: Check: .." line.
 
112
   * This line must be present. 
 
113
   */
 
114
  do
 
115
    {
 
116
      if ((strstr(s, "..") != NULL && strstr(s, "MSF:") != NULL) &&
 
117
          Strparse("^.+MSF: +([0-9]+) +Type: +([PNX]).+Check: +([0-9]+) +\\.\\.", s, 3))
 
118
        {
 
119
          alleged_alen     = atoi(sqd_parse[0]);
 
120
          switch (*(sqd_parse[1])) {
 
121
          case 'N' : alleged_type = kRNA;      break;
 
122
          case 'P' : alleged_type = kAmino;    break;  
 
123
          case 'X' : alleged_type = kOtherSeq; break;
 
124
          default  : alleged_type = kOtherSeq; 
 
125
          }
 
126
          alleged_checksum = atoi(sqd_parse[3]);
 
127
          if (msa->type == kOtherSeq) msa->type = alleged_type;
 
128
          break;                /* we're done with comment section. */
 
129
        }
 
130
      if (! IsBlankline(s)) 
 
131
        MSAAddComment(msa, s);
 
132
    } while ((s = MSAFileGetLine(afp)) != NULL); 
 
133
 
 
134
  /* Now we're in the name section.
 
135
   * GCG has a relatively poorly documented feature: only sequences that
 
136
   * appear in this list will be read from the alignment section. Commenting
 
137
   * out sequences in the name list (by preceding them with "!") is
 
138
   * allowed as a means of manually defining subsets of sequences in
 
139
   * the alignment section. We can support this feature reasonably
 
140
   * easily because of the hash table for names in the MSA: we
 
141
   * only add names to the hash table when we see 'em in the name section.
 
142
   */
 
143
  while ((s = MSAFileGetLine(afp)) != NULL) 
 
144
    {
 
145
      while ((*s == ' ' || *s == '\t') && *s) s++; /* skip leading whitespace */
 
146
 
 
147
      if      (*s == '\n')   continue;                 /* skip blank lines */
 
148
      else if (*s == '!')    MSAAddComment(msa, s);
 
149
      else if ((sp  = strstr(s, "Name:")) != NULL) 
 
150
        {
 
151
                                /* We take the name and the weigh, and that's it */
 
152
          sp   += 5;
 
153
          tok   = sre_strtok(&sp, " \t", &slen); /* <sequence name> */
 
154
          sqidx = GKIStoreKey(msa->index, tok);
 
155
          if (sqidx >= msa->nseqalloc) MSAExpand(msa);
 
156
          msa->sqname[sqidx] = sre_strdup(tok, slen);
 
157
          msa->nseq++;
 
158
 
 
159
          if ((sp = strstr(sp, "Weight:")) == NULL)
 
160
            Die("No Weight: on line %d for %s in name section of MSF file %s\n",
 
161
                afp->linenumber, msa->sqname[sqidx],  afp->fname);
 
162
          sp += 7;
 
163
          tok = sre_strtok(&sp, " \t", &slen);
 
164
          msa->wgt[sqidx] = atof(tok);
 
165
          msa->flags |= MSA_SET_WGT;
 
166
        }
 
167
      else if (strncmp(s, "//", 2) == 0)
 
168
        break;
 
169
      else
 
170
        {
 
171
          Die("Invalid line (probably %d) in name section of MSF file %s:\n%s\n",
 
172
              afp->linenumber, afp->fname, s);
 
173
          squid_errno = SQERR_FORMAT; /* NOT THREADSAFE */
 
174
          return NULL;
 
175
        }
 
176
 
 
177
    }
 
178
 
 
179
  /* And now we're in the sequence section. 
 
180
   * As discussed above, if we haven't seen a sequence name, then we
 
181
   * don't include the sequence in the alignment.
 
182
   * Also, watch out for coordinate-only lines.
 
183
   */
 
184
  while ((s = MSAFileGetLine(afp)) != NULL) 
 
185
    {
 
186
      sp  = s;
 
187
      if ((name = sre_strtok(&sp, " \t", NULL)) == NULL) continue;
 
188
      if ((seq  = sre_strtok(&sp, "\n",  &slen)) == NULL) continue;
 
189
      
 
190
      /* The test for a coord line: digits starting both fields
 
191
       */
 
192
      if (isdigit(*name) && isdigit(*seq))
 
193
        continue;
 
194
  
 
195
      /* It's not blank, and it's not a coord line: must be sequence
 
196
       */
 
197
      sqidx = GKIKeyIndex(msa->index, name);
 
198
      if (sqidx < 0) continue;  /* not a sequence we recognize */
 
199
      
 
200
      msa->sqlen[sqidx] = sre_strcat(&(msa->aseq[sqidx]), msa->sqlen[sqidx], seq, slen); 
 
201
    }
 
202
  
 
203
  /* We've left blanks in the aseqs; take them back out.
 
204
   */
 
205
  for (sqidx = 0; sqidx <  msa->nseq; sqidx++)
 
206
    {
 
207
      if (msa->aseq[sqidx] == NULL)
 
208
        Die("Didn't find a sequence for %s in MSF file %s\n", msa->sqname[sqidx], afp->fname);
 
209
      
 
210
      for (s = sp = msa->aseq[sqidx]; *s != '\0'; s++)
 
211
        {
 
212
          if (*s == ' ' || *s == '\t') {
 
213
            msa->sqlen[sqidx]--;
 
214
          } else {
 
215
            *sp = *s;
 
216
            sp++;
 
217
          }
 
218
        }
 
219
      *sp = '\0';
 
220
    }
 
221
  
 
222
  MSAVerifyParse(msa);          /* verifies, and also sets alen and wgt. */
 
223
  return msa;
 
224
}
 
225
 
 
226
 
 
227
/* Function: WriteMSF()
 
228
 * Date:     SRE, Mon May 31 11:25:18 1999 [St. Louis]
 
229
 *
 
230
 * Purpose:  Write an alignment in MSF format to an open file.
 
231
 *
 
232
 * Args:     fp    - file that's open for writing.
 
233
 *           msa   - alignment to write. 
 
234
 *
 
235
 *                   Note that msa->type, usually optional, must be
 
236
 *                   set for WriteMSF to work. If it isn't, a fatal
 
237
 *                   error is generated.
 
238
 *
 
239
 * Returns:  (void)
 
240
 */
 
241
void
 
242
WriteMSF(FILE *fp, MSA *msa)
 
243
{
 
244
  time_t now;                   /* current time as a time_t */
 
245
  char   date[64];              /* today's date in GCG's format "October 3, 1996 15:57" */
 
246
  char **gcg_aseq;              /* aligned sequences with gaps converted to GCG format */
 
247
  char **gcg_sqname;            /* sequence names with GCG-valid character sets */
 
248
  int    idx;                   /* counter for sequences         */
 
249
  char  *s;                     /* pointer into sqname or seq    */
 
250
  int    len;                   /* tmp variable for name lengths */
 
251
  int    namelen;               /* maximum name length used      */
 
252
  int    pos;                   /* position counter              */
 
253
  char   buffer[51];            /* buffer for writing seq        */
 
254
  int    i;                     /* another position counter */
 
255
 
 
256
  /*****************************************************************
 
257
   * Make copies of sequence names and sequences.
 
258
   *   GCG recommends that name characters should only contain
 
259
   *   alphanumeric characters, -, or _
 
260
   *   Some GCG and GCG-compatible software is sensitive to this.
 
261
   *   We silently convert all other characters to '_'.
 
262
   *   
 
263
   *   For sequences, GCG allows only ~ and . for gaps.
 
264
   *   Otherwise, everthing is interpreted as a residue;
 
265
   *   so squid's IUPAC-restricted chars are fine. ~ means
 
266
   *   an external gap. . means an internal gap.
 
267
   *****************************************************************/ 
 
268
   
 
269
                                /* make copies that we can edit */
 
270
   gcg_aseq   = MallocOrDie(sizeof(char *) * msa->nseq);
 
271
   gcg_sqname = MallocOrDie(sizeof(char *) * msa->nseq);
 
272
   for (idx = 0; idx < msa->nseq; idx++)
 
273
     {
 
274
       gcg_aseq[idx]   = sre_strdup(msa->aseq[idx],   msa->alen);
 
275
       gcg_sqname[idx] = sre_strdup(msa->sqname[idx], -1);
 
276
     }
 
277
                                /* alter names as needed  */
 
278
   for (idx = 0; idx < msa->nseq; idx++)
 
279
     for (s = gcg_sqname[idx]; *s != '\0'; s++)
 
280
       if (! isalnum((int) *s) && *s != '-' && *s != '_')
 
281
         *s = '_';
 
282
                                /* alter gap chars in seq  */
 
283
   for (idx = 0; idx < msa->nseq; idx++)
 
284
     {
 
285
       for (s = gcg_aseq[idx]; *s != '\0' && isgap(*s); s++)
 
286
         *s = '~';
 
287
       for (; *s != '\0'; s++)
 
288
         if (isgap(*s)) *s = '.';
 
289
       for (pos = msa->alen-1; pos > 0 && isgap(gcg_aseq[idx][pos]); pos--)
 
290
         gcg_aseq[idx][pos] = '~';
 
291
     }
 
292
                                /* calculate max namelen used */
 
293
  namelen = 0;
 
294
  for (idx = 0; idx < msa->nseq; idx++)
 
295
    if ((len = strlen(msa->sqname[idx])) > namelen) 
 
296
      namelen = len;
 
297
 
 
298
  /*****************************************************
 
299
   * Write the MSF header
 
300
   *****************************************************/
 
301
                                /* required file type line */
 
302
  if (msa->type == kOtherSeq)
 
303
    msa->type = GuessAlignmentSeqtype(msa->aseq, msa->nseq);
 
304
 
 
305
  if      (msa->type == kRNA)   fprintf(fp, "!!NA_MULTIPLE_ALIGNMENT 1.0\n");
 
306
  else if (msa->type == kDNA)   fprintf(fp, "!!NA_MULTIPLE_ALIGNMENT 1.0\n");
 
307
  else if (msa->type == kAmino) fprintf(fp, "!!AA_MULTIPLE_ALIGNMENT 1.0\n");
 
308
  else if (msa->type == kOtherSeq) 
 
309
    Die("WriteMSF(): couldn't guess whether that alignment is RNA or protein.\n"); 
 
310
  else    
 
311
    Die("Invalid sequence type %d in WriteMSF()\n", msa->type); 
 
312
 
 
313
                                /* free text comments */
 
314
  if (msa->ncomment > 0)
 
315
    {
 
316
      for (idx = 0; idx < msa->ncomment; idx++)
 
317
        fprintf(fp, "%s\n", msa->comment[idx]);
 
318
      fprintf(fp, "\n");
 
319
    }
 
320
                                /* required checksum line */
 
321
  now = time(NULL);
 
322
  if (strftime(date, 64, "%B %d, %Y %H:%M", localtime(&now)) == 0)
 
323
    Die("What time is it on earth? strftime() failed in WriteMSF().\n");
 
324
  fprintf(fp, " %s  MSF: %d  Type: %c  %s  Check: %d  ..\n", 
 
325
          msa->name != NULL ? msa->name : "squid.msf",
 
326
          msa->alen,
 
327
          msa->type == kRNA ? 'N' : 'P',
 
328
          date,
 
329
          GCGMultchecksum(gcg_aseq, msa->nseq));
 
330
  fprintf(fp, "\n");
 
331
 
 
332
  /*****************************************************
 
333
   * Names/weights section
 
334
   *****************************************************/
 
335
 
 
336
  for (idx = 0; idx < msa->nseq; idx++)
 
337
    {
 
338
      fprintf(fp, " Name: %-*.*s  Len:  %5d  Check: %4d  Weight: %.2f\n",
 
339
              namelen, namelen,
 
340
              gcg_sqname[idx],
 
341
              msa->alen,
 
342
              GCGchecksum(gcg_aseq[idx], msa->alen),
 
343
              msa->wgt[idx]);
 
344
    }
 
345
  fprintf(fp, "\n");
 
346
  fprintf(fp, "//\n");
 
347
 
 
348
  /*****************************************************
 
349
   * Write the sequences
 
350
   *****************************************************/
 
351
 
 
352
  for (pos = 0; pos < msa->alen; pos += 50)
 
353
    {
 
354
      fprintf(fp, "\n");        /* Blank line between sequence blocks */
 
355
 
 
356
                                /* Coordinate line */
 
357
      len = (pos + 50) > msa->alen ? msa->alen - pos : 50;
 
358
      if (len > 10)
 
359
        fprintf(fp, "%*s  %-6d%*s%6d\n", namelen, "", 
 
360
                pos+1,
 
361
                len + ((len-1)/10) - 12, "",
 
362
                pos + len);
 
363
      else
 
364
        fprintf(fp, "%*s  %-6d\n", namelen, "", pos+1);
 
365
 
 
366
      for (idx = 0; idx < msa->nseq; idx++)
 
367
        {
 
368
          fprintf(fp, "%-*s ", namelen, gcg_sqname[idx]);
 
369
                                /* get next line's worth of 50 from seq */
 
370
          strncpy(buffer, gcg_aseq[idx] + pos, 50);
 
371
          buffer[50] = '\0';
 
372
                                /* draw the sequence line */
 
373
          for (i = 0; i < len; i++)
 
374
            {
 
375
              if (! (i % 10)) fputc(' ', fp);
 
376
              fputc(buffer[i], fp);
 
377
            }
 
378
          fputc('\n', fp);
 
379
        }
 
380
    }
 
381
 
 
382
  Free2DArray((void **) gcg_aseq,   msa->nseq);
 
383
  Free2DArray((void **) gcg_sqname, msa->nseq);
 
384
  return;
 
385
}
 
386
 
 
387
 
 
388