filereader.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673
  1. /*
  2. *
  3. * Copyright (c) 2011, Jue Ruan <ruanjue@gmail.com>
  4. *
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #ifndef __FILEREADER_RJ_H
  20. #define __FILEREADER_RJ_H
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include <sys/types.h>
  25. #include <sys/stat.h>
  26. #include <unistd.h>
  27. #include <errno.h>
  28. #include "chararray.h"
  29. #include "mem_share.h"
  30. #include "list.h"
  31. #include "thread.h"
  32. #include "pgzf.h"
  33. #define BIOSEQ_ATTR_NULL 0
  34. #define BIOSEQ_ATTR_TAG 1
  35. #define BIOSEQ_ATTR_SEQ 2
  36. #define BIOSEQ_ATTR_QLT 4
  37. #define BIOSEQ_ATTR_FULL 7
  38. typedef struct {
  39. String *tag, *seq, *dsc, *qlt;
  40. u4i attr;
  41. } BioSequence;
  42. #define FILEREADER_TYPE_NULL 0
  43. #define FILEREADER_TYPE_FASTA 1
  44. #define FILEREADER_TYPE_FASTQ 2
  45. #define FILEREADER_TYPE_TEXT 3
  46. #define FILEREADER_ATTR_NULL 0
  47. #define FILEREADER_ATTR_NORMAL 1
  48. #define FILEREADER_ATTR_STDIN 2
  49. #define FILEREADER_ATTR_PROC 3
  50. #define FILEREADER_ATTR_TEXT 4
  51. #define FILEREADER_ATTR_USER 5 // defined by user
  52. typedef size_t (*read_data_func)(void *obj, void *dat, size_t len);
  53. typedef void (*close_input_func)(void *obj);
  54. static inline size_t _read_data_file(void *obj, void *dat, size_t len){ return fread(dat, 1, len, (FILE*)obj); }
  55. static inline void _close_input_file(void *obj){ if(obj) fclose((FILE*)obj); }
  56. static inline void _close_input_proc(void *obj){ if(obj) pclose((FILE*)obj); }
  57. typedef struct {
  58. int file_attr;
  59. char *filename;
  60. void *_file;
  61. read_data_func _read;
  62. close_input_func _close;
  63. } file_src_t;
  64. define_list_core(filesrcv, file_src_t, int, 0xFF);
  65. typedef struct {
  66. filesrcv *files;
  67. int fidx;
  68. char *buffer[2];
  69. int ridx, widx, flag;
  70. u8i bufmax, bufoff, bufcnt[2];
  71. #ifdef FR_USE_SPINLOCK
  72. pthread_spinlock_t lock;
  73. #else
  74. pthread_mutex_t lock;
  75. #endif
  76. char line_breaker;
  77. char delimiter;
  78. u8i n_char, n_line;
  79. String *line, *line2;
  80. VStrv *tabs;
  81. int rollback; // line will be re-used in next readline
  82. // thread
  83. pthread_t pid;
  84. int running;
  85. int eof;
  86. } FileReader;
  87. static inline BioSequence* init_biosequence(){
  88. BioSequence *seq;
  89. seq = malloc(sizeof(BioSequence));
  90. seq->tag = init_string(32);
  91. seq->seq = init_string(32);
  92. seq->dsc = init_string(32);
  93. seq->qlt = init_string(32);
  94. seq->attr = BIOSEQ_ATTR_FULL;
  95. return seq;
  96. }
  97. static inline void reset_biosequence(BioSequence *seq){
  98. clear_string(seq->tag);
  99. clear_string(seq->seq);
  100. clear_string(seq->dsc);
  101. clear_string(seq->qlt);
  102. }
  103. static inline void free_biosequence(BioSequence *seq){
  104. free_string(seq->tag);
  105. free_string(seq->seq);
  106. free_string(seq->dsc);
  107. free_string(seq->qlt);
  108. free(seq);
  109. }
  110. static inline void* file_src_thread_func(void *obj){
  111. FileReader *fr;
  112. file_src_t *fc;
  113. void *_file;
  114. read_data_func _read;
  115. close_input_func _close;
  116. size_t off, cnt, len;
  117. fr = (FileReader*)obj;
  118. while(fr->running){
  119. if(fr->fidx >= fr->files->size){
  120. fr->eof = 1;
  121. microsleep(1);
  122. } else {
  123. fr->eof = 0;
  124. fc = ref_filesrcv(fr->files, fr->fidx);
  125. _file = NULL;
  126. _read = NULL;
  127. _close = NULL;
  128. switch(fc->file_attr){
  129. case FILEREADER_ATTR_TEXT:
  130. len = strlen(fc->filename);
  131. off = 0;
  132. while(fr->running && len){
  133. while(fr->flag == 1 && fr->running){ nano_sleep(1); }
  134. cnt = num_min(len, fr->bufmax);
  135. memcpy(fr->buffer[fr->widx], fc->filename + off, cnt);
  136. fr->flag = 1;
  137. off += cnt;
  138. len -= cnt;
  139. fr->widx = !fr->widx;
  140. }
  141. break;
  142. case FILEREADER_ATTR_STDIN:
  143. if(_file == NULL){
  144. _file = fc->_file = stdin;
  145. _read = fc->_read = _read_data_file;
  146. _close = fc->_close = NULL;
  147. }
  148. case FILEREADER_ATTR_PROC:
  149. if(_file == NULL){
  150. _file = fc->_file = popen(fc->filename, "r");
  151. _read = fc->_read = _read_data_file;
  152. _close = fc->_close = _close_input_proc;
  153. }
  154. case FILEREADER_ATTR_USER:
  155. if(_file == NULL){
  156. _file = fc->_file;
  157. _read = fc->_read;
  158. _close = fc->_close;
  159. }
  160. default:
  161. if(_file == NULL){
  162. _file = fc->_file = open_file_for_read(fc->filename, NULL);
  163. _read = fc->_read = _read_data_file;
  164. _close = fc->_close = _close_input_file;
  165. }
  166. while(fr->running){
  167. while(fr->flag == 1){
  168. nano_sleep(1);
  169. if(fr->running == 0){
  170. break;
  171. }
  172. }
  173. if(fr->flag == 1) break;
  174. fr->bufcnt[fr->widx] = _read(_file, fr->buffer[fr->widx], fr->bufmax);
  175. fr->widx = !fr->widx;
  176. fr->flag = 1;
  177. if(fr->bufcnt[!fr->widx] == 0) break;
  178. }
  179. }
  180. if(_file && _close){
  181. _close(_file);
  182. }
  183. fr->fidx ++;
  184. }
  185. }
  186. return NULL;
  187. }
  188. static inline FileReader* init_filereader(){
  189. FileReader *fr;
  190. fr = malloc(sizeof(FileReader));
  191. fr->files = init_filesrcv(4);
  192. fr->fidx = 0;
  193. fr->bufmax = 128 * 1024;
  194. fr->bufoff = 0;
  195. fr->bufcnt[0] = 0;
  196. fr->bufcnt[1] = 0;
  197. fr->ridx = 0;
  198. fr->widx = 1;
  199. fr->flag = 0;
  200. #ifdef FR_USE_SPINLOCK
  201. pthread_spin_init(&fr->lock, 0);
  202. #else
  203. pthread_mutex_init(&fr->lock, NULL);
  204. #endif
  205. fr->buffer[0] = malloc(fr->bufmax);
  206. fr->buffer[1] = malloc(fr->bufmax);
  207. fr->line_breaker = '\n';
  208. fr->delimiter = '\t';
  209. fr->n_char = 0;
  210. fr->n_line = 0;
  211. fr->line = init_string(32);
  212. fr->line2 = init_string(32);
  213. fr->tabs = init_VStrv(16);
  214. fr->rollback = 0;
  215. fr->pid = 0;
  216. fr->running = 1;
  217. fr->eof = 0;
  218. return fr;
  219. }
  220. static inline void beg_asyn_filereader(FileReader *fr){
  221. if(pthread_create(&fr->pid, NULL, file_src_thread_func, fr) != 0){
  222. fprintf(stderr, " -- Failed to create thread [%s] in %s -- %s:%d --\n", "file_src_thread_func", __FUNCTION__, __FILE__, __LINE__);
  223. fr->pid = 0; // switch to directed read
  224. }
  225. }
  226. static inline void reset_filereader(FileReader *fr){
  227. if(fr->pid){
  228. fr->running = 0;
  229. pthread_join(fr->pid, NULL);
  230. }
  231. fr->fidx = 0;
  232. fr->bufoff = 0;
  233. fr->bufcnt[0] = 0;
  234. fr->bufcnt[1] = 0;
  235. fr->ridx = 0;
  236. fr->widx = 0;
  237. fr->flag = 0;
  238. #ifdef FR_USE_SPINLOCK
  239. pthread_spin_destroy(&fr->lock);
  240. pthread_spin_init(&fr->lock, 0);
  241. #else
  242. pthread_mutex_destroy(&fr->lock);
  243. pthread_mutex_init(&fr->lock, NULL);
  244. #endif
  245. clear_string(fr->line);
  246. clear_VStrv(fr->tabs);
  247. fr->rollback = 0;
  248. fr->n_line = 0;
  249. fr->n_char = 0;
  250. fr->running = 1;
  251. fr->eof = 0;
  252. if(fr->pid){
  253. fr->pid = 0;
  254. beg_asyn_filereader(fr);
  255. }
  256. }
  257. static inline void free_filereader(FileReader *fr){
  258. file_src_t *f;
  259. int i;
  260. if(fr->pid){
  261. fr->running = 0;
  262. pthread_join(fr->pid, NULL);
  263. }
  264. for(i=0;i<fr->files->size;i++){
  265. f = ref_filesrcv(fr->files, i);
  266. if(f->filename) free(f->filename);
  267. }
  268. #ifdef FR_USE_SPINLOCK
  269. pthread_spin_destroy(&fr->lock);
  270. #else
  271. pthread_mutex_destroy(&fr->lock);
  272. #endif
  273. free(fr->buffer[0]);
  274. free(fr->buffer[1]);
  275. free_filesrcv(fr->files);
  276. free_string(fr->line);
  277. free_string(fr->line2);
  278. free_VStrv(fr->tabs);
  279. free(fr);
  280. }
  281. static inline int push_filereader(FileReader *fr, char *filename){
  282. file_src_t *f;
  283. int len;
  284. f = next_ref_filesrcv(fr->files);
  285. f->_file = NULL;
  286. f->_read = NULL;
  287. f->_close = NULL;
  288. len = filename? strlen(filename) : 0;
  289. while(len && filename[len-1] == ' ') len --;
  290. if(len == 0 || strcmp(filename, "-") == 0){
  291. f->filename = NULL;
  292. f->file_attr = FILEREADER_ATTR_STDIN;
  293. } else if(filename[len-1] == '|'){
  294. f->filename = malloc(len);
  295. strncpy(f->filename, filename, len - 1);
  296. f->file_attr = FILEREADER_ATTR_PROC;
  297. } else if(len > 3 && strcmp(filename + len - 3, ".gz") == 0){
  298. //f->filename = malloc(len + 20);
  299. //sprintf(f->filename, "gzip -dc %s", filename);
  300. //f->file_attr = FILEREADER_ATTR_PROC;
  301. f->filename = strdup(filename);
  302. f->file_attr = FILEREADER_ATTR_USER;
  303. f->_file = open_pgzf_reader(open_file_for_read(f->filename, NULL), 0, 4);
  304. f->_read = read_pgzf4filereader;
  305. f->_close = close_pgzf4filereader;
  306. } else if(len > 5 && strcmp(filename + len - 5, ".pgzf") == 0){
  307. f->filename = strdup(filename);
  308. f->file_attr = FILEREADER_ATTR_USER;
  309. f->_file = open_pgzf_reader(open_file_for_read(f->filename, NULL), 0, 4);
  310. f->_read = read_pgzf4filereader;
  311. f->_close = close_pgzf4filereader;
  312. } else {
  313. f->filename = strdup(filename);
  314. f->file_attr = FILEREADER_ATTR_NORMAL;
  315. }
  316. return f->file_attr;
  317. }
  318. static inline int push_text_filereader(FileReader *fr, char *str, size_t len){
  319. file_src_t *f;
  320. UNUSED(len);
  321. f = next_ref_filesrcv(fr->files);
  322. f->_file = NULL;
  323. f->_read = NULL;
  324. f->_close = NULL;
  325. f->filename = str;
  326. f->file_attr = FILEREADER_ATTR_TEXT;
  327. return f->file_attr;
  328. }
  329. static inline int push_user_filereader(FileReader *fr, void *_file, read_data_func _read, close_input_func _close){
  330. file_src_t *f;
  331. f = next_ref_filesrcv(fr->files);
  332. f->_file = _file;
  333. f->_read = _read;
  334. f->_close = _close;
  335. f->filename = NULL;
  336. f->file_attr = FILEREADER_ATTR_USER;
  337. return f->file_attr;
  338. }
  339. static inline void push_all_filereader(FileReader *fr, int nfile, char **filenames){
  340. int i;
  341. for(i=0;i<nfile;i++) push_filereader(fr, filenames[i]);
  342. }
  343. // asyn: asynchronous reading
  344. static inline FileReader* open_filereader(char *filename, int asyn){
  345. FileReader *fr;
  346. fr = init_filereader();
  347. push_filereader(fr, filename);
  348. if(asyn) beg_asyn_filereader(fr);
  349. return fr;
  350. }
  351. static inline FileReader* string_filereader(char *str, int asyn){
  352. int len;
  353. FileReader *fr;
  354. len = str? strlen(str) : 0;
  355. fr = init_filereader();
  356. push_text_filereader(fr, str, len);
  357. if(asyn) beg_asyn_filereader(fr);
  358. return fr;
  359. }
  360. static inline FileReader* open_all_filereader(int nfile, char **filenames, int asyn){
  361. FileReader *fr;
  362. fr = init_filereader();
  363. push_all_filereader(fr, nfile, filenames);
  364. if(asyn) beg_asyn_filereader(fr);
  365. return fr;
  366. }
  367. #define close_filereader(fr) free_filereader(fr)
  368. static inline int asyn_readline_filereader(FileReader *fr, String *line){
  369. char *buffer;
  370. u8i i, nc;
  371. int ret;
  372. if(fr->rollback){
  373. fr->rollback = 0;
  374. return line->size + 1; // in case of end of file and not terminated by line_breaker, the return value is bigger by 1
  375. } else if(fr->eof && fr->bufoff == fr->bufcnt[fr->ridx]){
  376. return 0;
  377. } else {
  378. clear_string(line);
  379. nc = fr->n_char;
  380. while(1){
  381. buffer = fr->buffer[fr->ridx];
  382. ret = 0;
  383. for(i=fr->bufoff;i<fr->bufcnt[fr->ridx];){
  384. if(buffer[i++] == fr->line_breaker){
  385. ret = 1;
  386. break;
  387. }
  388. }
  389. fr->n_char += i - fr->bufoff;
  390. encap_string(line, i - fr->bufoff);
  391. append_string(line, buffer + fr->bufoff, i - fr->bufoff - ret);
  392. fr->bufoff = i;
  393. if(ret){
  394. return fr->n_char - nc;
  395. } else if(fr->eof){
  396. return fr->n_char - nc;
  397. }
  398. fr->bufoff = 0;
  399. fr->bufcnt[fr->ridx] = 0;
  400. while(fr->flag == 0){
  401. nano_sleep(1);
  402. if(fr->eof){
  403. if(fr->flag) break;
  404. else {
  405. return fr->n_char - nc;
  406. }
  407. }
  408. }
  409. fr->flag = 0;
  410. fr->ridx = !fr->ridx;
  411. }
  412. return 0;
  413. }
  414. }
  415. static inline int directed_readline_filereader(FileReader *fr, String *line){
  416. file_src_t *fc;
  417. void *_file;
  418. read_data_func _read;
  419. close_input_func _close;
  420. u8i i, nc;
  421. int ch;
  422. int ret;
  423. if(fr->eof) return 0;
  424. else if(fr->rollback){
  425. fr->rollback = 0;
  426. return line->size + 1; // in case of end of file and not terminated by line_breaker, the return value is bigger by 1
  427. }
  428. clear_string(line);
  429. nc = fr->n_char;
  430. while(fr->fidx < fr->files->size){
  431. fc = ref_filesrcv(fr->files, fr->fidx);
  432. _file = NULL;
  433. _read = NULL;
  434. _close = NULL;
  435. if(fr->flag == 0){
  436. switch(fc->file_attr){
  437. case FILEREADER_ATTR_TEXT:
  438. break;
  439. case FILEREADER_ATTR_STDIN:
  440. _file = fc->_file = stdin;
  441. _read = fc->_read = _read_data_file;
  442. _close = fc->_close = NULL;
  443. break;
  444. case FILEREADER_ATTR_PROC:
  445. _file = fc->_file = popen(fc->filename, "r");
  446. _read = fc->_read = _read_data_file;
  447. _close = fc->_close = _close_input_proc;
  448. break;
  449. case FILEREADER_ATTR_USER:
  450. _file = fc->_file;
  451. _read = fc->_read;
  452. _close = fc->_close;
  453. break;
  454. default:
  455. _file = fc->_file = open_file_for_read(fc->filename, NULL);
  456. _read = fc->_read = _read_data_file;
  457. _close = fc->_close = _close_input_file;
  458. break;
  459. }
  460. fr->flag = 1;
  461. fr->bufoff = 0;
  462. fr->bufcnt[0] = fr->bufcnt[1] = 0;
  463. } else {
  464. _file = fc->_file;
  465. _read = fc->_read;
  466. _close = fc->_close;
  467. }
  468. switch(fc->file_attr){
  469. case FILEREADER_ATTR_TEXT:
  470. ret = 0;
  471. for(i=fr->bufoff;fc->filename[i];){
  472. if(fc->filename[i++] == fr->line_breaker){
  473. ret = 1;
  474. break;
  475. }
  476. }
  477. fr->n_char += i - fr->bufoff;
  478. encap_string(line, i - fr->bufoff);
  479. append_string(line, fc->filename + fr->bufoff, i - fr->bufoff - ret);
  480. fr->bufoff = i;
  481. if(ret){
  482. break;
  483. }
  484. break;
  485. case FILEREADER_ATTR_STDIN:
  486. while((ch = fgetc(stdin)) != EOF){
  487. fr->n_char ++;
  488. if(ch == fr->line_breaker){
  489. break;
  490. }
  491. add_char_string(line, ch);
  492. }
  493. break;
  494. default:
  495. while(1){
  496. if(fr->bufoff >= fr->bufcnt[0]){
  497. fr->bufoff = 0;
  498. fr->bufcnt[0] = _read(_file, fr->buffer[0], fr->bufmax);
  499. if(fr->bufcnt[0] == 0) break;
  500. }
  501. ret = 0;
  502. for(i=fr->bufoff;i<fr->bufcnt[0];){
  503. if(fr->buffer[0][i++] == fr->line_breaker){
  504. ret = 1;
  505. break;
  506. }
  507. }
  508. fr->n_char += i - fr->bufoff;
  509. encap_string(line, i - fr->bufoff);
  510. append_string(line, fr->buffer[0] + fr->bufoff, i - fr->bufoff - ret);
  511. fr->bufoff = i;
  512. if(ret){
  513. break;
  514. }
  515. }
  516. break;
  517. }
  518. if(fr->n_char > nc){
  519. return fr->n_char - nc;
  520. } else {
  521. if(_file && _close){
  522. _close(_file);
  523. }
  524. fr->flag = 0;
  525. fr->fidx ++;
  526. }
  527. }
  528. fr->eof = 1;
  529. return 0;
  530. }
  531. int readline_filereader(FileReader *fr){
  532. int ret;
  533. ret = ((fr)->pid? asyn_readline_filereader(fr, (fr)->line) : directed_readline_filereader(fr, (fr)->line));
  534. if(ret > 0){
  535. fr->n_line ++;
  536. }
  537. return ret;
  538. }
  539. static inline void rollback_filereader(FileReader *fr){
  540. fr->rollback = 1;
  541. fr->n_line --;
  542. }
  543. static inline int split_line_filereader(FileReader *fr, char delimiter){
  544. VString *vs;
  545. int i;
  546. clear_VStrv(fr->tabs);
  547. vs = next_ref_VStrv(fr->tabs);
  548. vs->string = fr->line->string;
  549. vs->size = 0;
  550. for(i=0;i<fr->line->size;i++){
  551. if(fr->line->string[i] == delimiter){
  552. vs->size = fr->line->string + i - vs->string;
  553. vs = next_ref_VStrv(fr->tabs);
  554. vs->string = fr->line->string + i + 1;
  555. vs->size = 0;
  556. }
  557. }
  558. vs->size = fr->line->string + fr->line->size - vs->string;
  559. return (int)fr->tabs->size;
  560. }
  561. static inline int readtable_filereader(FileReader *fr){
  562. if(readline_filereader(fr) == 0) return -1;
  563. return split_line_filereader(fr, fr->delimiter);
  564. }
  565. static inline int get_col_len(FileReader *fr, int col){
  566. return fr->tabs->buffer[col].size;
  567. }
  568. static inline char* get_col_str(FileReader *fr, int col){
  569. VString *vs;
  570. vs = ref_VStrv(fr->tabs, col);
  571. vs->string[vs->size] = '\0';
  572. return vs->string;
  573. }
  574. static inline char* get_line_str(FileReader *fr){
  575. int i;
  576. for(i=0;i<fr->line->size;i++){
  577. if(fr->line->string[i] == 0){
  578. fr->line->string[i] = fr->delimiter;
  579. }
  580. }
  581. return fr->line->string;
  582. }
  583. // @return FILEREADER_TYPE_NULL (end of files), _FASTA, _FASTQ, or _TEXT (cannot parse sequence type)
  584. static inline int readseq_filereader(FileReader *fr, BioSequence *seq){
  585. int n, i;
  586. do {
  587. if((n = readline_filereader(fr)) == 0) return FILEREADER_TYPE_NULL;
  588. } while(n == 0);
  589. reset_biosequence(seq);
  590. if(fr->line->string[0] == '>'){
  591. if(seq->attr & BIOSEQ_ATTR_TAG){
  592. for(i=1;i<fr->line->size;i++){
  593. if(fr->line->string[i] == ' ' || fr->line->string[i] == '\t') break;
  594. }
  595. append_string(seq->tag, fr->line->string + 1, i - 1);
  596. append_string(seq->dsc, fr->line->string + i, fr->line->size - i);
  597. }
  598. while((n = readline_filereader(fr))){
  599. if(fr->line->string[0] == '>'){
  600. rollback_filereader(fr);
  601. break;
  602. } else if(seq->attr & BIOSEQ_ATTR_SEQ){
  603. append_string(seq->seq, fr->line->string, fr->line->size);
  604. }
  605. }
  606. return FILEREADER_TYPE_FASTA;
  607. } else if(fr->line->string[0] == '@'){
  608. if(seq->attr & BIOSEQ_ATTR_TAG){
  609. for(i=1;i<fr->line->size;i++){
  610. if(fr->line->string[i] == ' ' || fr->line->string[i] == '\t') break;
  611. }
  612. append_string(seq->tag, fr->line->string + 1, i - 1);
  613. append_string(seq->dsc, fr->line->string + i, fr->line->size - i);
  614. }
  615. if((n = readline_filereader(fr))){
  616. if(seq->attr & BIOSEQ_ATTR_SEQ) append_string(seq->seq, fr->line->string, fr->line->size);
  617. } else {
  618. return FILEREADER_TYPE_FASTQ;
  619. }
  620. if((n = readline_filereader(fr))){
  621. // expected '+'
  622. } else {
  623. return FILEREADER_TYPE_FASTQ;
  624. }
  625. if((n = readline_filereader(fr))){
  626. if(seq->attr & BIOSEQ_ATTR_QLT) append_string(seq->qlt, fr->line->string, fr->line->size);
  627. } else {
  628. return FILEREADER_TYPE_FASTQ;
  629. }
  630. return FILEREADER_TYPE_FASTQ;
  631. } else {
  632. append_string(seq->dsc, fr->line->string, fr->line->size);
  633. return FILEREADER_TYPE_TEXT;
  634. }
  635. }
  636. #endif