~ubuntu-branches/ubuntu/precise/acedb/precise

« back to all changes in this revision

Viewing changes to wstaden/expFileIO.c

  • Committer: Bazaar Package Importer
  • Author(s): Steffen Moeller
  • Date: 2010-07-11 06:27:12 UTC
  • Revision ID: james.westby@ubuntu.com-20100711062712-f1mtli96gavo7mk4
Tags: upstream-4.9.39
ImportĀ upstreamĀ versionĀ 4.9.39

Show diffs side-by-side

added added

removed removed

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