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

« back to all changes in this revision

Viewing changes to w7/gmapconvert.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
/*  File: gmapconvert.c
 
2
 *  Author: Simon Kelley (srk@sanger.ac.uk)
 
3
 *  Copyright (C) J Thierry-Mieg and R Durbin, 1991
 
4
 * -------------------------------------------------------------------
 
5
 * Acedb is free software; you can redistribute it and/or
 
6
 * modify it under the terms of the GNU General Public License
 
7
 * as published by the Free Software Foundation; either version 2
 
8
 * of the License, or (at your option) any later version.
 
9
 * 
 
10
 * This program is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 * GNU General Public License for more details.
 
14
 * 
 
15
 * You should have received a copy of the GNU General Public License
 
16
 * along with this program; if not, write to the Free Software
 
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
18
 * or see the on-line version at http://www.gnu.org/copyleft/gpl.txt
 
19
 * -------------------------------------------------------------------
 
20
 * This file is part of the ACEDB genome database package, written by
 
21
 *      Richard Durbin (MRC LMB, UK) rd@mrc-lmb.cam.ac.uk, and
 
22
 *      Jean Thierry-Mieg (CRBM du CNRS, France) mieg@kaa.cnrs-mop.fr
 
23
 *
 
24
 * Description: assorted utility functions for extracting data from
 
25
 * Map objects  
 
26
 * Exported functions:
 
27
 *     str2tag
 
28
 *     gMapNeighbours
 
29
 *     gMapPositive
 
30
 *     gMapNegative
 
31
 *     gMapMultiPt
 
32
 *     gMap2Pt
 
33
 *     gMapGetMultiData
 
34
 *     gMapGet2PtData
 
35
 *     getPos
 
36
 *     setTestPos
 
37
 *     gMapGetMapObject
 
38
 *     gMapSymbols
 
39
 *     gMapKeyOnTag
 
40
 *     
 
41
 * HISTORY:
 
42
 * Last edited: Mar 28 15:58 2007 (edgrif)
 
43
 *-------------------------------------------------------------------
 
44
 */
 
45
 
 
46
/* $Id: gmapconvert.c,v 1.39 2007/03/29 15:08:17 edgrif Exp $ */
 
47
 
 
48
#include "acedb.h"
 
49
#include "aceio.h"
 
50
#include "pick.h"
 
51
#include "gmap.h"
 
52
 
 
53
 
 
54
static BOOL tagTypesMatch(KEY tag_1, KEY tag_2) ;
 
55
 
 
56
 
 
57
 
 
58
KEY gMapCacheKey(KEY map, char *suffix)
 
59
{ char buf[100];
 
60
  KEY ret;
 
61
  OBJ obj = bsCreate(map);
 
62
  BOOL noCache = FALSE;
 
63
 
 
64
  if (obj)
 
65
    { noCache = bsFindTag(obj, str2tag("No_cache"));
 
66
      bsDestroy(obj);
 
67
    }
 
68
  if (noCache)
 
69
    return 0;
 
70
  strcpy(buf, name(map));
 
71
  strcat(buf, ".");
 
72
  strcat(buf, suffix);
 
73
  if (lexword2key(buf, &ret, _VgMap))
 
74
    return ret;
 
75
  else
 
76
    return 0;
 
77
}
 
78
 
 
79
void gMapCacheStore(KEY map, char *suffix, Array a, char *format)
 
80
{ char buf[100];
 
81
  KEY key;
 
82
  strcpy(buf, name(map));
 
83
  strcat(buf, ".");
 
84
  strcat(buf, suffix);
 
85
  lexaddkey(buf, &key, _VgMap);
 
86
  arrayStore(key, a, format);
 
87
}
 
88
 
 
89
void gMapCacheKill(KEY map)
 
90
{ char buf[100];
 
91
  KEYSET kset;
 
92
  int i;
 
93
 
 
94
  strcpy(buf, "FIND gMap ");
 
95
  strcat(buf, name(map));
 
96
  strcat(buf, ".*");
 
97
  kset = query(0, buf);
 
98
  for (i = 0 ; i < keySetMax(kset); i++)
 
99
    arrayKill(keySet(kset, i));
 
100
}
 
101
 
 
102
BOOL gMapIsCache(KEY map)
 
103
{
 
104
  KEY poscache = gMapCacheKey(map, "main");
 
105
  
 
106
  if (!poscache)
 
107
    return FALSE;
 
108
  
 
109
  if (iskey(poscache) != 2)
 
110
    return FALSE;
 
111
  
 
112
  return TRUE;
 
113
}
 
114
 
 
115
 
 
116
BOOL gMapNeighbours(MAPCONTROL map, KEYSET *keyset, KEY key)
 
117
{ KEYSET a;
 
118
  int i, j;
 
119
 
 
120
  *keyset = keySetReCreate(*keyset);
 
121
 
 
122
  a = bsKeySet(key);
 
123
  if (!a) return FALSE;
 
124
 
 
125
  for(i=0, j=0 ; i<keySetMax(a) ; i++)
 
126
    if (class(keySet(a,i)))
 
127
      keySet(*keyset,j++) = keySet(a,i) ;
 
128
  keySetDestroy(a) ;
 
129
 
 
130
  return keySetMax(*keyset) != 0;
 
131
  
 
132
 
 
133
}
 
134
 
 
135
static BOOL gMapContainment(int level, MAPCONTROL map, KEYSET *ks, 
 
136
                            KEY key, KEY senseTag)
 
137
/* senseTag is _Positive or _Negative */
 
138
{ KEY mapk = map->key;
 
139
  OBJ obj, comp;
 
140
  KEY k, mo1, mo2;
 
141
  int typeOf1, typeOf2, i;
 
142
  Array loci = arrayCreate(50, BSunit);
 
143
 
 
144
        /* get info in object */
 
145
  if ((obj = bsCreate(key)))
 
146
    { if (bsGetKey(obj, str2tag("More_data"), &k))
 
147
        do 
 
148
          { if (level>100)
 
149
              messerror("Have chased 100 levels of More_data and got to %s, "
 
150
                        "is there a loop?", name(k));
 
151
            else
 
152
              gMapContainment(level+1, map, ks, k, senseTag);
 
153
          } 
 
154
        while (bsGetKey(obj, _bsDown, &k));
 
155
  
 
156
    }
 
157
      
 
158
  if (bsFindTag(obj, senseTag) && bsFlatten(obj, 2, loci))
 
159
    for (i = 1; i<arrayMax(loci); i+= 2)
 
160
      { k = arr(loci, i, BSunit).k;
 
161
        if (k)
 
162
          keySet(*ks, keySetMax(*ks)) = k;
 
163
      }
 
164
 
 
165
        /* get info in Pos_neg_data */
 
166
  if (bsGetKey(obj, str2tag("Pos_neg_data"), &k))
 
167
    do 
 
168
      {
 
169
        comp = bsCreate(k);
 
170
        if (!bsFindTag(comp, senseTag))
 
171
          { bsDestroy(comp);
 
172
            continue;
 
173
          }
 
174
        
 
175
        if (bsFindTag(comp, str2tag("Item_1")) &&
 
176
            bsGetKeyTags(comp, _bsRight, &mo1) &&
 
177
            bsGetKey(comp, _bsRight, &mo1))
 
178
          typeOf1 = gMapGetMapObject(mo1, mapk, 0, 20, 0, 0, 0, 0);
 
179
        if (bsFindTag(comp, str2tag("Item_2")) &&
 
180
            bsGetKeyTags(comp, _bsRight, &mo2) &&
 
181
            bsGetKey(comp, _bsRight, &mo2))
 
182
          typeOf2 = gMapGetMapObject(mo2, mapk, 0, 20, 0, 0, 0, 0);
 
183
        bsDestroy(comp);
 
184
        
 
185
        if (((typeOf1&FLAG_ANY_INTERVAL) && (typeOf2&FLAG_ANY_LOCUS)) ||
 
186
            ((typeOf2&FLAG_ANY_INTERVAL) && (typeOf1&FLAG_ANY_LOCUS)))
 
187
          {
 
188
            if (mo1 == key)
 
189
              keySet(*ks, keySetMax(*ks)) = mo2;
 
190
            
 
191
            if (mo2 == key)
 
192
              keySet(*ks, keySetMax(*ks)) = mo1;
 
193
          }
 
194
      }
 
195
    while (bsGetKey(obj, _bsDown, &k));
 
196
  
 
197
  
 
198
  keySetSort(*ks);
 
199
  bsDestroy(obj);
 
200
  arrayDestroy(loci);
 
201
  return keySetMax(*ks) != 0;
 
202
}
 
203
 
 
204
BOOL gMapPositive(MAPCONTROL map, KEYSET *ks, KEY key)
 
205
{ *ks = keySetReCreate(*ks);
 
206
  return gMapContainment(0, map, ks, key, str2tag("Positive"));
 
207
}
 
208
 
 
209
BOOL gMapNegative(MAPCONTROL map, KEYSET *ks, KEY key)
 
210
{ *ks = keySetReCreate(*ks);
 
211
  return gMapContainment(0, map, ks, key, str2tag("Negative"));
 
212
}
 
213
 
 
214
BOOL gMapMultiPt(MAPCONTROL map, KEYSET *ks, KEY key)
 
215
{
 
216
  OBJ obj ;
 
217
  KEY k ;
 
218
  
 
219
  *ks = keySetReCreate(*ks) ;
 
220
  if ((obj = bsCreate (key)))
 
221
    { if (bsGetKey (obj, _Multi_point, &k)) do
 
222
        keySet (*ks, keySetMax(*ks)) = k ;
 
223
      while (bsGetKey (obj, _bsDown, &k)) ;
 
224
      bsDestroy (obj) ;
 
225
      keySetSort(*ks);
 
226
    }
 
227
 
 
228
  return keySetMax(*ks) != 0;
 
229
}
 
230
 
 
231
BOOL gMap2Pt(MAPCONTROL map, KEYSET *ks, KEY key)
 
232
{
 
233
  OBJ obj ;
 
234
  KEY k ;
 
235
  
 
236
  *ks = keySetReCreate(*ks) ;
 
237
  if ((obj = bsCreate (key)))
 
238
    { if (bsGetKey (obj, _2_point, &k)) do
 
239
        keySet (*ks, keySetMax(*ks)) = k ;
 
240
      while (bsGetKey (obj, _bsDown, &k)) ;
 
241
      bsDestroy (obj) ;
 
242
      keySetSort(*ks);
 
243
    }
 
244
 
 
245
  return keySetMax(*ks) != 0;
 
246
}
 
247
 
 
248
static void addMultiData (OBJ obj, Array counts, Array loci)
 
249
{
 
250
  int i, count ;
 
251
  KEY locus, tag ;
 
252
  static BSMARK mark ;
 
253
 
 
254
  mark = bsMark (obj, mark) ;
 
255
 
 
256
  for (i = 0 ; ; ++i)
 
257
    { bsPushObj(obj);
 
258
      if (!bsGetKeyTags(obj, _bsRight, &tag) ||
 
259
          !bsGetKey (obj, _bsRight, &locus))
 
260
        { messerror ("No terminating locus in multi results") ;
 
261
          goto done ;
 
262
        }
 
263
      if (i >= arrayMax(loci))
 
264
        array (loci, i, KEY) = locus ;
 
265
      else if (locus != array(loci,i,KEY))
 
266
        { messerror ("Mismatching locus %s in multi results", 
 
267
                     name(locus)) ;
 
268
          goto done ;
 
269
        }
 
270
      if (!bsGetData (obj, _bsRight, _Int, &count))
 
271
        goto done ;
 
272
      if (i >= arrayMax(counts))
 
273
        array(counts,i,int) = count ;
 
274
      else
 
275
        array(counts,i,int) += count ;
 
276
    }
 
277
 
 
278
 done:
 
279
  bsGoto (obj, mark) ;
 
280
}
 
281
 
 
282
 
 
283
BOOL gMapGetMultiPtData(MAPCONTROL map, 
 
284
                        KEY multi, 
 
285
                        STORE_HANDLE handle, 
 
286
                        MULTIPTDATA *ret)
 
287
{ Array counts, loci;
 
288
  float y, min, max;
 
289
  OBJ obj;
 
290
  MULTIPTDATA data;
 
291
  int i;
 
292
  
 
293
  if (!(obj = bsCreate (multi)))
 
294
    return FALSE;
 
295
  
 
296
  counts = arrayHandleCreate(20, int, handle);
 
297
  loci = arrayHandleCreate(20, KEY, handle);
 
298
  
 
299
  if (bsFindTag (obj, _Combined))
 
300
    addMultiData (obj, counts, loci) ;
 
301
  else 
 
302
    { if (bsFindTag (obj, _A_non_B))
 
303
        addMultiData (obj, counts, loci) ;
 
304
      if (bsFindTag (obj, _B_non_A))
 
305
        addMultiData (obj, counts, loci) ;
 
306
    }
 
307
 
 
308
  bsDestroy (obj);
 
309
 
 
310
  if (arrayMax(loci) <=2 && iskey(multi) > 1)  /* i.e. not just a name */
 
311
    {
 
312
      arrayDestroy(counts);
 
313
      arrayDestroy(loci);
 
314
      return FALSE;
 
315
    }
 
316
  
 
317
  min = 1000000 ; max = -1000000 ;
 
318
  for (i = 0 ; i < arrayMax(loci) ; ++i)
 
319
    if (getPos (map, arr(loci,i,KEY), &y))
 
320
      { if (y < min) min = y ;
 
321
        if (y > max) max = y ;
 
322
      }
 
323
 
 
324
  if (min > max)
 
325
    { arrayDestroy(counts);
 
326
      arrayDestroy(loci);
 
327
      return FALSE;
 
328
    }
 
329
 
 
330
  data = (MULTIPTDATA)handleAlloc(0, handle, sizeof(struct MultiPtData));
 
331
  data->counts = counts;
 
332
  data->loci = loci;
 
333
  data->min = min;
 
334
  data->max = max;
 
335
  *ret = data;
 
336
  return TRUE;
 
337
}
 
338
 
 
339
 
 
340
 
 
341
BOOL gMapGet2PtData(MAPCONTROL map, KEY key, STORE_HANDLE handle, TWOPTDATA *ret) 
 
342
{
 
343
  BOOL result = FALSE ;
 
344
  OBJ obj;
 
345
  KEY type_tag_1, type_tag_2 ;
 
346
  KEY type;
 
347
  TWOPTDATA data;
 
348
  BOOL barf;
 
349
  int *p;
 
350
  int i;
 
351
  
 
352
  obj = bsCreate(key);
 
353
  if (!obj)
 
354
    return result ; 
 
355
 
 
356
 
 
357
  /* Need two matching tags to give the two points. */
 
358
  if (!bsGetKeyTags(obj, str2tag("Point_1"), &type_tag_1) || !bsGetKeyTags(obj, str2tag("Point_2"), &type_tag_2)
 
359
      || !tagTypesMatch(type_tag_1, type_tag_2))
 
360
    {
 
361
      return FALSE ;
 
362
    }
 
363
  else
 
364
    {
 
365
      bsGoto(obj, 0) ;                                      /* Pop back up to root for later locations... */
 
366
    }
 
367
 
 
368
  data = (TWOPTDATA)handleAlloc(0, handle, sizeof(struct TwoPtData));
 
369
 
 
370
  /* Now get the position data. */
 
371
  if ((!bsGetKey(obj, type_tag_1, &data->loc1) || !bsGetKey(obj, type_tag_1, &data->loc2))
 
372
      || (!getPos(map, data->loc1, &data->y1) || !getPos(map, data->loc2, &data->y2)))
 
373
    {
 
374
      result = FALSE ;
 
375
      bsDestroy(obj);
 
376
      messfree(data);
 
377
      return result ;
 
378
    }
 
379
 
 
380
  if (!bsGetKeyTags(obj, _Calculation, &type))
 
381
    {
 
382
      data->type = 0;
 
383
      if (!bsGetData(obj, _Distance, _Float, &data->distance))
 
384
        data->distance = 0;
 
385
      if (!bsGetData(obj, _Error, _Float, &data->error))
 
386
        data->error = 0;
 
387
    }
 
388
  else
 
389
    {
 
390
      p = &data->n1;
 
391
      for (i=0; bsGetData(obj, _bsRight, _Int, p) && i < 4 ; p++, i++) ;
 
392
      data->count = i;
 
393
      data->type = type;
 
394
      
 
395
      barf = FALSE;
 
396
 
 
397
      if ((type == _Full ||             /* WT X Y XY */
 
398
           type == _Backcross ||        /* WT X Y XY */
 
399
           type == _Sex_full) &&        /* WT X Y XY */
 
400
          i != 4)
 
401
        barf = TRUE;
 
402
 
 
403
      if ((type == _Recs_all ||         /* X Y ALL */
 
404
           type == _Tetrad) &&          /* PD NPD TT */
 
405
          i != 3)
 
406
        barf = TRUE;
 
407
 
 
408
      if ((type == _One_recombinant ||  /* WT X */
 
409
           type == _Selected ||         /* X XY */
 
410
           type == _One_all ||          /* X ALL */
 
411
           type == _One_let ||          /* X ALL */
 
412
           type == _Tested ||           /* H X */
 
413
           type == _Selected_trans ||   /* X XY */
 
414
           type == _Back_one ||         /* WT X */
 
415
           type == _Sex_one ||          /* WT X */
 
416
           type == _Sex_cis ||          /* X ALL */
 
417
           type == _Dom_one ||          /* WT nonWT */
 
418
           type == _Dom_selected ||     /* WT X */
 
419
           type == _Dom_semi ||         /* XD ALL */
 
420
           type == _Dom_let ||          /* WT ALL */
 
421
           type == _Direct ||           /* R T */
 
422
           type == _Complex_mixed ||    /* X ALL */
 
423
           type == _Lethal_tested ||    /* N WT */
 
424
           type == _Centromere_segregation) && /* 1st 2nd */
 
425
          i != 2)
 
426
        barf = TRUE;
 
427
 
 
428
      if (barf)
 
429
        { messerror("Wrong number of data (%d) for 2 point calculation %s",
 
430
                    i, name(type));
 
431
          messfree(data);
 
432
          bsDestroy(obj);
 
433
          return FALSE;
 
434
        }
 
435
 
 
436
    }  
 
437
 
 
438
  bsDestroy(obj);
 
439
  *ret = data;
 
440
  return TRUE;
 
441
  
 
442
}
 
443
 
 
444
/* This is a utility function which returns the map position of any
 
445
   locus-like object on the map. As side effects, it is responsible
 
446
   for setting the values of map->min, map->max etc and look->orderedLoci,
 
447
   which is a keyset of all the loci which have a Positive_clone entry.
 
448
   It may be called with key zero to get its side-effects */
 
449
 
 
450
BOOL getPos (MAPCONTROL map, KEY key, float *y)
 
451
{ OBJ Chrom, Locus;
 
452
  KEY chrom, locus, clone;
 
453
  KEY posCache, orderedCache;
 
454
  int i, j, flags;
 
455
  float xmin = -1, xmax = 1; /* minimum sensible range */
 
456
  float x, dx, width;
 
457
  BOOL flipped;
 
458
  GeneticMap look = (GeneticMap)map->look;
 
459
  Array cacheArray = 0, orderedArray = 0, loci = 0;
 
460
  union 
 
461
    { float f;
 
462
      void *vs;
 
463
     } u;
 
464
  struct cacheEntry
 
465
    { KEY key;
 
466
      float x;
 
467
    }; 
 
468
  Associator a = look->posAss;
 
469
  
 
470
 
 
471
  if (!a)
 
472
    { 
 
473
      look->posAss = a = assHandleCreate(map->handle);
 
474
      look->orderedLoci = arrayHandleCreate(200, KEY, map->handle);
 
475
      if ((posCache = gMapCacheKey(map->key, "pos")) &&
 
476
          (cacheArray = arrayGet(posCache, struct cacheEntry, "kf")))
 
477
        {
 
478
          
 
479
          for (i = 2; i <arrayMax(cacheArray); i++)
 
480
            { 
 
481
              u.f = arr(cacheArray, i, struct cacheEntry).x;
 
482
              assInsert(a, assVoid(arr(cacheArray, i,struct cacheEntry).key), 
 
483
                        u.vs);
 
484
            }
 
485
          xmin = arr(cacheArray, 0, struct cacheEntry).x;
 
486
          xmax = arr(cacheArray, 1, struct cacheEntry).x;
 
487
          
 
488
          if ((orderedCache = gMapCacheKey(map->key, "ordered")) &&     
 
489
              (orderedArray = arrayGet(orderedCache, KEY, "k")))
 
490
            for (i= 0; i <arrayMax(orderedArray); i++)
 
491
              keySet(look->orderedLoci, i) = arr(orderedArray, i, KEY);
 
492
        }
 
493
      else 
 
494
        { 
 
495
          loci = gMapMapObjects(map->key);
 
496
          cacheArray = arrayCreate(200, struct cacheEntry);
 
497
          j = 2; /* zero and one for min and max */
 
498
          for (Locus = 0, i = 0; i <arrayMax(loci); bsDestroy (Locus) , i++)
 
499
            { locus = arr(loci, i, KEYPAIR).obj;
 
500
              chrom = arr(loci, i, KEYPAIR).map;
 
501
              flags = gMapGetMapObject(locus, map->key, chrom,
 
502
                                       20, &x, &dx, &Locus, 0);
 
503
              if (!flags)
 
504
                continue;
 
505
              if (flags & FLAG_ANY_LOCUS)
 
506
                { /* put info into cacheArray */
 
507
                  array(cacheArray, j, struct cacheEntry).x = x;
 
508
                  array(cacheArray, j, struct cacheEntry).key = locus;
 
509
                  j++;
 
510
                  /* This is very bizarre, we need need polymorphic assocs ASAP */
 
511
                  u.f = x;
 
512
                  assInsert(a, assVoid(locus), u.vs);
 
513
                  if (x < xmin)
 
514
                    xmin = x ;
 
515
                  if (x > xmax)
 
516
                    xmax = x ;
 
517
                }
 
518
              else /* Interval */
 
519
                { if (x-dx < xmin)
 
520
                    xmin = x-dx;
 
521
                  if (x+dx > xmax)
 
522
                    xmax = x+dx;
 
523
                }
 
524
              
 
525
              if (bsGetKey (Locus,_Positive_clone,&clone))
 
526
                keySetInsert(look->orderedLoci, locus);
 
527
            }
 
528
          
 
529
          array(cacheArray, 0, struct cacheEntry).x = xmin;
 
530
          array(cacheArray, 1, struct cacheEntry).x = xmax;
 
531
          orderedArray = arrayCopy(look->orderedLoci);
 
532
 
 
533
          gMapCacheStore(map->key, "pos", cacheArray, "kf");
 
534
          gMapCacheStore(map->key, "ordered", orderedArray, "k");
 
535
        }
 
536
      
 
537
      arrayDestroy(loci);
 
538
      arrayDestroy(cacheArray);
 
539
      arrayDestroy(orderedArray);
 
540
      /* If we can't find display tags in this map, 
 
541
         we look in any it inherits from */
 
542
      map->min = xmin;
 
543
      map->max = xmax;
 
544
      chrom = map->key;
 
545
      while ((Chrom = bsCreate(chrom)))
 
546
        { if (bsGetData(Chrom, _Extent, _Float, &map->min))
 
547
            { bsGetData(Chrom, _bsRight, _Float, &map->max);
 
548
              break;
 
549
            }
 
550
          if (bsGetKey(Chrom, _From_map, &chrom))
 
551
            { bsDestroy(Chrom);
 
552
              continue;
 
553
            }
 
554
          break;
 
555
        }
 
556
      bsDestroy(Chrom);
 
557
      
 
558
      map->centre = (map->max + map->min)/2.0; /* default values */
 
559
      width = (map->max - map->min)/3.0;
 
560
      flipped = FALSE;
 
561
      chrom = map->key;
 
562
      while ((Chrom = bsCreate(chrom)))
 
563
        { if (bsFindTag(Chrom, _Flipped))
 
564
            flipped = !flipped;
 
565
          if (bsGetData(Chrom, _Centre, _Float, &map->centre))
 
566
            { bsGetData(Chrom, _bsRight, _Float, &width);
 
567
              break;
 
568
            }
 
569
          if (bsGetKey(Chrom, _From_map, &chrom))
 
570
            { bsDestroy(Chrom);
 
571
              continue;
 
572
            }
 
573
          break;
 
574
        }
 
575
      bsDestroy(Chrom);
 
576
      map->mag = (map->control->graphHeight-5) / width;
 
577
      if (flipped)
 
578
        map->mag = - map->mag;
 
579
      
 
580
    }
 
581
  
 
582
  if (key && assFind(look->posAss, assVoid(key), &u.vs))
 
583
    { if (y) 
 
584
        *y = u.f;
 
585
      return TRUE;
 
586
    }
 
587
  
 
588
  return FALSE;
 
589
}
 
590
 
 
591
 
 
592
/* override the position value for a Locus temporarily */
 
593
 
 
594
void setTestPos (MAPCONTROL map, KEY key, float pos)
 
595
{
 
596
  GeneticMap look = (GeneticMap)map->look;
 
597
  union { float f;
 
598
          void *vs;
 
599
        } u;
 
600
  
 
601
  assRemove(look->posAss, assVoid(key));
 
602
 
 
603
  u.f = pos;
 
604
  assInsert(look->posAss, assVoid(key), u.vs);
 
605
 
 
606
}
 
607
 
 
608
/* This is a fundamental routine. It takes the key of 
 
609
   some object which has a Map tag followed by ?Map #Map_position
 
610
   and the key of the map on which the postition is required.
 
611
   It returns zero if something's missing,
 
612
   or FLAG_ANY_INTERVAL if it's an interval or FLAG_ANY_LOCUS if it's
 
613
   a Locus. 
 
614
   If the object doesn't have a position on the given map, but the map
 
615
   has a From_map tag, it searches recursively in the inherited from maps.
 
616
   For an interval the centre goes into *xret  and half the length
 
617
   into *dxret. For a Locus the position goes into *xret and the 
 
618
   error into *dxret.
 
619
   dxret and/or xret may be zero without segfaulting.
 
620
   The map key is needed to resolve the positions the objects which
 
621
   appear on more than one map. If objp is non-zero, the bsObject 
 
622
   for the object is not closed, but returned (a bsGoto(0) is performed on it).
 
623
   ind is the limit on how far one should recurse to resolve maps_with
 
624
   before giving up. 
 
625
   If count is non-null, multiple positions may be returned. In this
 
626
   case *count on calling gives the maximum number of positions to
 
627
   be returned (must be >=1) and xret and dxret must be suitably sized arrays.
 
628
   On return, *count if the actual number of positions found.
 
629
 
 
630
   Note that the object need not be mapped directly on the map given as a 
 
631
   parameter, it may be mapped on another map which the parameter map inherits
 
632
   from, or another map which it includes. See gMapMapObjects for details.
 
633
 
 
634
   
 
635
*/
 
636
 
 
637
int gMapGetMapObject
 
638
(KEY key, KEY map, KEY hint, int ind, 
 
639
 float *xret, float *dxret, OBJ *objp, int *count)
 
640
{
 
641
  OBJ item;     
 
642
  int flags;
 
643
  float offset;
 
644
  float x1, x2;
 
645
  int max, ourCount;
 
646
  BSMARK mark = 0;
 
647
  KEY _Multi_Ends = str2tag("Multi_Ends");
 
648
  float mapOffset, mapFactor; 
 
649
 
 
650
  if (count)
 
651
    max = *count;
 
652
  else
 
653
    max = 1;
 
654
 
 
655
  if (ind == 0)
 
656
    { messerror("Chased too many mapable objects trying to "
 
657
                "resolve \"maps with\". Is there a cycle involving %s?", 
 
658
                name(key));
 
659
      if (count)
 
660
        *count = 0;
 
661
      return 0;
 
662
    }
 
663
 
 
664
  if (!key || !(item = bsCreate(key)))
 
665
    { if (count)
 
666
        *count = 0;
 
667
      return 0;
 
668
    }
 
669
 
 
670
/* now find out what's what in the mapping dept. If we have a hint, and it's
 
671
   the same as the map, that's easy. A hint != map, means the locus is on an 
 
672
   inhertits-from map, or a sub-map. we find which, and determine the 
 
673
   transformation. If there is no hint, we need to first find the actual map 
 
674
   that the locus is on, using the same priority rules as gMapMapObjects
 
675
   (IMPORTANT), then proceed as above. */
 
676
 
 
677
  if (hint)
 
678
    { if (map != hint)
 
679
        /* find the map which includes the hint, or is the hint */
 
680
        { OBJ Map;
 
681
          while (hint != map &&
 
682
                 (Map = bsCreate(map)) &&
 
683
                 !bsFindKey(Map, str2tag("Includes"), hint))
 
684
            /* cannot find mapping for this map, it may inherit from another */
 
685
            { if (!bsGetKey(Map, str2tag("From_map"), &map))
 
686
                { bsDestroy(Map);
 
687
                  bsDestroy(item);
 
688
                  if (count)
 
689
                    *count = 0;
 
690
                  return 0;
 
691
                }
 
692
              bsDestroy(Map);
 
693
            }
 
694
          bsDestroy(Map);
 
695
        }
 
696
 
 
697
      if (!bsFindKey(item, str2tag("Map"), hint))
 
698
        { bsDestroy(item);
 
699
          if (count)
 
700
            *count = 0;
 
701
          return 0;
 
702
        }
 
703
    }
 
704
  else /* !hint */
 
705
    while  (!hint) 
 
706
      { if (bsFindKey(item, str2tag("Map"), map)) 
 
707
          /* it's on the map we want, easy */
 
708
          hint = map;
 
709
      else
 
710
        /* it's not, see if it's on a sub-map */
 
711
        { OBJ Map = bsCreate(map);
 
712
          KEY submap;
 
713
          if (bsGetKey(Map, str2tag("Includes"), &submap)) 
 
714
            do 
 
715
              { if (bsFindKey(item, str2tag("Map"), submap))
 
716
                  hint = submap;
 
717
              }
 
718
          while (!hint && bsGetKey(Map, _bsDown, &submap));
 
719
          bsDestroy(Map);
 
720
        }
 
721
 
 
722
      if (!hint) /* not found it yet, try inherits from maps. */
 
723
        { OBJ Map = bsCreate(map);
 
724
          if (!Map || !bsGetKey(Map, str2tag("From_map"), &map))
 
725
            /* No more, failed to find it. */
 
726
            { bsDestroy(Map);
 
727
              bsDestroy(item);
 
728
              if (count)
 
729
                *count = 0;
 
730
              return 0;
 
731
            }
 
732
          bsDestroy(Map);
 
733
        }
 
734
      }
 
735
  
 
736
  /* Ok , we now have a sequence map, hint, item, if hint != map, 
 
737
     we can calculate the scaling factor and offset */
 
738
  
 
739
  if (hint == map)
 
740
    { mapFactor = 1; 
 
741
      mapOffset = 0;
 
742
    }
 
743
  else
 
744
    { float leftEnd, rightEnd, extentLeft, extentRight;
 
745
      OBJ Submap = bsCreate(hint);
 
746
      if (!bsFindKey(Submap, str2tag("Map"), map) || 
 
747
          !bsPushObj(Submap) ||
 
748
          !bsGetData(Submap, _Left, _Float, &leftEnd) ||
 
749
          !bsGetData(Submap, _Right, _Float, &rightEnd))
 
750
        messerror("Failed to find map position for submap %s in map %s",
 
751
                  name(hint), name(map));
 
752
      if (leftEnd == rightEnd)
 
753
        messerror("Submap %s has zero length on map %s - cannot scale.",
 
754
                  name(hint), name(map));
 
755
      bsGoto(Submap, 0);
 
756
      if (!bsGetData(Submap, str2tag("Extent"), _Float, &extentLeft) ||
 
757
          !bsGetData(Submap, _bsRight, _Float, &extentRight))
 
758
        messerror("Map %s is a submap of map %s, but does not have an extent",
 
759
                  name(hint), name(map));
 
760
      
 
761
      bsDestroy(Submap);
 
762
      
 
763
      if (leftEnd > rightEnd)
 
764
        { float tmp = rightEnd;
 
765
          rightEnd = leftEnd;
 
766
          leftEnd = tmp;
 
767
        }
 
768
 
 
769
      mapOffset = leftEnd;
 
770
      mapFactor = (extentRight - extentLeft) / (leftEnd - rightEnd);
 
771
    }
 
772
      
 
773
 
 
774
 
 
775
  if (!bsPushObj(item)) /* to #Map_position */
 
776
    { bsDestroy(item);
 
777
      if (count)
 
778
        *count = 0;
 
779
      return 0;
 
780
    }
 
781
 
 
782
  if (bsGetData(item, _Multi_Position, _Float, &x1))
 
783
    { ourCount = 0;
 
784
      do 
 
785
        { mark = bsMark(item, mark);
 
786
          bsPushObj(item); /* To #Map_Error */
 
787
          if (!bsGetData(item, _Error, _Float, &x2))
 
788
            x2 = 0.0; /* default if no error */
 
789
          
 
790
          if (xret) 
 
791
            *(xret++) = mapOffset + mapFactor*x1;
 
792
          if (dxret)
 
793
            *(dxret++) = mapFactor*x2;
 
794
          
 
795
          ourCount++;
 
796
          bsGoto(item, mark);
 
797
        } 
 
798
      while (ourCount<max && bsGetData(item, _bsDown, _Float, &x1));
 
799
      
 
800
      bsMarkFree(mark);
 
801
      
 
802
      if (count) 
 
803
        *count = ourCount;
 
804
      
 
805
      if (objp)
 
806
        { bsGoto(item, 0);
 
807
          *objp = item;
 
808
        }
 
809
      else
 
810
        bsDestroy(item);
 
811
      
 
812
      return FLAG_ANY_LOCUS;
 
813
    }
 
814
  
 
815
  if (bsGetData(item, _Multi_Ends, _Float, &x1))
 
816
    { ourCount = 0;
 
817
      do 
 
818
        { mark = bsMark(item, mark);
 
819
          if (!bsGetData(item, _bsRight, _Float, &x2))
 
820
            continue; /* lines with no right */
 
821
          if (x1 < x2)
 
822
            { float dx = (x2 - x1)/2.0;
 
823
              if (xret)
 
824
                *(xret++) = mapOffset + mapFactor * (x1 + dx);
 
825
              if (dxret)
 
826
                *(dxret++) = mapFactor*dx;
 
827
            }
 
828
          else
 
829
            { float dx = (x1 - x2)/2.0;
 
830
              if (xret)
 
831
                *(xret++) = mapOffset + mapFactor * (x2 + dx);
 
832
              if (dxret)
 
833
                *(dxret++) =  mapFactor*dx; 
 
834
            }
 
835
          
 
836
          ourCount++;
 
837
          bsGoto(item, mark);
 
838
        } 
 
839
      while (ourCount<max && bsGetData(item, _bsDown, _Float, &x1));
 
840
      
 
841
      bsMarkFree(mark);
 
842
      
 
843
      if (count) 
 
844
        *count = ourCount;
 
845
      
 
846
      if (objp)
 
847
        { bsGoto(item, 0);
 
848
          *objp = item;
 
849
        }
 
850
      else
 
851
        bsDestroy(item);
 
852
      
 
853
      return FLAG_ANY_INTERVAL;
 
854
    }
 
855
  
 
856
  if (bsGetData(item, _Position, _Float, &x1)) /* Locus-like */
 
857
    { bsPushObj(item); /* to #Map_Error */
 
858
      if (!bsGetData(item, _Error, _Float, &x2))
 
859
        x2 = 0.0; /* default if no error */
 
860
      if (objp)
 
861
        { bsGoto(item, 0);
 
862
          *objp = item;
 
863
        }
 
864
      else
 
865
        bsDestroy(item);
 
866
      if (xret) 
 
867
        *xret = mapOffset + mapFactor*x1;
 
868
      if (dxret)
 
869
        *dxret = mapFactor*x2;
 
870
      if (count)
 
871
        *count = 1;
 
872
      return FLAG_ANY_LOCUS;
 
873
    }
 
874
   
 
875
  if (bsGetData(item , _Left, _Float, &x1) && /* Interval-like */
 
876
      bsGetData(item, _Right, _Float, &x2))
 
877
    { if (objp)
 
878
        { bsGoto(item, 0);
 
879
          *objp = item;
 
880
        }
 
881
      else
 
882
        bsDestroy(item);
 
883
      
 
884
      if (x1 < x2)
 
885
        { float dx = (x2 - x1)/2.0;
 
886
          if (xret)
 
887
            *xret = mapOffset + mapFactor*(x1 + dx);
 
888
          if (dxret)
 
889
            *dxret = mapFactor*dx;
 
890
        }
 
891
      else
 
892
        { float dx = (x1 - x2)/2.0;
 
893
          if (xret)
 
894
            *xret = mapOffset + mapFactor * (x2 + dx);
 
895
          if (dxret)
 
896
            *dxret = mapFactor * dx;
 
897
        }
 
898
 
 
899
      if (count)
 
900
        *count = 1;
 
901
      return FLAG_ANY_INTERVAL;
 
902
    }
 
903
 
 
904
 
 
905
  if (bsFindTag(item, str2tag("With")) && 
 
906
      bsGetKeyTags(item, _bsRight, &key) &&
 
907
      bsGetKey(item, _bsRight, &key))
 
908
    { int i;
 
909
      flags = gMapGetMapObject(key, map, 0, ind-1, xret, dxret, 0, count);
 
910
      if (flags && 
 
911
          bsPushObj(item) && bsFindTag(item, str2tag("Relative")) && 
 
912
          bsPushObj(item))
 
913
        { if (bsGetData(item, _Position, _Float, &offset))
 
914
            { if (xret) 
 
915
                for (i= 0; i < (count ? *count : 1); i++)
 
916
                  xret[i] += offset;
 
917
              flags = FLAG_ANY_LOCUS ;
 
918
            }
 
919
          else if (bsGetData(item, _Left, _Float, &x1) &&
 
920
                   bsGetData(item, _Right, _Float, &x2))
 
921
            { float dx ;
 
922
              if (x2 > x1) 
 
923
                { int tmp = x1 ; x1 = x2 ; x2 = tmp ; }
 
924
              dx = (x1 + x2) / 2.0 ;
 
925
              if (xret) 
 
926
                for (i= 0; i < (count ? *count : 1); i++)
 
927
                  xret[i] += dx ;
 
928
              dx = (x2 - x1) / 2.0 ;
 
929
              if (dxret)
 
930
                for (i= 0; i < (count ? *count : 1); i++)
 
931
                  dxret[i] = dx ;
 
932
              flags = FLAG_ANY_INTERVAL ;
 
933
            }
 
934
          else
 
935
            flags = 0 ;         /* require Position or Ends */
 
936
        }
 
937
      if (objp)
 
938
        { bsGoto(item, 0);
 
939
          *objp = item;
 
940
        }
 
941
      else
 
942
        bsDestroy(item);
 
943
      return flags;
 
944
    }
 
945
 
 
946
  if (count)
 
947
    *count = 0; 
 
948
 
 
949
  bsDestroy(item); /* mieg */
 
950
  return 0;
 
951
}
 
952
 
 
953
/**********************************/
 
954
 
 
955
 
 
956
/* This generates an array of all the objects on a map. It handles included 
 
957
   maps (one level only) and inherits_from maps. The output is a set of 
 
958
   (mapped object, map) pairs. The map is the map which directly contains the
 
959
   object, to be given as a hint to gMapGetMapObject.
 
960
   Note that the same object may not be mapped in more than one map, extra 
 
961
   mappings get ignored. The priority for this ensures that inheritance 
 
962
   works OK, and that objects mapped on a map and it's sub-map get the sub-map
 
963
   mapping ignored.
 
964
 */
 
965
 
 
966
 
 
967
Array gMapMapObjects(KEY chrom)
 
968
{ Array loci, results;
 
969
  int i;
 
970
  OBJ Chrom ;
 
971
  KEY key, locus, submap ;
 
972
  KEYPAIR *p;
 
973
  
 
974
  results = arrayCreate(300, KEYPAIR);
 
975
  loci = arrayCreate(200, BSunit);
 
976
 
 
977
  i = 256 ;
 
978
  while (i--) /* this is used to prevent infinite recursion in inheritance */
 
979
    lexClearClassStatus(i, CALCULSTATUS);
 
980
 
 
981
  while ((Chrom = bsCreate(chrom)))
 
982
  { 
 
983
    lexSetStatus(chrom, CALCULSTATUS) ;  /* prevent recursions */
 
984
 
 
985
    if (bsFindTag (Chrom,_Contains) && bsFlatten(Chrom, 2, loci))
 
986
      { for (i = 1; i<arrayMax(loci); i+=2)
 
987
          { locus =  arr(loci, i, BSunit).k;
 
988
            if (locus && !(CALCULSTATUS & lexGetStatus(locus)))
 
989
              { lexSetStatus(locus, CALCULSTATUS);
 
990
                p = arrayp(results, arrayMax(results), KEYPAIR);
 
991
                p->obj = arr(loci, i, BSunit).k;
 
992
                p->map = chrom;
 
993
              }
 
994
          }
 
995
      }
 
996
    /* now deal with  included maps */
 
997
    /* note that these cannot inherit, and that only on level of 
 
998
       inclusion is allowed */
 
999
    
 
1000
    if (bsGetKey(Chrom, str2tag("includes"), &submap))
 
1001
      { do
 
1002
          { OBJ Subchrom = bsCreate(submap);
 
1003
            if (Subchrom &&
 
1004
                bsFindTag (Subchrom,_Contains) && bsFlatten(Subchrom, 2, loci))
 
1005
              { for (i = 1; i<arrayMax(loci); i+=2)
 
1006
                  { locus =  arr(loci, i, BSunit).k;
 
1007
                    if (locus && !(CALCULSTATUS & lexGetStatus(locus)))
 
1008
                      { lexSetStatus(locus, CALCULSTATUS);
 
1009
                        p = arrayp(results, arrayMax(results), KEYPAIR);
 
1010
                        p->obj = arr(loci, i, BSunit).k;
 
1011
                        p->map = submap;
 
1012
                      }
 
1013
                  }
 
1014
              }
 
1015
            bsDestroy(Subchrom);
 
1016
          }
 
1017
      while (bsGetKey(Chrom, _bsDown, &submap));
 
1018
      }
 
1019
    
 
1020
    /* now do the same in any inherited maps. */
 
1021
   
 
1022
    if (!bsGetKey(Chrom, _From_map, &key) || 
 
1023
        (CALCULSTATUS & lexGetStatus(key)))
 
1024
      { bsDestroy(Chrom);
 
1025
        break;
 
1026
      }
 
1027
    
 
1028
    bsDestroy(Chrom);
 
1029
    chrom = key;
 
1030
  }
 
1031
  
 
1032
  arrayDestroy(loci);
 
1033
  return results;
 
1034
}
 
1035
 
 
1036
KEY gMapKeyOnTag(KEY key, KEY tag)
 
1037
{ OBJ obj;
 
1038
  KEY ret;
 
1039
  BOOL ok;
 
1040
 
 
1041
  if (!tag)
 
1042
    return key;
 
1043
 
 
1044
  if (!(obj = bsCreate(key))) 
 
1045
    return key;
 
1046
  
 
1047
  ok = bsGetKey(obj, tag, &ret);
 
1048
  bsDestroy(obj);
 
1049
  if (ok)
 
1050
    return ret;
 
1051
  else
 
1052
    return key;
 
1053
}
 
1054
 
 
1055
 
 
1056
/****************** giface hook *****************/
 
1057
 
 
1058
void gMapDrawGIF (ACEIN command_in, ACEOUT result_out)
 
1059
{
 
1060
  KEY key, view ;
 
1061
  KEY _VView ;
 
1062
  BOOL haveBounds = FALSE ;
 
1063
  BOOL isWhole = FALSE ;
 
1064
  BOOL isHideHeader = FALSE ;
 
1065
  float x1, x2, hdiff ;
 
1066
  char *word ;
 
1067
  MAPCONTROL map ;
 
1068
 
 
1069
  lexaddkey ("View", &key, _VMainClasses) ;
 
1070
  _VView = KEYKEY(key) ;
 
1071
              
 
1072
  if (!aceInCheck(command_in, "w"))
 
1073
    goto usage ;
 
1074
 
 
1075
  word = aceInWord(command_in);
 
1076
  if (!lexword2key(word, &key, _VMap))
 
1077
    {
 
1078
      aceOutPrint (result_out, "// gif map error: map %s not known\n", word) ;
 
1079
      return ;
 
1080
    }
 
1081
 
 
1082
  view = 0 ;
 
1083
  while (aceInStep (command_in, '-'))   /* options */
 
1084
    if ((word = aceInWord(command_in)))
 
1085
      {
 
1086
        if (strcmp (word, "view") == 0
 
1087
            && aceInCheck(command_in, "w"))
 
1088
          {
 
1089
            word = aceInWord(command_in);
 
1090
            if (!lexword2key (word, &view, _VView))
 
1091
              {
 
1092
                aceOutPrint (result_out, "// gif map error: view %s not known\n", word);
 
1093
                return ;
 
1094
              }
 
1095
          }
 
1096
        else if (strcmp (word, "coords") == 0
 
1097
                 && aceInCheck(command_in, "ff"))
 
1098
          {
 
1099
            aceInFloat (command_in, &x1);
 
1100
            aceInFloat (command_in, &x2) ;
 
1101
            haveBounds = (x2 != x1) ;
 
1102
            if (!haveBounds)
 
1103
              {
 
1104
                aceOutPrint (result_out, "// gif map error: coords given are the same (%g)\n", x1) ;
 
1105
                return ;
 
1106
              }
 
1107
          }
 
1108
        else if (strcmp (word, "whole") == 0)
 
1109
          isWhole = TRUE ;
 
1110
        else if (strcmp (word, "hideheader") == 0)
 
1111
          isHideHeader = TRUE ;
 
1112
        else
 
1113
          goto usage ;
 
1114
      }
 
1115
    else
 
1116
      goto usage ;
 
1117
 
 
1118
  if (aceInCheck (command_in, "w"))
 
1119
    /* no more options allowed on command-line */
 
1120
    goto usage ;
 
1121
 
 
1122
  { extern BOOL displayReportGif ;
 
1123
    displayReportGif = FALSE ;
 
1124
    display (key, view, "GMAP") ;       /* the primary display */
 
1125
    displayReportGif = TRUE ;
 
1126
  }
 
1127
 
 
1128
  map = currentMapControl () ;
 
1129
 
 
1130
  if (isHideHeader)
 
1131
    { map->control->hideHeader = TRUE ;
 
1132
      map->control->topMargin = 1 ;
 
1133
    }
 
1134
  if (haveBounds)
 
1135
    { map->centre = (x1 + x2) / 2.0 ;  
 
1136
      map->mag = (map->control->graphHeight - 
 
1137
                  map->control->topMargin - 2.0) / (x2 - x1) ;
 
1138
    }
 
1139
  else if (isWhole)
 
1140
    {  BOOL isNeg = (map->mag < 0) ;
 
1141
       map->centre = (map->max + map->min) / 2.0 ;  
 
1142
       map->mag = (map->control->graphHeight - 
 
1143
                   map->control->topMargin - 2.0) /
 
1144
         (map->max - map->min) ;
 
1145
       if (isNeg) map->mag = -map->mag ;
 
1146
    }
 
1147
 
 
1148
  if (haveBounds || isHideHeader || isWhole)
 
1149
    controlDraw () ;
 
1150
 
 
1151
  hdiff = (map->control->graphHeight - 5) / (2.0 * map->mag) ;
 
1152
  x1 = map->centre - hdiff ;
 
1153
  x2 = map->centre + hdiff ;
 
1154
  aceOutPrint (result_out, "// MAP  %s %g %g", freeprotect(name(key)), x1, x2) ;
 
1155
  if (view) aceOutPrint (result_out, " view=%s", freeprotect(name(view))) ;
 
1156
  aceOutPrint (result_out, "\n") ;
 
1157
 
 
1158
  return ;
 
1159
 
 
1160
usage:
 
1161
  aceOutPrint (result_out, "// gif map error: usage: MAP map [-view view] [-coords x1 x2]\n") ;
 
1162
 
 
1163
  return;
 
1164
} /* gMapDrawGIF */
 
1165
 
 
1166
 
 
1167
/* Checks to see that two tags match where the relationship between the tags is:
 
1168
 * 
 
1169
 * name(tag_1) = "XXXX_1"
 
1170
 * name(tag_2) = "XXXX_2"
 
1171
 * 
 
1172
 *  */
 
1173
static BOOL tagTypesMatch(KEY tag_1, KEY tag_2)
 
1174
{
 
1175
  BOOL result = FALSE ;
 
1176
  char *prefix ;
 
1177
  char *tag ;
 
1178
 
 
1179
  prefix = strtok(g_strdup(name(tag_1)), "_") ;
 
1180
 
 
1181
  tag = g_strdup_printf("%s_1", prefix) ;
 
1182
 
 
1183
  if (strcmp(tag, name(tag_1)) == 0)
 
1184
    {
 
1185
      g_free(tag) ;
 
1186
      tag = g_strdup_printf("%s_2", prefix) ;
 
1187
 
 
1188
      if (strcmp(tag, name(tag_2)) == 0)
 
1189
        result = TRUE ;
 
1190
    }
 
1191
 
 
1192
  g_free(tag) ;
 
1193
  g_free(prefix) ;
 
1194
 
 
1195
  return result ;
 
1196
}
 
1197
 
 
1198
 
 
1199
/*******************************************************************/
 
1200
/********************** end of file ********************************/