]> git.donarmstrong.com Git - fastq-tools.git/blob - src/parse.c
e27a3859ebdb24a6a9b7406fa0f9218d64b40e99
[fastq-tools.git] / src / parse.c
1
2 #include <stdbool.h>
3 #include <stdio.h>
4 #include <string.h>
5
6 #include "parse.h"
7 #include "common.h"
8
9
10 static void str_init(str_t* str)
11 {
12     str->n = 0;
13     str->size = 128;
14     str->s = malloc_or_die(str->size = 0);
15     str->s[0] = '\0';
16 }
17
18
19 static void str_free(str_t* str)
20 {
21     free(str->s);
22 }
23
24
25 /* Reserve space for `size` more characters. */
26 static void str_reserve_extra(str_t* str, size_t size)
27 {
28     if (str->n + size > str->size) {
29         if (str->n + size > 2 * str->size) {
30             str->size = str->n + size;
31         }
32         else str->size *= 2;
33         str->s = realloc_or_die(str->s, str->size * sizeof(char));
34     }
35 }
36
37
38 /* Copy n characters from c to the end of str. */
39 static void str_append(str_t* str, char* c, size_t n)
40 {
41     str_reserve_extra(str, n);
42     memcpy(str->s + str->n, c, n);
43     str->n += n;
44     str->s[str->n] = '\0';
45 }
46
47
48 seq_t* seq_create()
49 {
50     seq_t* seq = malloc_or_die(sizeof(seq_t));
51     str_init(&seq->id1);
52     str_init(&seq->seq);
53     str_init(&seq->id2);
54     str_init(&seq->qual);
55     return seq;
56 }
57
58
59 void seq_free(seq_t* seq)
60 {
61     str_free(&seq->id1);
62     str_free(&seq->seq);
63     str_free(&seq->id2);
64     str_free(&seq->qual);
65     free(seq);
66 }
67
68
69 static const size_t parser_buf_size = 1000000;
70
71
72 struct fastq_t_
73 {
74     FILE* file;
75     size_t readlen;
76     char* buf;
77     char* next;
78     bool linestart;
79 };
80
81
82
83 fastq_t* fastq_create(FILE* file)
84 {
85     fastq_t* f = malloc_or_die(sizeof(fastq_t));
86     f->file = file;
87     f->next = f->buf = malloc_or_die(parser_buf_size);
88     f->readlen = 0;
89     f->linestart = true;
90     return f;
91 }
92
93
94 void fastq_free(fastq_t* f)
95 {
96     free(f->buf);
97     free(f);
98 }
99
100
101 typedef enum {
102     FASTQ_STATE_ID1,  /* Reading ID1. */
103     FASTQ_STATE_SEQ,  /* Reading the sequence. */
104     FASTQ_STATE_ID2,  /* Reading ID2. */
105     FASTQ_STATE_QUAL, /* Reading quality scores. */
106 } fastq_parser_state_t;
107
108
109 bool fastq_read(fastq_t* f, seq_t* seq)
110 {
111     seq->id1.n = seq->seq.n = seq->id2.n = seq->qual.n = 0;
112     fastq_parser_state_t state = FASTQ_STATE_ID1;
113     char* end = f->buf + f->readlen;
114     do {
115         while (f->next < end) {
116             /* Consume pointless special characters prefixing IDs */
117             if ((state == FASTQ_STATE_ID1 && f->linestart && f->next[0] == '@') ||
118                 (state == FASTQ_STATE_ID2 && f->linestart && f->next[0] == '+')) {
119                 f->linestart = false;
120                 ++f->next;
121                 continue;
122             }
123
124             char* u = memchr(f->next, '\n', end - f->next);
125             if (u == NULL) {
126                 f->linestart = false;
127                 u = end;
128             }
129             else f->linestart = true;
130
131             switch (state) {
132                 case FASTQ_STATE_ID1:
133                     str_append(&seq->id1, f->next, u - f->next);
134                     if (f->linestart) state = FASTQ_STATE_SEQ;
135                     break;
136
137                 case FASTQ_STATE_SEQ:
138                     str_append(&seq->seq, f->next, u - f->next);
139                     if (f->linestart) state = FASTQ_STATE_ID2;
140                     break;
141
142                 case FASTQ_STATE_ID2:
143                     str_append(&seq->id2, f->next, u - f->next);
144                     if (f->linestart) state = FASTQ_STATE_QUAL;
145                     break;
146
147                 case FASTQ_STATE_QUAL:
148                     str_append(&seq->qual, f->next, u - f->next);
149                     if (f->linestart) {
150                         f->next = u + 1;
151                         return true;
152                     }
153                     break;
154             }
155
156             f->next = u + 1;
157         }
158
159         /* Try to read more. */
160         f->readlen = fread(f->buf, 1, parser_buf_size, f->file);
161         f->next = f->buf;
162         end = f->buf + f->readlen;
163     } while (f->readlen);
164
165     return false;
166 }
167
168
169 void fastq_print(FILE* fout, const seq_t* seq)
170 {
171     fprintf(fout, "@%s\n%s\n+%s\n%s\n",
172                   seq->id1.s,
173                   seq->seq.s,
174                   seq->id2.s,
175                   seq->qual.s );
176 }
177
178