|
|
@@ -44,6 +44,7 @@ |
|
|
type_t f; \
|
|
|
} kstream_t;
|
|
|
|
|
|
+#define ks_err(ks) ((ks)->end == -1)
|
|
|
#define ks_eof(ks) ((ks)->is_eof && (ks)->begin >= (ks)->end)
|
|
|
#define ks_rewind(ks) ((ks)->is_eof = (ks)->begin = (ks)->end = 0)
|
|
|
|
|
|
@@ -66,11 +67,13 @@ |
|
|
#define __KS_GETC(__read, __bufsize) \
|
|
|
static inline int ks_getc(kstream_t *ks) \
|
|
|
{ \
|
|
|
+ if (ks_err(ks)) return -3; \
|
|
|
if (ks->is_eof && ks->begin >= ks->end) return -1; \
|
|
|
if (ks->begin >= ks->end) { \
|
|
|
ks->begin = 0; \
|
|
|
ks->end = __read(ks->f, ks->buf, __bufsize); \
|
|
|
if (ks->end == 0) { ks->is_eof = 1; return -1;} \
|
|
|
+ if (ks->end == -1) { ks->is_eof = 1; return -3;}\
|
|
|
} \
|
|
|
return (int)ks->buf[ks->begin++]; \
|
|
|
}
|
|
|
@@ -95,11 +98,13 @@ typedef struct __kstring_t { |
|
|
str->l = append? str->l : 0; \
|
|
|
for (;;) { \
|
|
|
int i; \
|
|
|
+ if (ks_err(ks)) return -3; \
|
|
|
if (ks->begin >= ks->end) { \
|
|
|
if (!ks->is_eof) { \
|
|
|
ks->begin = 0; \
|
|
|
ks->end = __read(ks->f, ks->buf, __bufsize); \
|
|
|
if (ks->end == 0) { ks->is_eof = 1; break; } \
|
|
|
+ if (ks->end == -1) { ks->is_eof = 1; return -3; } \
|
|
|
} else break; \
|
|
|
} \
|
|
|
if (delimiter == KS_SEP_LINE) { \
|
|
|
@@ -167,25 +172,26 @@ typedef struct __kstring_t { |
|
|
>=0 length of the sequence (normal)
|
|
|
-1 end-of-file
|
|
|
-2 truncated quality string
|
|
|
+ -3 error reading stream
|
|
|
*/
|
|
|
#define __KSEQ_READ(SCOPE) \
|
|
|
SCOPE int kseq_read(kseq_t *seq) \
|
|
|
{ \
|
|
|
- int c; \
|
|
|
+ int c,r; \
|
|
|
kstream_t *ks = seq->f; \
|
|
|
if (seq->last_char == 0) { /* then jump to the next header line */ \
|
|
|
- while ((c = ks_getc(ks)) != -1 && c != '>' && c != '@'); \
|
|
|
- if (c == -1) return -1; /* end of file */ \
|
|
|
+ while ((c = ks_getc(ks)) >= 0 && c != '>' && c != '@'); \
|
|
|
+ if (c < 0) return c; /* end of file or error*/ \
|
|
|
seq->last_char = c; \
|
|
|
} /* else: the first header char has been read in the previous call */ \
|
|
|
seq->comment.l = seq->seq.l = seq->qual.l = 0; /* reset all members */ \
|
|
|
- if (ks_getuntil(ks, 0, &seq->name, &c) < 0) return -1; /* normal exit: EOF */ \
|
|
|
+ if ((r=ks_getuntil(ks, 0, &seq->name, &c)) < 0) return r; /* normal exit: EOF or error */ \
|
|
|
if (c != '\n') ks_getuntil(ks, KS_SEP_LINE, &seq->comment, 0); /* read FASTA/Q comment */ \
|
|
|
if (seq->seq.s == 0) { /* we can do this in the loop below, but that is slower */ \
|
|
|
seq->seq.m = 256; \
|
|
|
seq->seq.s = (char*)malloc(seq->seq.m); \
|
|
|
} \
|
|
|
- while ((c = ks_getc(ks)) != -1 && c != '>' && c != '+' && c != '@') { \
|
|
|
+ while ((c = ks_getc(ks)) >= 0 && c != '>' && c != '+' && c != '@') { \
|
|
|
if (c == '\n') continue; /* skip empty lines */ \
|
|
|
seq->seq.s[seq->seq.l++] = c; /* this is safe: we always have enough space for 1 char */ \
|
|
|
ks_getuntil2(ks, KS_SEP_LINE, &seq->seq, 0, 1); /* read the rest of the line */ \
|
|
|
@@ -202,9 +208,10 @@ typedef struct __kstring_t { |
|
|
seq->qual.m = seq->seq.m; \
|
|
|
seq->qual.s = (char*)realloc(seq->qual.s, seq->qual.m); \
|
|
|
} \
|
|
|
- while ((c = ks_getc(ks)) != -1 && c != '\n'); /* skip the rest of '+' line */ \
|
|
|
+ while ((c = ks_getc(ks)) >= 0 && c != '\n'); /* skip the rest of '+' line */ \
|
|
|
if (c == -1) return -2; /* error: no quality string */ \
|
|
|
- while (ks_getuntil2(ks, KS_SEP_LINE, &seq->qual, 0, 1) >= 0 && seq->qual.l < seq->seq.l); \
|
|
|
+ while ((c = ks_getuntil2(ks, KS_SEP_LINE, &seq->qual, 0, 1) >= 0 && seq->qual.l < seq->seq.l)); \
|
|
|
+ if (c == -3) return -3; /* stream error */ \
|
|
|
seq->last_char = 0; /* we have not come to the next header line */ \
|
|
|
if (seq->seq.l != seq->qual.l) return -2; /* error: qual string is of a different length */ \
|
|
|
return seq->seq.l; \
|
|
|
|
0 comments on commit
d0b8b55