Mercurial > repos > dawe > srf2fastq
comparison srf2fastq/io_lib-1.12.2/io_lib/expFileIO.c @ 0:d901c9f41a6a default tip
Migrated tool version 1.0.1 from old tool shed archive to new tool shed repository
author | dawe |
---|---|
date | Tue, 07 Jun 2011 17:48:05 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:d901c9f41a6a |
---|---|
1 /* | |
2 * Copyright (c) Medical Research Council 1994. All rights reserved. | |
3 * | |
4 * Permission to use, copy, modify and distribute this software and its | |
5 * documentation for any purpose is hereby granted without fee, provided that | |
6 * this copyright and notice appears in all copies. | |
7 * | |
8 * This file was written by James Bonfield, Simon Dear, Rodger Staden, | |
9 * as part of the Staden Package at the MRC Laboratory of Molecular | |
10 * Biology, Hills Road, Cambridge, CB2 2QH, United Kingdom. | |
11 * | |
12 * MRC disclaims all warranties with regard to this software. | |
13 */ | |
14 | |
15 /* | |
16 * File: expFileIO.c | |
17 * Version: | |
18 * | |
19 * Description: Routines for reading and writing to experiment files. | |
20 * | |
21 * 1. Opening experiment files | |
22 * 2. Reading information from an experiment file | |
23 * 3. Appending to experiment files | |
24 * 4. Closing an opened experiment file | |
25 * | |
26 * Created: | |
27 * Updated: | |
28 * | |
29 */ | |
30 | |
31 /* | |
32 * Tag format: | |
33 * | |
34 * 0 10 | |
35 * |----.----|- | |
36 * TG TYPE S position..length | |
37 * TG One or more comment lines starting at character position 10 | |
38 * TG Each line represents a line of tag. | |
39 * TG Extra indentation is simply added to the comment. | |
40 * | |
41 * Where S is the strand, either "+", "-", or "=" (both). | |
42 * Eg: | |
43 * | |
44 * TG COMM = 100..110 | |
45 * TG This comment contains | |
46 * TG several lines. | |
47 * | |
48 * So the above is a COMMent tag on both strands from bases 100 to 110 | |
49 * inclusive containing the annotation | |
50 * "This comment contains\n several lines.\n" | |
51 * | |
52 * This is written using exp_put_str giving the multi line string: | |
53 * "COMM = 100..110\nThis comment contains\n several lines." | |
54 * | |
55 * (ie the indentation is added by the experiment file format, not by the | |
56 * calling routines. Similarly this indentation is stripped out again when | |
57 * reading back.) | |
58 */ | |
59 | |
60 | |
61 #include <stdio.h> | |
62 #include <string.h> /* IMPORT: strdup (hopefully!) */ | |
63 #include <ctype.h> | |
64 | |
65 /* 6/1/99 johnt - includes needed for Visual C++ */ | |
66 #ifdef _MSC_VER | |
67 # include <io.h> | |
68 # include <fcntl.h> | |
69 #endif | |
70 | |
71 #include "io_lib/expFileIO.h" | |
72 #include "io_lib/xalloc.h" | |
73 #include "io_lib/misc.h" | |
74 #include "io_lib/stdio_hack.h" | |
75 | |
76 /* Fixup for broken SunOS 4.x systems */ | |
77 #ifndef FOPEN_MAX | |
78 #define FOPEN_MAX 20 | |
79 #endif | |
80 | |
81 static int exp_check_eid_read(Exp_info *e,int id); | |
82 | |
83 /************************************************************* | |
84 * Line types for experiment file | |
85 *************************************************************/ | |
86 | |
87 char eflt_feature_ids[MAXIMUM_EFLTS][MAXIMUM_EFLT_LENGTH+1] = { | |
88 "CF", /* 0 cloning vector sequence file */ | |
89 "CN", /* 1 clone name */ | |
90 "CS", /* 2 cloning vector sequence present in sequence */ | |
91 "CV", /* 3 cloning vector type */ | |
92 "DR", /* 4 direction of read */ | |
93 "DT", /* 5 date of experiment */ | |
94 "EN", /* 6 experiment name */ | |
95 "EX", /* 7 experimental notes */ | |
96 "FM", /* 8 sequencing vector fragmentation method */ | |
97 "LN", /* 9 local format trace file name */ | |
98 "LT", /* 10 local format trace file type */ | |
99 "MC", /* 11 machine on which experiment ran */ | |
100 "MN", /* 12 machine generated trace file name */ | |
101 "MT", /* 13 machine generated trace file type */ | |
102 "OP", /* 14 operator */ | |
103 "PN", /* 15 primer name */ | |
104 "QR", /* 16 poor quality sequence present at right (3') end */ | |
105 "SC", /* 17 sequencing vector cloning site */ | |
106 "SF", /* 18 sequencing vector sequence file */ | |
107 "SI", /* 19 sequencing vector insertion length */ | |
108 "SL", /* 20 sequencing vector present at left (5') end */ | |
109 "SP", /* 21 sequencing vector primer site (relative to cloning site) */ | |
110 "SQ", /* 22 sequence */ | |
111 "SR", /* 23 sequencing vector present at right (3') end */ | |
112 "ST", /* 24 strands */ | |
113 "SV", /* 25 sequencing vector type */ | |
114 "TN", /* 26 template name */ | |
115 "QL", /* 27 poor quality sequence present at left (5') end */ | |
116 "PS", /* 28 processing status */ | |
117 "CC", /* 29 comments */ | |
118 "SS", /* 30 sequence to screen against */ | |
119 /* added 27-May-93 */ | |
120 "TG", /* 31 gel tag line */ | |
121 "ID", /* 32 identifier */ | |
122 /* added 24-Sep-93 */ | |
123 "AQ", /* 33 average quality measure */ | |
124 /* added 15-Oct-93 */ | |
125 "PR", /* 34 primer type */ | |
126 "LI", /* 35 subclone library (mtd) */ | |
127 "LE", /* 36 subclone library entry (well) */ | |
128 /* added 19-Apr-94 */ | |
129 "TC", /* 37 contig tag line */ | |
130 "AC", /* 38 accession number */ | |
131 /* added 11-Nov-94 */ | |
132 "BC", /* 39 base calling software */ | |
133 "ON", /* 40 original base numbers (positions) */ | |
134 "AV", /* 41 accuracy (quality) values */ | |
135 "PC", /* 42 position in contig */ | |
136 "SE", /* 43 sense, whether it is complemented */ | |
137 /* added 5-4-95 */ | |
138 "CL", /* 44 cloning vector left end*/ | |
139 "CR", /* 45 cloning vector right end*/ | |
140 "AP", /* 46 assembly position */ | |
141 "CH", /* 47 special chemistry used (eg taq) */ | |
142 "PD", /* 48 primer data - the sequence of a primer */ | |
143 "WT", /* 49 wild type trace */ | |
144 "NT", /* 50 note */ | |
145 "GD", /* 51 Gap4 database file */ | |
146 "WL", /* 52 wildtype trace left clip point */ | |
147 "WR", /* 53 wildtype trace right clip point */ | |
148 "FT", /* 54 EMBL format feature table */ | |
149 "LG" /* 55 LiGation: an amalgamation of LI and LE */ | |
150 }; | |
151 | |
152 | |
153 | |
154 | |
155 /************************************************************* | |
156 * Output/update lines | |
157 *************************************************************/ | |
158 | |
159 static int exp_print_line_(FILE *fp, char *eflt, char *entry) | |
160 /* | |
161 * Output an experiment file line | |
162 */ | |
163 { | |
164 return fprintf(fp, | |
165 "%-5s%s\n", | |
166 eflt, | |
167 entry | |
168 ) < 0; | |
169 } | |
170 | |
171 int exp_print_line(FILE *fp, Exp_info *e, int eflt, int i) | |
172 /* | |
173 * Output an experiment file line | |
174 */ | |
175 { | |
176 return exp_print_line_(fp, | |
177 eflt_feature_ids[eflt], | |
178 arr(char *,e->entries[eflt],i) | |
179 ); | |
180 } | |
181 | |
182 /* | |
183 * Outputs a multi-line experiment file line. | |
184 * Continuation lines are automatically added by adding 5 characters of extra | |
185 * indentation at the start of each continuation. | |
186 * | |
187 * returns -1 for failure, 0 for success. | |
188 */ | |
189 int exp_print_mline(FILE *fp, Exp_info *e, int eflt, int i) { | |
190 char *p, *c; | |
191 | |
192 p = arr(char *, e->entries[eflt], i); | |
193 | |
194 /* first line */ | |
195 if (c = strchr(p, '\n')) | |
196 *c = '\0'; | |
197 if (-1 == exp_print_line_(fp, eflt_feature_ids[eflt], p)) | |
198 return -1; | |
199 | |
200 while (c) { | |
201 *c = '\n'; | |
202 p = c+1; | |
203 | |
204 if (c = strchr(p, '\n')) { | |
205 *c = '\0'; | |
206 } | |
207 | |
208 if (-1 == fprintf(fp, "%-10s%s\n", eflt_feature_ids[eflt], p)) | |
209 return -1; | |
210 } | |
211 | |
212 return 0; | |
213 } | |
214 | |
215 | |
216 int exp_print_seq(FILE *fp, Exp_info *e, int eflt, int i) | |
217 /* | |
218 * Output an experiment file multi line | |
219 */ | |
220 { | |
221 int j, l; | |
222 char *seq; | |
223 if (fprintf(fp,"%-5s",eflt_feature_ids[eflt])<0) return 1; | |
224 | |
225 l = strlen(seq = arr(char *,e->entries[eflt],i)); | |
226 for(j=0;j<l;j++) { | |
227 if (j%60==0) if ( fprintf(fp,"\n ") < 0 ) return 1; | |
228 if (j%10==0) if ( fprintf(fp," ") < 0 ) return 1; | |
229 if ( fprintf(fp,"%c",seq[j]) < 0 ) return 1; | |
230 } | |
231 if ( fprintf(fp,"\n//\n") < 0 ) return 1; | |
232 | |
233 return 0; | |
234 } | |
235 | |
236 int exp_get_feature_index(char *e) | |
237 { | |
238 int i; | |
239 for (i = 0; i < MAXIMUM_EFLTS; i++) { | |
240 if (eflt_feature_ids[i][0] == e[0] && | |
241 eflt_feature_ids[i][1] == e[1]) | |
242 return i; | |
243 } | |
244 | |
245 return -1; | |
246 } | |
247 | |
248 | |
249 /************************************************************* | |
250 * Utility routines | |
251 *************************************************************/ | |
252 | |
253 /* | |
254 * Creates a string of 'range format' from the start and end points. | |
255 * The string (of form start..end) is also returned. | |
256 */ | |
257 char *exp_create_range(char *str, int start, int end) { | |
258 sprintf(str, "%d..%d", start, end); | |
259 return str; | |
260 } | |
261 | |
262 /* | |
263 * Extracts the start and end points from a range string. | |
264 * Returns 0 for success and -1 for failure. | |
265 */ | |
266 int exp_extract_range(char *str, int *start, int *end) { | |
267 return sscanf(str, "%d..%d", start, end) != 2; | |
268 } | |
269 | |
270 Exp_info *exp_create_info(void) | |
271 /* | |
272 * Allocate space for new experiment file information | |
273 */ | |
274 { | |
275 Exp_info *new; | |
276 int i; | |
277 | |
278 new = (Exp_info *)xmalloc(sizeof(Exp_info)); | |
279 if (new != NULL) { | |
280 for(i=0; i< MAXIMUM_EFLTS ; i++) { | |
281 new->Nentries[i] = 0; | |
282 new->entries[i] = ArrayCreate(sizeof(char *), 1/*one entry*/); | |
283 } | |
284 new->fp = NULL; | |
285 } | |
286 | |
287 return new; | |
288 } | |
289 | |
290 | |
291 void exp_destroy_info(Exp_info *e) | |
292 /* | |
293 * Destroy experiment file information | |
294 */ | |
295 { | |
296 int i; | |
297 int j; | |
298 if (e != NULL_Exp_info) { | |
299 for (i = 0; i < MAXIMUM_EFLTS; i++) { | |
300 Array a = e->entries[i]; | |
301 for(j=0;j<e->Nentries[i];j++) | |
302 if (arr(char *,a,j) != NULL) xfree(arr(char *,a,j)); | |
303 ArrayDestroy(a); | |
304 } | |
305 if (e->fp != NULL) fclose(e->fp); | |
306 xfree(e); | |
307 } | |
308 } | |
309 | |
310 | |
311 | |
312 | |
313 /* | |
314 * Read from file a sequence, discarding all white space til a // is | |
315 * encountered | |
316 */ | |
317 static char *exp_read_sequence(FILE *fp) | |
318 { | |
319 char *seq = NULL; | |
320 size_t seq_len = 0, seq_alloc; | |
321 char line[EXP_FILE_LINE_LENGTH+1]; | |
322 char *l; | |
323 static int valid_char[256], init = 0; | |
324 | |
325 /* Initialise lookup tables for efficiency later on.*/ | |
326 if (!init) { | |
327 int i; | |
328 for (i = 0; i < 256; i++) { | |
329 if (i < 128 && !isspace(i) && !isdigit(i) && !iscntrl(i)) | |
330 valid_char[i] = 1; | |
331 else | |
332 valid_char[i] = 0; | |
333 } | |
334 init = 1; | |
335 } | |
336 | |
337 /* Initialise memory */ | |
338 seq_alloc = EXP_FILE_LINE_LENGTH * 8; | |
339 seq = (char *)xmalloc(seq_alloc); | |
340 if (NULL == seq) | |
341 return NULL; | |
342 seq[0] = '\0'; | |
343 | |
344 /* Reading line by line, until we get "//" */ | |
345 l = fgets(line,EXP_FILE_LINE_LENGTH,fp); | |
346 while (l!= NULL && strncmp(l,"//",2)) { | |
347 char *a, *b; | |
348 | |
349 /* make sure the seq buffer is large enough */ | |
350 if (seq_len + EXP_FILE_LINE_LENGTH + 1 > seq_alloc) { | |
351 seq_alloc *= 2; | |
352 if (NULL == (seq = (char *)xrealloc(seq, seq_alloc))) | |
353 return NULL; | |
354 } | |
355 | |
356 /* copy to seq, stripping spaces on the fly */ | |
357 for(a=line, b = &seq[seq_len]; *a; a++) | |
358 if (valid_char[(unsigned char)*a]) | |
359 *b++ = *a; | |
360 *b = '\0'; | |
361 seq_len = b-seq; | |
362 | |
363 l = fgets(line,EXP_FILE_LINE_LENGTH,fp); | |
364 } | |
365 | |
366 /* Shrink the allocated string to reduce memory usage */ | |
367 seq = (char *)xrealloc(seq, seq_len + 1); | |
368 | |
369 return seq; | |
370 } | |
371 | |
372 | |
373 /* | |
374 * Converts the opos[] array into a char array. | |
375 * In doing so this shrinks the data size by using a .. notation. | |
376 * No check is made that buf is large enough. It is recommended that buf is | |
377 * allocated to 5*len which covers the worst case (for sequences less that | |
378 * 9999 bases long). | |
379 * | |
380 * Note that on older systems sprintf may return the first argument rather | |
381 * than the number of characters written. | |
382 * For this reason we have to do the counting ourselves. | |
383 */ | |
384 char *opos2str(int2 *opos, int len, char *buf) { | |
385 int i, st, f, dir = 0; | |
386 char *r = buf, *rs = buf; | |
387 | |
388 f = opos[st = 0]; | |
389 for (i = 1; i < len; f=opos[i++]) { | |
390 if (dir == 0) | |
391 if (opos[i] == f+1) | |
392 dir=1; | |
393 else if (opos[i] == f-1) | |
394 dir=-1; | |
395 | |
396 if (dir && opos[i] != f + dir) { | |
397 if (st != i-1) | |
398 sprintf(buf, "%d..%d ", opos[st], opos[i-1]); | |
399 else | |
400 sprintf(buf, "%d ", opos[st]); | |
401 st = i; | |
402 dir = 0; | |
403 | |
404 buf += strlen(buf); | |
405 | |
406 } else if (dir == 0) { | |
407 sprintf(buf, "%d ", f); | |
408 | |
409 st = i; | |
410 buf += strlen(buf); | |
411 } | |
412 | |
413 if (buf - rs > 60) { | |
414 *buf++ = '\n'; | |
415 *buf = '\0'; | |
416 rs = buf - 6; | |
417 } | |
418 } | |
419 | |
420 if (st != i-1) | |
421 sprintf(buf, "%d..%d", opos[st], opos[i-1]); | |
422 else | |
423 sprintf(buf, "%d", opos[st]); | |
424 | |
425 return r; | |
426 } | |
427 | |
428 | |
429 | |
430 /* | |
431 * Expands from the character string .. notation to the opos[] array, up to | |
432 * a maximum of len elements in opos[]. | |
433 * | |
434 * Returns the length of the opos array. | |
435 */ | |
436 int str2opos(int2 *opos, int len, char *buf) { | |
437 /* int i, n1, n2, st, en, m, j = 0; */ | |
438 int i, j = 0, st, en; | |
439 char *cp; | |
440 | |
441 while (j < len && *buf) { | |
442 st = strtol(buf, &cp, 10); | |
443 if (buf == cp) { | |
444 buf++; | |
445 continue; | |
446 } | |
447 buf = cp; | |
448 if (buf[0] == '.' && buf[1] == '.') { | |
449 en = strtol(buf += 2, &cp, 10); | |
450 if (buf == cp) { | |
451 opos[j++] = st; | |
452 buf++; | |
453 continue; | |
454 } | |
455 buf = cp; | |
456 | |
457 if (en >= st) | |
458 for (i = st; i <= en && j < len; i++) | |
459 opos[j++] = i; | |
460 else | |
461 for (i = st; i >= en && j < len; i--) | |
462 opos[j++] = i; | |
463 } else { | |
464 opos[j++] = st; | |
465 } | |
466 } | |
467 | |
468 return j; | |
469 } | |
470 | |
471 | |
472 /* | |
473 * Converts the accuracy value string (AV) to the confidence array up to | |
474 * a maximum of len elements in conf[]. | |
475 * | |
476 * The AV string is of format: | |
477 * "x y z ..." where x, y and z are confidence values for the first three | |
478 * called bases. Or: | |
479 * "a,b,c,d e,f,g,h i,j,k,l ..." where the 4-tuples represent the four | |
480 * confidence values for each base. | |
481 * | |
482 * Returns: number of confidence values read, or -1 for error. | |
483 */ | |
484 int str2conf(int1 *conf, int len, char *buf) { | |
485 int ind = 0; | |
486 | |
487 while (*buf && ind < len) { | |
488 char *new_buf; | |
489 int val1; | |
490 | |
491 val1 = strtol(buf, &new_buf, 10); | |
492 if (new_buf == buf) | |
493 break; | |
494 | |
495 if (*new_buf == ',') { | |
496 fprintf(stderr, "4-tuple system is currently unsupported\n"); | |
497 return -1; | |
498 } | |
499 | |
500 conf[ind++] = val1; | |
501 buf = new_buf; | |
502 } | |
503 | |
504 return ind; | |
505 } | |
506 | |
507 | |
508 /* | |
509 * Converts the confidence array to the accuracy value string (AV). | |
510 * | |
511 * Note no memory overrun checks are performed on buf. It is recommended | |
512 * that it is allocated to 4*len (worst case of "255 " for each base) plus. | |
513 * a couple of terminating newline and null plus another byte per 15 values | |
514 * to allow for the 60-char line length. | |
515 * For ease, allocating to 5*len+2 is more than sufficient. | |
516 * | |
517 * Returns the buf argument. | |
518 */ | |
519 char *conf2str(int1 *conf, int len, char *buf) { | |
520 int i; | |
521 char *ret = buf, *rs = buf; | |
522 | |
523 for (i = 0; i < len; i++) { | |
524 sprintf(buf, "%d ", conf[i]); | |
525 buf += strlen(buf); | |
526 | |
527 if (buf - rs > 60) { | |
528 *buf++ = '\n'; | |
529 *buf = '\0'; | |
530 rs = buf - 6; | |
531 } | |
532 } | |
533 | |
534 return ret; | |
535 } | |
536 | |
537 /************************************************************* | |
538 * Main C interface routines | |
539 *************************************************************/ | |
540 | |
541 | |
542 /* | |
543 * Closes an experiment file (if open), but does not free it. | |
544 */ | |
545 void exp_close(Exp_info *e) { | |
546 if (e->fp) { | |
547 fclose(e->fp); | |
548 e->fp = NULL; | |
549 } | |
550 } | |
551 | |
552 | |
553 Exp_info *exp_read_info(char *file) | |
554 /* | |
555 * Read in an experiment file and return handle | |
556 */ | |
557 { | |
558 Exp_info *e; | |
559 FILE *fp; | |
560 | |
561 /* | |
562 * open for read | |
563 */ | |
564 if ((fp = fopen(file,"r"))==NULL) { | |
565 return NULL_Exp_info; | |
566 } | |
567 | |
568 e = exp_fread_info(fp); | |
569 fclose(fp); | |
570 | |
571 if (NULL_Exp_info == e) { | |
572 return NULL_Exp_info; | |
573 } | |
574 | |
575 /* | |
576 * reopen for appending | |
577 */ | |
578 e->fp = fopen(file,"a"); | |
579 | |
580 return e; | |
581 | |
582 } | |
583 | |
584 | |
585 /* | |
586 * Read in an experiment file and return handle | |
587 */ | |
588 Exp_info *exp_fread_info(FILE *fp) | |
589 { | |
590 Exp_info *e; | |
591 char line[EXP_FILE_LINE_LENGTH+1]; | |
592 char *aline; | |
593 int alloced_length = EXP_FILE_LINE_LENGTH+1; | |
594 int apos, len; | |
595 int last_entry = -1; | |
596 size_t entry_len = 0; | |
597 | |
598 e = exp_create_info(); | |
599 | |
600 | |
601 /* | |
602 * No longer has an effect due to mFILE already being loaded. Ifdef not | |
603 * triggered under mingw anyway. | |
604 */ | |
605 #ifdef _WIN32 | |
606 /* 6/1/99 johnt - need to ensure text mode to translate \r\n to \n */ | |
607 /* _setmode(fileno(fp),_O_TEXT); */ | |
608 mfascii(fp); | |
609 #endif | |
610 | |
611 /* | |
612 * open for read, set this temporarily in this function. Should be NULL | |
613 * when exiting as this isn't our file pointer to own, but the destroy | |
614 * function does attempt to automatically close it. | |
615 */ | |
616 e->fp = fp; | |
617 | |
618 if (NULL == (aline = (char *)xmalloc(alloced_length))) | |
619 return NULL; | |
620 | |
621 if (e != NULL_Exp_info) { | |
622 int at_end = 0; | |
623 | |
624 for(;;) { | |
625 char *c; | |
626 int entry; | |
627 | |
628 /* Read into aline, joining and allocating as necessary */ | |
629 apos = 0; | |
630 do { | |
631 if (fgets(line,EXP_FILE_LINE_LENGTH,e->fp) == NULL) { | |
632 at_end = 1; | |
633 break; | |
634 } | |
635 | |
636 len = strlen(line); | |
637 if (apos + len >= alloced_length) { | |
638 alloced_length *= 2; | |
639 if (NULL == (aline = (char *)xrealloc(aline, | |
640 alloced_length))) { | |
641 e->fp = NULL; | |
642 return NULL; | |
643 } | |
644 } | |
645 | |
646 strcpy(aline+apos, line); | |
647 apos += len; | |
648 } while (line[len-1] != '\n'); | |
649 | |
650 if (at_end) | |
651 break; | |
652 | |
653 /* | |
654 * zero terminate first argument | |
655 * set c to point to second argument | |
656 * | |
657 * FIXME: c should point to character 6 always. Indentation is | |
658 * important when considering continuation lines. | |
659 */ | |
660 for (c=aline;*c && !isspace(*c); c++) ; | |
661 if (*c) { | |
662 *c++ = '\0'; | |
663 for (;*c && isspace(*c); c++) ; | |
664 } | |
665 | |
666 entry = exp_get_feature_index(aline); | |
667 if (entry >= 0) { | |
668 /* | |
669 * Tag lines may be split over multiple lines. If we have no | |
670 * tag type then we append to the existing tag. | |
671 */ | |
672 if (entry == last_entry && | |
673 (int)(c-aline) >= 10/* continuation lines */ | |
674 && (entry == EFLT_TG || entry == EFLT_TC || | |
675 entry == EFLT_ON || entry == EFLT_AV || | |
676 entry == EFLT_NT || entry == EFLT_FT)) { | |
677 char *en; | |
678 size_t l1, l2; | |
679 | |
680 /* | |
681 * Extend our current line by the appropriate amount | |
682 */ | |
683 if( exp_check_eid_read(e,entry) ) | |
684 return NULL; | |
685 en = exp_get_entry(e,entry); | |
686 l1 = entry_len; | |
687 l2 = strlen(&aline[10]); | |
688 | |
689 if (NULL == (en = exp_get_entry(e, entry) = | |
690 (char *)xrealloc(en, l1 + l2 + 1))) { | |
691 e->fp = NULL; | |
692 return NULL; | |
693 } | |
694 | |
695 | |
696 /* | |
697 * Append the new line (without the \n char) | |
698 */ | |
699 en[l1] = '\n'; | |
700 aline[l2+9] = '\0'; | |
701 strcpy(&en[l1+1], &aline[10]); | |
702 | |
703 entry_len += l2; | |
704 } else { | |
705 /* | |
706 * Increment number of entries for line type entry | |
707 * This will force exp_get_entry() to return pointer to | |
708 * next free element in array | |
709 */ | |
710 (void)ArrayRef(e->entries[entry],e->Nentries[entry]++); | |
711 | |
712 if (entry == EFLT_SQ) | |
713 exp_get_entry(e,entry) = exp_read_sequence(e->fp); | |
714 else { | |
715 char *eoln = strchr(c,'\n'); | |
716 int i; | |
717 | |
718 if (eoln!=NULL) *eoln='\0'; | |
719 | |
720 if (entry == EFLT_LT) | |
721 for (i=3; isspace(c[i]) && i >= 0; c[i--]='\0'); | |
722 | |
723 exp_get_entry(e,entry) = (char *)strdup(c); | |
724 entry_len = strlen(c); | |
725 } | |
726 } | |
727 } | |
728 | |
729 last_entry = entry; | |
730 } | |
731 } | |
732 | |
733 e->fp = NULL; | |
734 xfree(aline); | |
735 | |
736 return e; | |
737 } | |
738 | |
739 static int exp_check_eid_read(Exp_info *e,int id) | |
740 /* | |
741 * Check these are a valid combination and that | |
742 * an entry exists for read | |
743 */ | |
744 { | |
745 return ( | |
746 e == NULL || | |
747 id < 0 || | |
748 id >= MAXIMUM_EFLTS || | |
749 e->Nentries[id] == 0 || | |
750 eflt_feature_ids[id][0]=='\0' | |
751 ); | |
752 } | |
753 | |
754 static int exp_check_eid_write(Exp_info *e,int id) | |
755 /* | |
756 * Check these are a valid combination and that | |
757 * an entry exists for write | |
758 */ | |
759 { | |
760 return (e == NULL || | |
761 id < 0 || | |
762 id >= MAXIMUM_EFLTS || | |
763 e->fp == NULL || | |
764 eflt_feature_ids[id][0]=='\0'); | |
765 } | |
766 | |
767 | |
768 | |
769 | |
770 | |
771 | |
772 int exp_get_int(Exp_info *e, int id, int *val) | |
773 /* | |
774 * Get the integer for entry id | |
775 * returns: | |
776 * 0 - success | |
777 * 1 - no entry | |
778 */ | |
779 { | |
780 if ( exp_check_eid_read(e,id) ) return 1; | |
781 *val = atoi(exp_get_entry(e,id)); | |
782 return 0; | |
783 } | |
784 | |
785 | |
786 int exp_get_rng(Exp_info *e, int id, int *from, int *to) | |
787 /* | |
788 * Get the integer pair for entry id | |
789 * returns: | |
790 * 0 - success | |
791 * 1 - no entry | |
792 */ | |
793 { | |
794 if ( exp_check_eid_read(e,id) ) return 1; | |
795 (void)exp_extract_range(exp_get_entry(e,id), from, to); | |
796 | |
797 return 0; | |
798 } | |
799 | |
800 | |
801 | |
802 int exp_get_str(Exp_info *e, int id, char *s, f_implicit s_l) | |
803 /* | |
804 * Get the string for entry id | |
805 * returns: | |
806 * 0 - success | |
807 * 1 - no entry | |
808 */ | |
809 { | |
810 if ( exp_check_eid_read(e,id) ) return 1; | |
811 strncpy(s,exp_get_entry(e,id),s_l); | |
812 | |
813 return 0; | |
814 } | |
815 | |
816 | |
817 static int exp_append_str(Exp_info *e, int id, char *s, int len) | |
818 /* | |
819 * Append the string to experiment file for entry id | |
820 * returns: | |
821 * 0 - success | |
822 * 1 - no update | |
823 */ | |
824 { | |
825 (void)ArrayRef(e->entries[id],e->Nentries[id]++); | |
826 exp_get_entry(e,id) = (char *)xmalloc(len+1); | |
827 strncpy(exp_get_entry(e,id), s, len); | |
828 exp_get_entry(e,id)[len] = '\0'; | |
829 | |
830 if ( id == EFLT_SQ ) | |
831 return exp_print_seq(e->fp,e,id,e->Nentries[id]-1); | |
832 else if (id == EFLT_TG || id == EFLT_TC || | |
833 id == EFLT_ON || id == EFLT_AV || | |
834 id == EFLT_NT || id == EFLT_FT) | |
835 return exp_print_mline(e->fp,e,id,e->Nentries[id]-1); | |
836 else | |
837 return exp_print_line(e->fp,e,id,e->Nentries[id]-1); | |
838 } | |
839 | |
840 | |
841 int exp_put_int(Exp_info *e, int id, int *val) | |
842 /* | |
843 * Append the integer for entry id to the experiment file | |
844 * returns: | |
845 * 0 - success | |
846 * 1 - no update | |
847 */ | |
848 { | |
849 char buf[EXP_FILE_LINE_LENGTH]; | |
850 if ( exp_check_eid_write(e,id) ) return 1; | |
851 sprintf(buf,"%d",*val); | |
852 return exp_append_str(e,id,buf,strlen(buf)); | |
853 } | |
854 | |
855 | |
856 int exp_put_rng(Exp_info *e, int id, int *from, int *to) | |
857 /* | |
858 * Append the integer pair for entry id to the experiment file | |
859 * returns: | |
860 * 0 - success | |
861 * 1 - no update | |
862 */ | |
863 { | |
864 char buf[EXP_FILE_LINE_LENGTH]; | |
865 if ( exp_check_eid_write(e,id) ) return 1; | |
866 | |
867 (void )exp_create_range(buf, *from, *to); | |
868 | |
869 return exp_append_str(e,id,buf,strlen(buf)); | |
870 } | |
871 | |
872 | |
873 | |
874 int exp_put_str(Exp_info *e, int id, char *s, f_implicit s_l) | |
875 /* | |
876 * Append the string for entry id to the experiment file | |
877 * returns: | |
878 * 0 - success | |
879 * 1 - no update | |
880 */ | |
881 { | |
882 if ( exp_check_eid_write(e,id) ) return 1; | |
883 return exp_append_str(e,id,s,s_l); | |
884 } | |
885 | |
886 | |
887 /************************************************************* | |
888 * FORTRAN INTERFACE | |
889 *************************************************************/ | |
890 | |
891 | |
892 | |
893 static int init_done = 0; | |
894 static int NHandles = 0; | |
895 static Exp_info **Handles = NULL; | |
896 | |
897 static int initialise(void) | |
898 { | |
899 int i; | |
900 | |
901 if (init_done) return 0; | |
902 init_done++; | |
903 | |
904 NHandles = FOPEN_MAX; | |
905 | |
906 if ( (Handles = (Exp_info **)xmalloc(sizeof(Exp_info *) * NHandles)) == NULL) { | |
907 NHandles = 0; | |
908 return 1; | |
909 } | |
910 | |
911 for (i=0; i<NHandles; i++) Handles[i] = NULL; | |
912 | |
913 return 0; | |
914 } | |
915 | |
916 | |
917 static int get_free_handle(void) | |
918 /* | |
919 * find a free entry in the Exp array | |
920 * returns -1 if there is none | |
921 */ | |
922 { | |
923 int i; | |
924 | |
925 (void) initialise(); | |
926 | |
927 if (!NHandles) return -1; /* no slots! */ | |
928 for (i=0; i<NHandles && Handles[i]!=NULL; i++) ; | |
929 return (i==NHandles)?-1:i; | |
930 } | |
931 | |
932 | |
933 static int check_handle(f_int *handle) | |
934 { | |
935 return (handle == NULL || | |
936 (int) (*handle) <= 0 || | |
937 (int) (*handle) > NHandles); | |
938 } | |
939 | |
940 | |
941 | |
942 f_int expopn_(char *fn, f_implicit fn_l) | |
943 /* | |
944 * FORTRAN interface to exp_open_file() | |
945 */ | |
946 { | |
947 char cfn[1025]; | |
948 int handle; | |
949 | |
950 if ( (handle = get_free_handle()) >= 0 ) { | |
951 f2cstr(fn,fn_l,cfn,1024); | |
952 Handles[handle] = exp_read_info(cfn); | |
953 } | |
954 | |
955 return (f_int) (handle+1); | |
956 } | |
957 | |
958 | |
959 | |
960 f_proc_ret expkil_(f_int *handle) | |
961 /* | |
962 * FORTRAN interface to exp_destroy_info | |
963 */ | |
964 { | |
965 Exp_info *e; | |
966 if ( check_handle(handle) ) f_proc_return(); | |
967 e = (Exp_info *) Handles[(int)(*handle)-1]; | |
968 | |
969 exp_destroy_info(e); | |
970 | |
971 Handles[(int)(*handle)-1] = NULL; | |
972 *handle = 0; | |
973 | |
974 f_proc_return(); | |
975 } | |
976 | |
977 f_int expri_(f_int *handle, f_int *id, f_int *val) | |
978 /* | |
979 * FORTRAN interface to exp_get_int | |
980 */ | |
981 { | |
982 Exp_info *e; | |
983 if ( check_handle(handle) ) return 1; | |
984 e = (Exp_info *) Handles[(int)(*handle)-1]; | |
985 | |
986 return exp_get_int(e, (int)*id, (int *)val); | |
987 } | |
988 | |
989 | |
990 f_int exprr_(f_int *handle, f_int *id, f_int *from, f_int *to) | |
991 /* | |
992 * FORTRAN interface to exp_get_rng | |
993 */ | |
994 { | |
995 Exp_info *e; | |
996 if ( check_handle(handle) ) return 1; | |
997 e = (Exp_info *) Handles[(int)(*handle)-1]; | |
998 | |
999 return exp_get_rng(e,(int)*id,(int *)from,(int *)to); | |
1000 | |
1001 } | |
1002 | |
1003 /* ARGSUSED */ | |
1004 f_int exprsa_(f_int *handle, f_int *id, char *s, f_int *max_len, f_implicit s_l) | |
1005 /* | |
1006 * FORTRAN interface to exp_get_str workalike | |
1007 * NOTE: for use with FORTRAN CHARACTER arrays instead CHARACTER strings | |
1008 */ | |
1009 { | |
1010 Exp_info *e; | |
1011 if ( check_handle(handle) ) return 1; | |
1012 e = (Exp_info *) Handles[(int)(*handle)-1]; | |
1013 | |
1014 if ( exp_check_eid_read(e,*id) ) return 1; | |
1015 c2fstr(exp_get_entry(e,*id),(int)*max_len,s,(int)*max_len); | |
1016 return 0; | |
1017 } | |
1018 | |
1019 | |
1020 f_int exprs_(f_int *handle, f_int *id, char *s, f_implicit s_l) | |
1021 /* | |
1022 * FORTRAN interface to exp_get_str workalike | |
1023 * NOTE: for use with FORTRAN CHARACTER strings instead CHARACTER arrays | |
1024 */ | |
1025 { | |
1026 Exp_info *e; | |
1027 if ( check_handle(handle) ) return 1; | |
1028 e = (Exp_info *) Handles[(int)(*handle)-1]; | |
1029 | |
1030 if ( exp_check_eid_read(e,*id) ) return 1; | |
1031 c2fstr(exp_get_entry(e,*id),s_l,s,s_l); | |
1032 return 0; | |
1033 } | |
1034 | |
1035 | |
1036 f_int expwi_(f_int *handle, f_int *id, f_int *val) | |
1037 /* | |
1038 * FORTRAN interface to exp_put_int | |
1039 */ | |
1040 { | |
1041 Exp_info *e; | |
1042 if ( check_handle(handle) ) return 1; | |
1043 e = (Exp_info *) Handles[(int)(*handle)-1]; | |
1044 | |
1045 return exp_put_int(e, (int)*id, (int *)val); | |
1046 } | |
1047 | |
1048 | |
1049 f_int expwr_(f_int *handle, f_int *id, f_int *from, f_int *to) | |
1050 /* | |
1051 * FORTRAN interface to exp_put_rng | |
1052 */ | |
1053 { | |
1054 Exp_info *e; | |
1055 if ( check_handle(handle) ) return 1; | |
1056 e = (Exp_info *) Handles[(int)(*handle)-1]; | |
1057 | |
1058 return exp_put_rng(e, (int)*id, (int *)from, (int *)to); | |
1059 } | |
1060 | |
1061 | |
1062 /* ARGSUSED */ | |
1063 f_int expwsa_(f_int *handle, f_int *id, char *s, f_int *max_len, f_implicit s_l) | |
1064 /* | |
1065 * FORTRAN interface to exp_put_str workalike | |
1066 * NOTE: for use with FORTRAN CHARACTER arrays instead CHARACTER strings | |
1067 */ | |
1068 { | |
1069 Exp_info *e; | |
1070 char buf[EXP_FILE_LINE_LENGTH]; | |
1071 if ( check_handle(handle) ) return 1; | |
1072 e = (Exp_info *) Handles[(int)(*handle)-1]; | |
1073 | |
1074 | |
1075 if ( exp_check_eid_write(e,*id) ) return 1; | |
1076 /* don't allow multi-line entries to be written */ | |
1077 if (*id == EFLT_SQ ) return 1; | |
1078 f2cstr(s,(int)*max_len,buf,sizeof(buf)); | |
1079 return exp_append_str(e,*id,buf,strlen(buf)); | |
1080 | |
1081 } | |
1082 | |
1083 f_int expws_(f_int *handle, f_int *id, char *s, f_implicit s_l) | |
1084 /* | |
1085 * FORTRAN interface to exp_put_str workalike | |
1086 * NOTE: for use with FORTRAN CHARACTER strings instead CHARACTER arrays | |
1087 */ | |
1088 { | |
1089 char buf[EXP_FILE_LINE_LENGTH]; | |
1090 Exp_info *e; | |
1091 if ( check_handle(handle) ) return 1; | |
1092 e = (Exp_info *) Handles[(int)(*handle)-1]; | |
1093 | |
1094 | |
1095 if ( exp_check_eid_write(e,*id) ) return 1; | |
1096 /* don't allow multi-line entries to be written */ | |
1097 if (*id == EFLT_SQ ) return 1; | |
1098 f2cstr(s,s_l,buf,sizeof(buf)); | |
1099 return exp_append_str(e,*id,buf,s_l); | |
1100 } | |
1101 | |
1102 /* | |
1103 * FORTRAN interface to exp_create_range() | |
1104 */ | |
1105 void expcr_(char *str, f_int *start, f_int *end, f_implicit str_l) { | |
1106 exp_create_range(str, *start, *end); | |
1107 c2fstr(str, str_l, str, str_l); | |
1108 | |
1109 f_proc_return(); | |
1110 } | |
1111 | |
1112 /* | |
1113 * FORTRAN interface to exp_extract_range() | |
1114 */ | |
1115 /* ARGSUSED */ | |
1116 f_int exper_(char *str, f_int *start, f_int *end, f_implicit str_l) { | |
1117 return exp_extract_range(str, start, end); | |
1118 } | |
1119 | |
1120 | |
1121 | |
1122 | |
1123 /************************************************************* | |
1124 * Go for it! | |
1125 *************************************************************/ | |
1126 | |
1127 static void print_line(FILE *fp, Exp_info *e, int eflt, int all) | |
1128 { | |
1129 if (all) { | |
1130 int i; | |
1131 for(i=0;i<e->Nentries[eflt];i++) exp_print_line(fp,e,eflt,i); | |
1132 } else if (e->Nentries[eflt] > 0) { | |
1133 exp_print_line(fp,e,eflt,e->Nentries[eflt]-1); | |
1134 } | |
1135 } | |
1136 | |
1137 | |
1138 static void print_mline(FILE *fp, Exp_info *e, int eflt, int all) | |
1139 { | |
1140 if (all) { | |
1141 int i; | |
1142 for(i=0;i<e->Nentries[eflt];i++) exp_print_mline(fp,e,eflt,i); | |
1143 } else if (e->Nentries[eflt] > 0) { | |
1144 exp_print_mline(fp,e,eflt,e->Nentries[eflt]-1); | |
1145 } | |
1146 } | |
1147 | |
1148 | |
1149 | |
1150 static void print_seq(FILE *fp, Exp_info *e, int eflt) | |
1151 { | |
1152 if (e->Nentries[eflt] > 0) | |
1153 exp_print_seq(fp,e,eflt,e->Nentries[eflt]-1); | |
1154 } | |
1155 | |
1156 | |
1157 | |
1158 | |
1159 void exp_print_file(FILE *fp, Exp_info *e) | |
1160 { | |
1161 print_line(fp,e,EFLT_ID, 0); | |
1162 print_line(fp,e,EFLT_AC, 0); | |
1163 print_line(fp,e,EFLT_EN, 0); | |
1164 | |
1165 print_line(fp,e,EFLT_CC, 1); | |
1166 print_line(fp,e,EFLT_EX, 1); | |
1167 print_line(fp,e,EFLT_PS, 1); | |
1168 | |
1169 print_line(fp,e,EFLT_LN, 0); | |
1170 print_line(fp,e,EFLT_LT, 0); | |
1171 | |
1172 print_line(fp,e,EFLT_CF, 0); | |
1173 print_line(fp,e,EFLT_CV, 0); | |
1174 print_line(fp,e,EFLT_CS, 0); | |
1175 print_line(fp,e,EFLT_CL, 0); | |
1176 print_line(fp,e,EFLT_CR, 0); | |
1177 | |
1178 print_line(fp,e,EFLT_SF, 0); | |
1179 print_line(fp,e,EFLT_SV, 0); | |
1180 print_line(fp,e,EFLT_SI, 0); | |
1181 print_line(fp,e,EFLT_SC, 0); | |
1182 print_line(fp,e,EFLT_SP, 0); | |
1183 print_line(fp,e,EFLT_PD, 0); | |
1184 print_line(fp,e,EFLT_FM, 0); | |
1185 print_line(fp,e,EFLT_SL, 0); | |
1186 print_line(fp,e,EFLT_SR, 0); | |
1187 | |
1188 print_line(fp,e,EFLT_QL, 0); | |
1189 print_line(fp,e,EFLT_QR, 0); | |
1190 | |
1191 print_mline(fp,e,EFLT_TG,1); | |
1192 print_mline(fp,e,EFLT_TC,1); | |
1193 print_mline(fp,e,EFLT_NT,1); | |
1194 | |
1195 print_line(fp,e,EFLT_CN, 0); | |
1196 print_line(fp,e,EFLT_TN, 0); | |
1197 print_line(fp,e,EFLT_PN, 0); | |
1198 print_line(fp,e,EFLT_PR, 0); | |
1199 print_line(fp,e,EFLT_LI, 0); | |
1200 print_line(fp,e,EFLT_LE, 0); | |
1201 print_line(fp,e,EFLT_CH, 0); | |
1202 | |
1203 print_mline(fp,e,EFLT_ON,0); | |
1204 print_line(fp,e,EFLT_AQ, 0); | |
1205 print_mline(fp,e,EFLT_AV,0); | |
1206 | |
1207 print_line(fp,e,EFLT_DR, 0); | |
1208 print_line(fp,e,EFLT_SE, 0); | |
1209 print_line(fp,e,EFLT_PC, 0); | |
1210 print_line(fp,e,EFLT_AP, 0); | |
1211 print_line(fp,e,EFLT_ST, 0); | |
1212 | |
1213 print_line(fp,e,EFLT_DT, 0); | |
1214 print_line(fp,e,EFLT_MC, 0); | |
1215 print_line(fp,e,EFLT_MN, 0); | |
1216 print_line(fp,e,EFLT_MT, 0); | |
1217 print_line(fp,e,EFLT_OP, 1); | |
1218 print_line(fp,e,EFLT_BC, 0); | |
1219 print_line(fp,e,EFLT_SS, 0); | |
1220 | |
1221 print_line(fp,e,EFLT_WT, 0); | |
1222 print_line(fp,e,EFLT_WL, 0); | |
1223 print_line(fp,e,EFLT_WR, 0); | |
1224 | |
1225 print_mline(fp,e,EFLT_FT,1); | |
1226 | |
1227 print_seq (fp,e,EFLT_SQ); | |
1228 } | |
1229 | |
1230 | |
1231 /* | |
1232 * Allocate an set a new experiment file entry | |
1233 */ | |
1234 char *exp_set_entry(Exp_info *e, int eflt, char *str) { | |
1235 char *s; | |
1236 size_t l; | |
1237 | |
1238 if (NULL == ArrayRef(e->entries[eflt], e->Nentries[eflt])) | |
1239 return NULL; | |
1240 else | |
1241 e->Nentries[eflt]++; | |
1242 | |
1243 l = strlen(str); | |
1244 if (NULL == (s = exp_get_entry(e, eflt) = (char *)xmalloc(l+1))) { | |
1245 e->Nentries[eflt]--; | |
1246 return NULL; | |
1247 } | |
1248 strcpy(s, str); | |
1249 | |
1250 return s; | |
1251 } |