1 /*  objmgr.c
2 * ===========================================================================
3 *
4 *                            PUBLIC DOMAIN NOTICE
5 *               National Center for Biotechnology Information
6 *
7 *  This software/database is a "United States Government Work" under the
8 *  terms of the United States Copyright Act.  It was written as part of
9 *  the author's official duties as a United States Government employee and
10 *  thus cannot be copyrighted.  This software/database is freely available
11 *  to the public for use. The National Library of Medicine and the U.S.
12 *  Government have not placed any restriction on its use or reproduction.
13 *
14 *  Although all reasonable efforts have been taken to ensure the accuracy
15 *  and reliability of the software and data, the NLM and the U.S.
16 *  Government do not and cannot warrant the performance or results that
17 *  may be obtained by using this software or data. The NLM and the U.S.
18 *  Government disclaim all warranties, express or implied, including
19 *  warranties of performance, merchantability or fitness for any particular
20 *  purpose.
21 *
22 *  Please cite the author in any work or product based on this material.
23 *
24 * ===========================================================================
25 *
26 * File Name:  objmgr.c
27 *
28 * Author:  James Ostell
29 *
30 * Version Creation Date: 9/94
31 *
32 * $Revision: 6.90 $
33 *
34 * File Description:  Manager for Bioseqs and BioseqSets
35 *
36 * Modifications:
37 * --------------------------------------------------------------------------
38 *
39 * ==========================================================================
40 */
41 
42 /** for ErrPostEx() ****/
43 
44 static char *this_module = "ncbiapi";
45 #define THIS_MODULE this_module
46 static char *this_file = __FILE__;
47 #define THIS_FILE this_file
48 
49 /**********************/
50 
51 #include <objmgr.h>        /* the interface */
52 #include <objsset.h>       /* temporary for caching functions */
53 #include <ncbithr.h>       /* for thread safe functions */
54 #include <sequtil.h>
55 #include <explore.h>       /* for SeqMgrClearFeatureIndexes */
56 
57 /***
58 #define DEBUG_OBJMGR
59 ***/
60 
61 #define OBJMGR_MAX UINT4_MAX
62 
63 
64 /*****************************************************************************
65 *
66 *   Data Object local functions
67 *
68 *****************************************************************************/
69 static Uint4 NEAR ObjMgrTouchCnt PROTO((void));
70 static Boolean NEAR ObjMgrExtend PROTO((ObjMgrPtr omp));
71 static ObjMgrDataPtr NEAR ObjMgrFindByEntityID PROTO((ObjMgrPtr omp, Uint2 entityID, ObjMgrDataPtr PNTR prev));
72 static Boolean NEAR ObjMgrFreeClipBoardFunc PROTO((ObjMgrPtr omp));
73 static Boolean NEAR ObjMgrFreeCacheFunc PROTO((ObjMgrPtr omp, Uint2 type, Uint2Ptr rettype, VoidPtr PNTR retval));
74 static Boolean NEAR ObjMgrAddFunc PROTO((ObjMgrPtr omp, Uint2 type, Pointer data));
75 static Boolean NEAR ObjMgrFreeUserDataFunc PROTO((ObjMgrPtr omp, Uint2 entityID,
76                                 Uint2 procid, Uint2 proctype, Uint2 userkey));
77 static Int4 NEAR ObjMgrLockFunc (ObjMgrPtr omp, Uint2 type, Pointer data, Boolean lockit);
78 /*****************************************************************************
79 *
80 *   Procedure Management local Functions
81 *
82 *****************************************************************************/
83 static Boolean NEAR ObjMgrProcExtend PROTO((ObjMgrPtr omp));
84 
85 /*****************************************************************************
86 *
87 *   Type Management Local functions
88 *
89 *****************************************************************************/
90 static Boolean NEAR ObjMgrTypeExtend PROTO((ObjMgrPtr omp));
91 
92 /*****************************************************************************
93 *
94 *   Messaging/Selection local functions
95 *
96 *****************************************************************************/
97 static Boolean NEAR ObjMgrSendMsgFunc PROTO((ObjMgrPtr omp, ObjMgrDataPtr omdp,
98                 Int2 msg, Uint2 entityID, Uint4 itemID,    Uint2 itemtype, Uint2 rowID,
99                 Uint2 fromProcID, Uint2 toProcID, Pointer procmsgdata));
100 static Boolean NEAR ObjMgrSendStructMsgFunc PROTO((ObjMgrPtr omp, ObjMgrDataPtr omdp,
101                 OMMsgStructPtr ommsp));
102 static SelStructPtr NEAR ObjMgrAddSelStruct PROTO((ObjMgrPtr omp,
103      Uint2 entityID, Uint4 itemID, Uint2 itemtype, Uint1 regiontype, Pointer region));
104 static Boolean NEAR ObjMgrSelectFunc PROTO((ObjMgrPtr omp, Uint2 entityID, Uint4 itemID, Uint2 itemtype,
105                                     Uint1 regiontype, Pointer region));
106 static Boolean NEAR ObjMgrDeSelectFunc PROTO((ObjMgrPtr omp, Uint2 entityID, Uint4 itemID, Uint2 itemtype,
107                                     Uint1 regiontype, Pointer region));
108 /* static Boolean NEAR ObjMgrDeSelectStrucFunc PROTO((ObjMgrPtr omp, SelStructPtr ssp)); */
109 static Boolean NEAR ObjMgrDeSelectAllFunc PROTO((ObjMgrPtr omp));
110 static Boolean NEAR ObjMgrRegionMatch PROTO((Uint1 regiontype1, Pointer region1,
111                         Uint1 regiontype2, Pointer region2));
112 /* static Pointer NEAR ObjMgrRegionCopy PROTO((ObjMgrPtr omp, Uint1 regiontype, Pointer region)); */
113 static Pointer NEAR ObjMgrRegionFree PROTO((ObjMgrPtr omp, Uint1 regiontype, Pointer region));
114 static Pointer NEAR ObjMgrMemCopyFunc PROTO((ObjMgrPtr omp, Uint2 type, Pointer ptr, Boolean unlock));
115 static Pointer NEAR ObjMgrFreeFunc PROTO((ObjMgrPtr omp, Uint2 type, Pointer ptr, Boolean unlock));
116 
117 /*****************************************************************************
118 *
119 *   ObjMgr Functions
120 *
121 *****************************************************************************/
122 static TNlmMutex omctr_mutex = NULL;
ObjMgrTouchCnt(void)123 static Uint4 NEAR ObjMgrTouchCnt (void)
124 {
125     static Uint4 ObjMgrTouchCtr = 1; /* start at 1 to avoid rollover signal */
126     Int4 ret, imax, i;
127     ObjMgrPtr omp;
128     ObjMgrDataPtr PNTR omdpp;
129     Uint4 tmpctr;
130 
131     if (! ObjMgrTouchCtr)  /* rolled over */
132     {
133         ret = NlmMutexLockEx(&omctr_mutex); /* protect this section */
134         if (ret)  /* error */
135         {
136             ErrPostEx(SEV_FATAL,0,0,"ObjMgrTouchCnt failed [%ld]", (long)ret);
137             return ObjMgrTouchCtr;
138         }
139 
140         /**** reset the touch values *****/
141         /** all calls to this function should already have ObjMgrWriteLock **/
142 
143         if (! ObjMgrTouchCtr) /* check that this was not a stalled thread */
144         {
145             tmpctr = 0;
146             omp = ObjMgrGet();
147             imax = omp->currobj;
148             omdpp = omp->datalist;
149             for (i = 0; i < imax; i++)
150             {
151                 if (omdpp[i]->parentptr == NULL)
152                     omdpp[i]->touch = ++tmpctr;
153             }
154             ObjMgrTouchCtr = tmpctr;
155         }
156         NlmMutexUnlock(omctr_mutex);
157     }
158 
159     return ++ObjMgrTouchCtr;
160 
161 }
162 
ObjMgrGetData(Uint2 entityID)163 NLM_EXTERN ObjMgrDataPtr LIBCALL ObjMgrGetData (Uint2 entityID)
164 {
165     ObjMgrDataPtr prev, retval=NULL;
166     ObjMgrPtr omp;
167 
168     omp = ObjMgrReadLock();
169     retval = ObjMgrFindByEntityID (omp, entityID, &prev);
170     ObjMgrUnlock();
171     return retval;
172 }
173 
ObjMgrGetDataStruct(ObjMgrPtr omp,Uint2 entityID)174 NLM_EXTERN ObjMgrDataPtr LIBCALL ObjMgrGetDataStruct (ObjMgrPtr omp, Uint2 entityID)
175 {
176     ObjMgrDataPtr prev;
177 
178     return ObjMgrFindByEntityID (omp, entityID, &prev);
179 }
180 
181 /* cache to avoid linear search of all objects in ObjMgrFindByEntityID */
182 
183 #define TOP_ID_STACK_SIZE  100
184 
185 static Uint2 topEntityIDs [TOP_ID_STACK_SIZE];
186 static ObjMgrDataPtr topOMDPs [TOP_ID_STACK_SIZE];
187 static Int2  topIDStackPt = 0;
188 
189 extern void ObjMgrRecordOmdpByEntityID (Uint2 entityID, ObjMgrDataPtr omdp);
ObjMgrRecordOmdpByEntityID(Uint2 entityID,ObjMgrDataPtr omdp)190 extern void ObjMgrRecordOmdpByEntityID (Uint2 entityID, ObjMgrDataPtr omdp)
191 
192 {
193     Int2  i;
194 
195     if (entityID < 1) return;
196 
197     /* check for preexisting entry, update */
198 
199     for (i = 0; i < topIDStackPt; i++) {
200         if (entityID == topEntityIDs [i]) {
201             topOMDPs [i] = omdp; /* record in stack */
202             if (omdp == NULL) { /* remove if null */
203                 if (topIDStackPt > i + 1) {
204                     topIDStackPt--;
205                     topEntityIDs [i] = topEntityIDs [topIDStackPt];
206                     topOMDPs [i] = topOMDPs [topIDStackPt];
207                 } else {
208                     topIDStackPt--;
209                 }
210             }
211             return;
212         }
213     }
214 
215     /* add if not found */
216 
217     if (omdp == NULL) return;
218     if (topIDStackPt < TOP_ID_STACK_SIZE) {
219         topEntityIDs [topIDStackPt] = entityID;
220         topOMDPs [topIDStackPt] = omdp;
221         topIDStackPt++;
222     }
223     ObjMgrAddIndexOnEntityID(NULL,entityID,omdp);
224 }
225 
ObjMgrFindByEntityID(ObjMgrPtr omp,Uint2 entityID,ObjMgrDataPtr PNTR prev)226 static ObjMgrDataPtr NEAR ObjMgrFindByEntityID (ObjMgrPtr omp, Uint2 entityID, ObjMgrDataPtr PNTR prev)
227 {
228     ObjMgrDataPtr omdp, prevptr=NULL;
229     ObjMgrDataPtr PNTR omdpp;
230     Int4 i, imax;
231 
232     /* check cache first to avoid linear search through all objects */
233     if((omdp=ObjMgrLookupIndexOnEntityID(omp,entityID)) != NULL) return omdp;
234 
235     for (i = 0; i < topIDStackPt; i++) {
236         if (entityID == topEntityIDs [i]) {
237             omdp = topOMDPs [i];
238             if (omdp != NULL && omdp->parentptr == NULL && omdp->EntityID == entityID) {
239                 if (prev != NULL)
240                     *prev = prevptr;
241                 return omdp;
242             }
243         }
244     }
245 
246     imax = omp->currobj;
247     omdpp = omp->datalist;
248     for (i = 0; i < imax; i++)
249     {
250         omdp = omdpp[i];    /* emptys always at end */
251         if (omdp->parentptr == NULL)
252         {
253             if (omdp->EntityID == entityID)
254             {
255                 if (prev != NULL)
256                     *prev = prevptr;
257                 return omdp;
258             }
259         }
260     }
261     return NULL;
262 }
263 
ObjMgrFindByData(ObjMgrPtr omp,Pointer ptr)264 NLM_EXTERN ObjMgrDataPtr LIBCALL ObjMgrFindByData (ObjMgrPtr omp, Pointer ptr)
265 {
266     ObjMgrDataPtr omdp;
267     ObjMgrDataPtr PNTR omdpp;
268     Int4 i, imax;
269 
270     if (ptr == NULL) return NULL;
271 
272     imax = omp->currobj;
273     omdpp = omp->datalist;
274 
275     i = ObjMgrLookup(omp, ptr);   /* find by binary search on dataptr? */
276     if (i >= 0)
277         return omdpp[i];          /* found it */
278 
279     for (i = 0; i < imax; i++)
280     {
281         omdp = omdpp[i];    /* emptys always at end */
282         if ((Pointer)(omdp->choice) == ptr)
283         {
284             return omdp;
285         }
286     }
287     return NULL;
288 }
289 
290 static TNlmMutex  entityid_array_mutex = NULL;
291 
292 static Uint4    assignedIDsArray [2050];
293 static Int2     assignedIDStackPt = 0;
294 static Boolean  assignedIDsInited = FALSE;
295 
296 static Uint4    assignedIDsBitIdx [32];
297 
ObjMgrInitAssignedIDArray(void)298 static void ObjMgrInitAssignedIDArray (void)
299 
300 {
301   Uint4  bit;
302   Int2   jdx;
303 
304   if (! assignedIDsInited) {
305     ObjMgrWriteLock ();
306 
307     MemSet ((Pointer) &assignedIDsArray, 0, sizeof assignedIDsArray);
308     MemSet ((Pointer) &assignedIDsBitIdx, 0, sizeof (assignedIDsBitIdx));
309 
310     /* initialize bit index array */
311 
312     bit = 1;
313     for (jdx = 0; jdx < 32; jdx++) {
314       assignedIDsBitIdx [jdx] = bit;
315       bit = bit << 1;
316     }
317 
318     /* entityID 0 is not available for use */
319 
320     assignedIDsArray [0] = assignedIDsBitIdx [0];
321 
322     assignedIDStackPt = 0;
323     assignedIDsInited = TRUE;
324 
325     ObjMgrUnlock ();
326   }
327 }
328 
329 
ObjMgrNextAvailEntityIDInt(ObjMgrPtr omp)330 static Uint2 ObjMgrNextAvailEntityIDInt (ObjMgrPtr omp)
331 
332 {
333   Uint2  entityID;
334   Int2   idx, jdx;
335   Uint4  val;
336 
337   if (! assignedIDsInited) {
338     ObjMgrInitAssignedIDArray ();
339   }
340 
341   /* find first 32 bit word with an available entityID */
342 
343   idx = assignedIDStackPt;
344   while (idx < 2048 && assignedIDsArray [idx] == 0xFFFFFFFF) {
345     idx++;
346   }
347   if (idx >= 2048) {
348     ErrPostEx (SEV_ERROR, 0, 0, "ObjMgrNextAvailEntityID failed with idx %d", (int) idx);
349     return 0;
350   }
351 
352   /* reset starting point, everything below should be in use */
353 
354   assignedIDStackPt = idx;
355 
356   /* find first empty bit in array element */
357 
358   val = assignedIDsArray [idx];
359   jdx = 0;
360   while (jdx < 32 && (val & assignedIDsBitIdx [jdx]) != 0) {
361     jdx++;
362   }
363   if (jdx >= 32) {
364     ErrPostEx (SEV_ERROR, 0, 0, "ObjMgrNextAvailEntityID failed with jdx %d", (int) jdx);
365     return 0;
366   }
367 
368   /* set bit to mark new entityID as in use */
369 
370   assignedIDsArray [idx] |= assignedIDsBitIdx [jdx];
371 
372   /* calculate entityID */
373 
374   entityID = (Uint2) (((Int4) idx) * 32L + (Int4) jdx);
375 
376   if (omp != NULL && omp->HighestEntityID < entityID) {
377     omp->HighestEntityID = entityID;
378   }
379 
380   return entityID;
381 }
382 
ObjMgrNextAvailEntityID(ObjMgrPtr omp)383 static Uint2 ObjMgrNextAvailEntityID (ObjMgrPtr omp)
384 
385 {
386   Uint2  entityID;
387 
388   NlmMutexLockEx (&entityid_array_mutex);
389   ObjMgrWriteLock ();
390 
391   entityID = ObjMgrNextAvailEntityIDInt (omp);
392 
393   ObjMgrUnlock ();
394   NlmMutexUnlock (entityid_array_mutex);
395 
396   return entityID;
397 }
398 
ObjMgrRecycleEntityIDInt(Uint2 entityID,ObjMgrPtr omp)399 static void ObjMgrRecycleEntityIDInt (Uint2 entityID, ObjMgrPtr omp)
400 
401 {
402   Int2   idx, jdx;
403 
404   if (! assignedIDsInited) {
405     ObjMgrInitAssignedIDArray ();
406   }
407 
408   if (entityID < 1) return;
409 
410   idx = (Int2) ((Uint4) entityID / 32L);
411   jdx = (Int2) ((Uint4) entityID % 32L);
412 
413   if (idx >= 2048 || idx < 0) {
414     ErrPostEx (SEV_ERROR, 0, 0, "ObjMgrRecycleEntityID %d failed with idx %d", (int) entityID, (int) idx);
415     return;
416   }
417   if (jdx >= 32 || jdx < 0) {
418     ErrPostEx (SEV_ERROR, 0, 0, "ObjMgrRecycleEntityID %d failed with jdx %d", (int) entityID, (int) jdx);
419     return;
420   }
421 
422   /* clear bit to mark old entityID as available */
423 
424   assignedIDsArray [idx] ^= assignedIDsBitIdx [jdx];
425 
426   /* reset starting point, everything below should be in use */
427 
428   if (idx < assignedIDStackPt) {
429     assignedIDStackPt = idx;
430   }
431 }
432 
ObjMgrRecycleEntityID(Uint2 entityID,ObjMgrPtr omp)433 static void ObjMgrRecycleEntityID (Uint2 entityID, ObjMgrPtr omp)
434 
435 {
436   NlmMutexLockEx (&entityid_array_mutex);
437   ObjMgrWriteLock ();
438 
439   ObjMgrRecycleEntityIDInt (entityID, omp);
440 
441   ObjMgrUnlock ();
442   NlmMutexUnlock (entityid_array_mutex);
443 }
444 
ObjMgrRemoveEntityIDFromRecycleInt(Uint2 entityID,ObjMgrPtr omp)445 static void ObjMgrRemoveEntityIDFromRecycleInt (Uint2 entityID, ObjMgrPtr omp)
446 
447 {
448   Int2   idx, jdx;
449 
450   if (! assignedIDsInited) {
451     ObjMgrInitAssignedIDArray ();
452   }
453 
454   if (entityID < 1) return;
455 
456   idx = (Int2) ((Uint4) entityID / 32L);
457   jdx = (Int2) ((Uint4) entityID % 32L);
458 
459   if (idx >= 2048 || idx < 0) return;
460   if (jdx >= 32 || jdx < 0) return;
461 
462   /* set bit to restore old entityID status to in use */
463 
464   assignedIDsArray [idx] |= assignedIDsBitIdx [jdx];
465 }
466 
467 extern void ObjMgrRemoveEntityIDFromRecycle (Uint2 entityID, ObjMgrPtr omp);
ObjMgrRemoveEntityIDFromRecycle(Uint2 entityID,ObjMgrPtr omp)468 extern void ObjMgrRemoveEntityIDFromRecycle (Uint2 entityID, ObjMgrPtr omp)
469 
470 {
471   NlmMutexLockEx (&entityid_array_mutex);
472   ObjMgrWriteLock ();
473 
474   ObjMgrRemoveEntityIDFromRecycleInt (entityID, omp);
475 
476   ObjMgrUnlock ();
477   NlmMutexUnlock (entityid_array_mutex);
478 }
479 
ObjMgrAddEntityID(ObjMgrPtr omp,ObjMgrDataPtr omdp)480 NLM_EXTERN Uint2 LIBCALL ObjMgrAddEntityID (ObjMgrPtr omp, ObjMgrDataPtr omdp)
481 {
482     if (omdp == NULL) return 0;
483 
484     if (omdp->EntityID)
485        return omdp->EntityID;
486 
487     /* omdp->EntityID = ++(omp->HighestEntityID); */
488     omdp->EntityID = ObjMgrNextAvailEntityID (omp);
489     ObjMgrRecordOmdpByEntityID (omdp->EntityID, omdp);
490 
491 #ifdef DEBUG_OBJMGR
492     ObjMgrDump(NULL, "ObjMgrAddEntityID-A");
493 #endif
494 
495     ObjMgrSendMsgFunc(omp, omdp, OM_MSG_CREATE, omdp->EntityID, 0, 0, 0, 0, 0, NULL);
496 
497 #ifdef DEBUG_OBJMGR
498     ObjMgrDump(NULL, "ObjMgrAddEntityID-B");
499 #endif
500 
501     return omdp->EntityID;
502 }
ObjMgrSendMsgFunc(ObjMgrPtr omp,ObjMgrDataPtr omdp,Int2 msg,Uint2 entityID,Uint4 itemID,Uint2 itemtype,Uint2 rowID,Uint2 fromProcID,Uint2 toProcID,Pointer procmsgdata)503 static Boolean NEAR ObjMgrSendMsgFunc (ObjMgrPtr omp, ObjMgrDataPtr omdp,
504                 Int2 msg, Uint2 entityID, Uint4 itemID,    Uint2 itemtype, Uint2 rowID,
505                 Uint2 fromProcID, Uint2 toProcID, Pointer procmsgdata)
506 {
507     OMMsgStruct omms;
508 
509     MemSet((Pointer)(&omms), 0, sizeof(OMMsgStruct));
510 
511     omms.message = msg;
512     omms.entityID = entityID;
513     omms.itemID = itemID;
514     omms.itemtype = itemtype;
515     omms.fromProcID = fromProcID;
516     omms.toProcID = toProcID;
517     omms.procmsgdata = procmsgdata;
518     omms.rowID = rowID;
519 
520     return ObjMgrSendStructMsgFunc (omp, omdp, &omms);
521 }
522 
523 /*********************************************************************
524 *
525 *   ObjMgrSendStructMsgFunc()
526 *   This function actually sends the messages to registered proceedures.
527 *   It has to unlock the objmgr so the proceedures can read or write the
528 *   objmgr. This is risky, but I am not sure how to do this safer. It does
529 *   keep an array of messages to send before it unlocks anything, in case
530 *   the message list changes from a callback. This imposes a fixed limit to
531 *   the number of messages that can be sent at once to MAXMSG. This may become
532 *   a problem.
533 *
534 *********************************************************************/
ObjMgrSendStructMsgFunc(ObjMgrPtr omp,ObjMgrDataPtr omdp,OMMsgStructPtr ommsp)535 static Boolean NEAR ObjMgrSendStructMsgFunc (ObjMgrPtr omp, ObjMgrDataPtr omdp,
536                 OMMsgStructPtr ommsp)
537 {
538 #define MAXMSG 250  /* max number of messages to save */
539     OMUserDataPtr prev=NULL, curr, next, PNTR root, msgs[MAXMSG], omudp;
540     Int2 retval;
541     Int2 ctr, nummsg, i;
542     Boolean is_write_locked, too_many, done;
543 
544     is_write_locked = omp->is_write_locked;   /* remember state */
545     nummsg = 0;      /* no messages known yet */
546 
547                       /*****************************************
548                       *  First find all messages to send while locked
549                       *****************************************/
550     curr = omp->userdata;
551     root = &(omp->userdata);
552     ctr = 2;
553     too_many = FALSE;
554     while ((ctr) && (! too_many))
555     {
556         prev = NULL;
557         while ((curr != NULL) && (! too_many))
558         {
559             next = curr->next;
560             if (curr->messagefunc != NULL)
561             {
562                 if (ommsp->toProcID == 0 || ommsp->toProcID == curr->procid) {
563                     if (nummsg < MAXMSG)
564                     {
565                         msgs[nummsg] = curr;
566                         nummsg++;
567                     }
568                     else
569                         too_many = TRUE;
570                 }
571             }
572             curr = next;
573         }
574 
575         if (omdp == NULL)
576             ctr -= 2;
577         else if (ctr == 2)
578         {
579             ctr--;
580             curr = omdp->userdata;
581             root = &(omdp->userdata);
582         }
583         else
584             ctr--;
585     }
586 
587     if (too_many)
588     {
589         ErrPostEx(SEV_ERROR,0,0,"ObjMgrSendMessage: more than %d messages",
590             (int)nummsg);
591     }
592 
593 
594 
595                       /*****************************************
596                       *  now send the messages confirming that each
597                       *    still exists
598                       *****************************************/
599 
600     for (i = 0; i < nummsg; i++)
601     {
602         omudp = msgs[i];
603         done = FALSE;
604     curr = omp->userdata;
605     root = &(omp->userdata);
606     ctr = 2;
607     while ((ctr) && (! done))
608     {
609         prev = NULL;
610         while ((curr != NULL) && (! done))
611         {
612             next = curr->next;
613             if (curr == omudp)
614             {
615               done = TRUE;   /* found this one */
616               if (curr->messagefunc != NULL)
617               {
618                 ommsp->omuserdata = (Pointer)curr;
619 
620                 ObjMgrUnlock();   /* have to allow message to react */
621                 retval = (* (curr->messagefunc))(ommsp);
622                 if (is_write_locked)
623                     ObjMgrWriteLock();
624                 else
625                     ObjMgrReadLock();
626 
627                 if (retval == OM_MSG_RET_ERROR)
628                     ErrShow();
629                 else if (retval == OM_MSG_RET_DEL)
630                 {
631                     if (prev == NULL)
632                         *root = next;
633                     else
634                         prev->next = next;
635                     if (curr->freefunc != NULL)
636                         (* (curr->freefunc))(curr->userdata.ptrvalue);
637                     MemFree(curr);
638                 }
639               }
640             }
641             curr = next;
642         }
643 
644         if (omdp == NULL)
645             ctr -= 2;
646         else if (ctr == 2)
647         {
648             ctr--;
649             curr = omdp->userdata;
650             root = &(omdp->userdata);
651         }
652         else
653             ctr--;
654       }
655     }
656     return TRUE;
657 
658 }
659 /*****************************************************************************
660 *
661 *   Return the current ObjMgr
662 *       ObjMgrGet is obsolete
663 *       ObjMgrReadLock, ReadUnlock, WriteLock, WriteUnlock are thread safe
664 *
665 *****************************************************************************/
666 static TNlmMutex omp_mutex = NULL;
667 static ObjMgrPtr global_omp = NULL;
668 static TNlmRWlock omp_RWlock = NULL;
669 
670 /*****************************************************************************
671 *
672 *   Return the current ObjMgr
673 *       Initialize if not done already
674 *       This function will become obsolete
675 *
676 *****************************************************************************/
ObjMgrGet(void)677 NLM_EXTERN ObjMgrPtr LIBCALL ObjMgrGet (void)
678 {
679     Int4 ret;
680     ObjMgrPtr omp;
681 
682     if (global_omp != NULL)
683         return global_omp;
684 
685     ret = NlmMutexLockEx(&omp_mutex);  /* protect this section */
686     if (ret)  /* error */
687     {
688         ErrPostEx(SEV_FATAL,0,0,"ObjMgrGet failed [%ld]", (long)ret);
689         return NULL;
690     }
691 
692     if (global_omp == NULL)  /* check again after mutex */
693     {
694                                  /*** have to initialize it **/
695         omp = (ObjMgrPtr) MemNew (sizeof(ObjMgr));
696         omp->maxtemp = DEFAULT_MAXTEMP;
697         omp->maxobj = DEFAULT_MAXOBJ;
698         omp_RWlock = NlmRWinit();  /* initialize RW lock */
699         global_omp = omp;       /* do this last for mutex safety */
700     }
701 
702     NlmMutexUnlock(omp_mutex);
703 
704     return global_omp;
705 }
706 
707 /*****************************************************************************
708 *
709 *   ObjMgrReadLock()
710 *       Initialize if not done already
711 *       A thread can have only one read or write lock at a time
712 *       Many threads can have read locks
713 *       Only one thread can have a write lock
714 *       No other threads may have read locks if a write lock is granted
715 *       If another thread holds a write lock, this call blocks until write
716 *          is unlocked.
717 *
718 *****************************************************************************/
ObjMgrReadLock(void)719 NLM_EXTERN ObjMgrPtr LIBCALL ObjMgrReadLock (void)
720 {
721     ObjMgrPtr omp;
722     Int4 ret;
723 
724     omp = ObjMgrGet();  /* ensure initialization */
725 
726         ret = NlmRWrdlock(omp_RWlock);
727     /* ret = NlmRWwrlock(omp_RWlock); */
728 
729     if (ret != 0)
730     {
731         ErrPostEx(SEV_ERROR,0,0,"ObjMgrReadLock: RWrdlock error [%ld]",
732             (long)ret);
733         return NULL;
734     }
735 
736     omp->is_write_locked = TRUE;
737 
738     return omp;
739 }
740 
741 /*****************************************************************************
742 *
743 *   ObjMgrWriteLock
744 *       Initialize if not done already
745 *       A thread can have only one read or write lock at a time
746 *       Many threads can have read locks
747 *       Only one thread can have a write lock
748 *       No other threads may have read locks if a write lock is granted
749 *       If another thread holds a read or write lock, this call blocks until write
750 *          is unlocked.
751 *
752 *****************************************************************************/
ObjMgrWriteLock(void)753 NLM_EXTERN ObjMgrPtr LIBCALL ObjMgrWriteLock (void)
754 {
755     ObjMgrPtr omp;
756     Int4 ret;
757 
758     omp = ObjMgrGet();  /* ensure initialization */
759 
760     ret = NlmRWwrlock(omp_RWlock);
761     if (ret != 0)
762     {
763         ErrPostEx(SEV_ERROR,0,0,"ObjMgrWriteLock: RWwrlock error [%ld]",
764             (long)ret);
765         return NULL;
766     }
767     omp->is_write_locked = TRUE;
768     return omp;
769 }
770 
771 
772 /*****************************************************************************
773 *
774 *  ObjMgrUnlock()
775 *
776 *****************************************************************************/
ObjMgrUnlock(void)777 NLM_EXTERN Boolean LIBCALL ObjMgrUnlock (void)
778 {
779     ObjMgrPtr omp;
780     Int4 ret;
781 
782     omp = ObjMgrGet();  /* ensure initialization */
783 
784     ret = NlmRWunlock(omp_RWlock);
785     if (ret != 0)
786     {
787         ErrPostEx(SEV_ERROR,0,0,"ObjMgrUnlock: RWunlock error [%ld]",
788             (long)ret);
789         return FALSE;
790     }
791     omp->is_write_locked = FALSE;  /* can't be write locked */
792     return TRUE;
793 }
794 
795 
796 
797 
798 /*****************************************************************************
799 *
800 *   ObjMgrSetOptions(Uint2 option, Uint2 entityID)
801 *     Sets options on the ObjMgr. All Options are 1 bit flags set with
802 *       defines. Several Options may be ORed together.
803 *       returns current options.
804 *
805 *****************************************************************************/
ObjMgrSetOptions(Uint2 option,Uint2 entityID)806 NLM_EXTERN Uint2 LIBCALL ObjMgrSetOptions (Uint2 option, Uint2 entityID)
807 {
808     ObjMgrPtr omp;
809     Uint2Ptr optionptr;
810     ObjMgrDataPtr omdp, prev;
811 
812     omp = ObjMgrGet();
813     if (entityID == 0)
814         optionptr = &(omp->options);
815     else
816     {
817         omdp = ObjMgrFindByEntityID(omp, entityID, &prev);
818         if (omdp == NULL)
819             return 0;
820         optionptr = &(omdp->options);
821     }
822     *optionptr |= (option & 0xFFFF);
823     return *optionptr;
824 }
825 
826 /*****************************************************************************
827 *
828 *   ObjMgrClearOptions(Uint2 option, Uint2 entityID)
829 *     Clears options on the ObjMgr. All Options are 1 bit flags set with
830 *       defines. Several Options may be ORed together.
831 *       returns current options.
832 *
833 *****************************************************************************/
ObjMgrClearOptions(Uint2 option,Uint2 entityID)834 NLM_EXTERN Uint2 LIBCALL ObjMgrClearOptions (Uint2 option, Uint2 entityID)
835 {
836     ObjMgrPtr omp;
837      Uint2Ptr optionptr;
838     ObjMgrDataPtr omdp, prev;
839 
840 
841     omp = ObjMgrGet();
842     if (entityID == 0)
843         optionptr = &(omp->options);
844     else
845     {
846         omdp = ObjMgrFindByEntityID(omp, entityID, &prev);
847         if (omdp == NULL)
848             return 0;
849         optionptr = &(omdp->options);
850     }
851     *optionptr &= ~(option & 0xFFFF);
852     return *optionptr;
853 }
854 
855 /*****************************************************************************
856 *
857 *   ObjMgrGetOptions(entityID)
858 *     Returns options on the ObjMgr. All Options are 1 bit flags set with
859 *       defines. Several Options may be ORed together.
860 *
861 *****************************************************************************/
ObjMgrGetOptions(Uint2 entityID)862 NLM_EXTERN Uint2 LIBCALL ObjMgrGetOptions (Uint2 entityID)
863 {
864     ObjMgrPtr omp;
865     ObjMgrDataPtr omdp, prev;
866     Uint2 retval = 0;
867 
868     omp = ObjMgrReadLock();
869     if (entityID == 0)
870          retval = omp->options;
871     else
872     {
873         omdp = ObjMgrFindByEntityID(omp, entityID, &prev);
874         if (omdp != NULL)
875             retval = omdp->options;
876     }
877     ObjMgrUnlock();
878     return retval;
879 }
880 
881 /*****************************************************************************
882 *
883 *   ObjMgrTestOptions(Uint2 option)
884 *     Tests options on the ObjMgr. All Options are 1 bit flags set with
885 *       defines. Several Options may be ORed together.
886 *       returns TRUE if ANY flags in "option" are set in the ObjMgr.
887 *       Normally one would supply only 1 option to test. If many were to
888 *       be tested, use ObjMgrGetOptions()
889 *
890 *****************************************************************************/
ObjMgrTestOptions(Uint2 option,Uint2 entityID)891 NLM_EXTERN Boolean LIBCALL ObjMgrTestOptions (Uint2 option, Uint2 entityID)
892 {
893     ObjMgrPtr omp;
894     Uint2Ptr optionptr;
895     ObjMgrDataPtr omdp, prev;
896     Boolean retval = FALSE;
897 
898     omp = ObjMgrReadLock();
899     if (entityID == 0)
900         optionptr = &(omp->options);
901     else
902     {
903         omdp = ObjMgrFindByEntityID(omp, entityID, &prev);
904         if (omdp == NULL)
905             goto erret;
906         optionptr = &(omdp->options);
907     }
908 
909     if (*optionptr & (option & 0xFFFF))
910         retval = TRUE;
911 erret:
912 
913     ObjMgrUnlock();
914 
915     return retval;
916 }
917 
918 /*****************************************************************************
919 *
920 *   ObjMgrSetHold()
921 *     Increments hold count in ObjMgr
922 *       returns current hold count
923 *     if hold != 0, then no tempload records are cached out of memory
924 *     This is useful if you are doing a complex task involving repeated
925 *      access to many records and you want them to stay in memory while
926 *      the task is performed, even though they are loaded temporarily by
927 *      BioseqLock..
928 *     Be sure to call ObjMgrClearHold() when you are done so they can be
929 *      cached out.
930 *
931 *****************************************************************************/
ObjMgrSetHold(void)932 NLM_EXTERN Uint2 LIBCALL ObjMgrSetHold (void)
933 {
934     ObjMgrPtr omp;
935 
936     omp = ObjMgrWriteLock();
937 
938     if (omp->hold < OBJMGR_MAX)
939         omp->hold++;
940     else
941         ErrPostEx(SEV_ERROR,0,0, "ObjMgrSetHold: hold > OBJMGR_MAX");
942     ObjMgrUnlock();
943     return omp->hold;
944 }
945 
946 /*****************************************************************************
947 *
948 *   ObjMgrClearHold()
949 *     Decrements hold count in ObjMgr
950 *       returns current hold count
951 *       will never decrement below 0
952 *     if hold == 0, then tempload records will be cached out of memory
953 *
954 *****************************************************************************/
ObjMgrClearHold(void)955 NLM_EXTERN Uint2 LIBCALL ObjMgrClearHold (void)
956 {
957     ObjMgrPtr omp;
958 
959     omp = ObjMgrWriteLock();
960 
961     if (omp->hold)
962     {
963         omp->hold--;
964         if (! (omp->hold))  /* down to 0 */
965             ObjMgrReap(omp);
966     }
967     else
968         ErrPostEx(SEV_ERROR,0,0, "ObjMgrClearHold: hold = 0");
969     ObjMgrUnlock();
970     return omp->hold;
971 }
972 
973 /*****************************************************************************
974 *
975 *   ObjMgrCheckHold()
976 *       returns current hold count
977 *     if hold == 0, then tempload records will be cached out of memory
978 *
979 *****************************************************************************/
ObjMgrCheckHold(void)980 NLM_EXTERN Uint2 LIBCALL ObjMgrCheckHold (void)
981 {
982     ObjMgrPtr omp;
983 
984     omp = ObjMgrReadLock();
985     ObjMgrUnlock();
986     return omp->hold;
987 }
988 
989 
990 
991 /*****************************************************************************
992 *
993 *   Data Management Functions
994 *
995 *****************************************************************************/
996 
997 
998 /*****************************************************************************
999 *
1000 *   ObjMgrExtend(omp)
1001 *
1002 *****************************************************************************/
ObjMgrExtend(ObjMgrPtr omp)1003 static Boolean NEAR ObjMgrExtend (ObjMgrPtr omp)
1004 {
1005     Boolean result = FALSE;
1006     OMDataPtr omdp, prev=NULL;
1007     ObjMgrDataPtr PNTR tmp;
1008     Int4 i, j;
1009 
1010     for (omdp = omp->ncbidata; omdp != NULL; omdp = omdp->next)
1011         prev = omdp;
1012 
1013     omdp = (OMDataPtr)MemNew(sizeof(OMData));
1014     if (omdp == NULL) return result;
1015     tmp = (ObjMgrDataPtr PNTR)MemNew((size_t)(sizeof(ObjMgrDataPtr) * (omp->totobj + NUM_OMD)));
1016     if (tmp == NULL)
1017     {
1018         MemFree(omdp);
1019         return result;
1020     }
1021 
1022     if (prev != NULL)
1023     {
1024         prev->next = omdp;
1025         MemMove(tmp, omp->datalist, (size_t)(sizeof(ObjMgrDataPtr) * omp->totobj));
1026         MemFree(omp->datalist);
1027     }
1028     else
1029         omp->ncbidata = omdp;
1030 
1031     j = omp->totobj;
1032 
1033     for (i = 0; i < NUM_OMD; i++, j++)
1034         tmp[j] = &(omdp->data[i]);
1035 
1036     if (omp->totobj < OBJMGR_MAX - NUM_OMD)
1037         omp->totobj += NUM_OMD;
1038     else
1039         ErrPostEx(SEV_ERROR, 0,0, "ObjMgrExtend: incrementing totobj above OBJMGR_MAX");
1040     omp->datalist = tmp;
1041 
1042     result = TRUE;
1043     return result;
1044 }
1045 /*****************************************************************************
1046 *
1047 *   ObjMgrAdd(type, data)
1048 *       adds a pointer (data) of type (type) to the sequence manager
1049 *
1050 *****************************************************************************/
ObjMgrAdd(Uint2 type,Pointer data)1051 NLM_EXTERN Boolean LIBCALL ObjMgrAdd (Uint2 type, Pointer data)
1052 {
1053     ObjMgrPtr omp;
1054     Boolean retval = FALSE;
1055 
1056     omp = ObjMgrWriteLock();
1057     retval = ObjMgrAddFunc(omp, type, data);
1058     ObjMgrUnlock();
1059     return retval;
1060 }
1061 
1062 
1063 /*****************************************************************************
1064 *
1065 *   ObjMgrAddFunc(omp, type, data)
1066 *       adds a pointer (data) of type (type) to the sequence manager
1067 *
1068 *****************************************************************************/
ObjMgrAddFunc(ObjMgrPtr omp,Uint2 type,Pointer data)1069 static Boolean NEAR ObjMgrAddFunc (ObjMgrPtr omp, Uint2 type, Pointer data)
1070 {
1071     ObjMgrDataPtr omdp;
1072     ObjMgrDataPtr PNTR omdpp;
1073     Int4 i, imin, imax;
1074     Boolean retval = FALSE;
1075     unsigned long tmp, datai;
1076     BioseqPtr bsp;
1077 #ifdef DEBUG_OBJMGR
1078     FILE * fp;
1079 
1080     fp = FileOpen("ObjMgr.log", "a");
1081 #endif
1082 
1083     /* if autoclean is set and above maxobj, remove least recently accessed objects */
1084     if (omp->autoclean && omp->currobj >= omp->maxobj) {
1085         ObjMgrReapOne (omp);
1086         ObjMgrFreeCache (OBJ_MAX); /* only frees unlocked objects */
1087     }
1088 
1089     if (omp->currobj >= omp->totobj)
1090     {
1091         if (! ObjMgrExtend(omp))
1092             goto erret;
1093     }
1094 
1095     i = omp->currobj;
1096     omdpp = omp->datalist;
1097     omdp = omdpp[i];    /* emptys always at end */
1098     omdp->options = omp->options;   /* set default options */
1099 
1100     imin = 0;                   /* find where it goes */
1101     imax = omp->currobj-1;
1102 
1103     datai = (unsigned long)data;
1104 
1105     if ((i) && (datai < (unsigned long)(omdpp[imax]->dataptr)))
1106     {
1107         i = (imax + imin) / 2;
1108         while (imax > imin)
1109         {
1110             tmp = (unsigned long)(omdpp[i]->dataptr);
1111 #ifdef DEBUG_OBJMGR
1112             fprintf(fp, "Sort: i=%d tmp=%ld data=%ld imax=%d imin=%d\n",
1113                 (int)i, (long)tmp, (long)data, (int)imax, (int)imin);
1114 #endif
1115             if (tmp > datai)
1116                 imax = i - 1;
1117             else if (tmp < datai)
1118                 imin = i + 1;
1119             else
1120                 break;
1121             i = (imax + imin)/2;
1122         }
1123 
1124 #ifdef DEBUG_OBJMGR
1125             fprintf(fp, "End: i=%d tmp=%ld data=%ld imax=%d imin=%d\n",
1126                 (int)i, (long)tmp, (long)data, (int)imax, (int)imin);
1127 #endif
1128         if (datai > (unsigned long)(omdpp[i]->dataptr)) /* check for off by 1 */
1129         {
1130             i++;
1131 #ifdef DEBUG_OBJMGR
1132             fprintf(fp, "Adjust: i=%d\n", (int)i);
1133 #endif
1134         }
1135 
1136 
1137         imax = omp->currobj - 1;     /* open the array */
1138         while (imax >= i)
1139         {
1140             omdpp[imax+1] = omdpp[imax];
1141             imax--;
1142         }
1143     }
1144 
1145     omdpp[i] = omdp;    /* put in the pointer in order */
1146     if (omp->currobj < OBJMGR_MAX)
1147         omp->currobj++;     /* got one more */
1148     else
1149         ErrPostEx(SEV_ERROR, 0,0, "ObjMgrAddFunc: incrementing currobj above OBJMGR_MAX");
1150 
1151     omdp->dataptr = data;  /* fill in the values */
1152     omdp->datatype = type;
1153     omdp->touch = ObjMgrTouchCnt();   /* stamp with time */
1154 
1155     if (type == OBJ_BIOSEQ) {
1156         bsp = (BioseqPtr) data;
1157         if (bsp != NULL) {
1158             /* used for feature indexing, rapid delete from SeqID index */
1159             /* may not be thread safe */
1160             /* bsp->omdp = (Pointer) omdp; */
1161         }
1162     }
1163 
1164 #ifdef DEBUG_OBJMGR
1165     FileClose(fp);
1166     ObjMgrDump(NULL, "ObjMgrAdd");
1167 #endif
1168     retval = TRUE;
1169 erret:
1170     return retval;
1171 }
1172 
1173 /*****************************************************************************
1174 *
1175 *   ObjMgrRegister (datatype, data)
1176 *       datatype is the datatype of data to register
1177 *       if data is already registered in ObjMgr, returns entityID
1178 *       if not, is added to the ObjMgr, returns entityID
1179 *
1180 *       if (datatype is a choice type, uses data as a ValNodePtr)
1181 *
1182 *       on failure returns 0
1183 *
1184 *****************************************************************************/
ObjMgrRegister(Uint2 datatype,Pointer data)1185 NLM_EXTERN Uint2 LIBCALL ObjMgrRegister (Uint2 datatype, Pointer data)
1186 {
1187     Uint2 dtype, retval = 0;
1188     ObjMgrPtr omp;
1189     ObjMgrDataPtr omdp;
1190     ObjMgrTypePtr omtp;
1191     Pointer ptr;
1192 
1193 
1194     if (data == NULL) return retval;
1195 
1196     dtype = datatype;  /* sets the default state */
1197     ptr = data;
1198 
1199     omp = ObjMgrWriteLock();
1200 
1201     omdp = ObjMgrFindByData(omp, data);  /* already have it? */
1202     if (omdp != NULL)
1203     {
1204         if (! omdp->EntityID)
1205         {
1206             if (omdp->parentptr != NULL)
1207                 ErrPostEx(SEV_ERROR,0,0, "ObjMgrRegister: parent != NULL");
1208 
1209             ObjMgrAddEntityID(omp, omdp);
1210         }
1211 
1212         retval = omdp->EntityID;
1213         goto erret;
1214     }
1215                                 /* have to add it to ObjMgr */
1216     omtp = ObjMgrTypeFind(omp, datatype, NULL, NULL);
1217     if (omtp == NULL)
1218     {
1219         ErrPostEx(SEV_ERROR,0,0, "ObjMgrRegister: invalid data type [%d]", (int)datatype);
1220         goto erret;
1221     }
1222 
1223       /*** this was to register things like SeqEntry.. currently we register data.ptrvalue directly **
1224 
1225     if (omtp->fromchoicefunc == NULL)
1226     {
1227         dtype = datatype;
1228         ptr = data;
1229     }
1230     else
1231     {
1232         vnp = (ValNodePtr)data;
1233         dtype = (*(omtp->fromchoicefunc))(vnp);
1234         ptr = vnp->data.ptrvalue;
1235     }
1236 
1237       ***********************************************************************************************/
1238 
1239     ObjMgrAddFunc(omp, dtype, ptr);
1240     omdp = ObjMgrFindByData(omp, ptr);
1241     if (omdp == NULL) goto erret;
1242 
1243     ObjMgrAddEntityID(omp, omdp);
1244     retval = omdp->EntityID;
1245 erret:
1246     ObjMgrUnlock();
1247 
1248     return retval;
1249 }
1250 
1251 
1252 /*****************************************************************************
1253 *
1254 *   ObjMgrAddUserData(entityID, procid, proctype, userkey)
1255 *       creates a new OMUserData struct attached to entityID
1256 *       if entityID = 0, attaches to the desktop (all objects)
1257 *       Caller must fill in returned structure
1258 *       returns NULL on failure
1259 *
1260 *****************************************************************************/
ObjMgrAddUserData(Uint2 entityID,Uint2 procid,Uint2 proctype,Uint2 userkey)1261 NLM_EXTERN OMUserDataPtr LIBCALL ObjMgrAddUserData (Uint2 entityID, Uint2 procid, Uint2 proctype, Uint2 userkey)
1262 {
1263     OMUserDataPtr omudp=NULL, tmp;
1264     ObjMgrPtr omp;
1265     ObjMgrDataPtr omdp;
1266 
1267     omp = ObjMgrWriteLock();
1268 
1269     omudp = MemNew(sizeof(OMUserData));
1270     omudp->procid = procid;
1271     omudp->proctype = proctype;
1272     omudp->userkey = userkey;
1273 
1274     if (entityID == 0)
1275     {
1276         if (omp->userdata == NULL)
1277             omp->userdata = omudp;
1278         else
1279         {
1280             for (tmp = omp->userdata; tmp->next != NULL; tmp = tmp->next)
1281                 continue;
1282             tmp->next = omudp;
1283         }
1284     }
1285     else
1286     {
1287         omdp = ObjMgrFindByEntityID(omp, entityID, NULL);
1288         if (omdp == NULL)
1289             omudp = MemFree(omudp);
1290         else
1291         {
1292             if (omdp->userdata == NULL)
1293                 omdp->userdata = omudp;
1294             else
1295             {
1296                 for (tmp = omdp->userdata; tmp->next != NULL; tmp = tmp->next)
1297                     continue;
1298                 tmp->next = omudp;
1299 
1300             }
1301         }
1302     }
1303 
1304     ObjMgrUnlock();
1305     return omudp;
1306 }
1307 
1308 /*****************************************************************************
1309 *
1310 *   ObjMgrGetUserData(entityID, procid, proctype, userkey)
1311 *       Finds an OMUserData struct attached to entityID
1312 *       if entityID = 0, gets from the desktop
1313 *       returns NULL on failure
1314 *
1315 *****************************************************************************/
ObjMgrGetUserData(Uint2 entityID,Uint2 procid,Uint2 proctype,Uint2 userkey)1316 NLM_EXTERN OMUserDataPtr LIBCALL ObjMgrGetUserData (Uint2 entityID, Uint2 procid, Uint2 proctype, Uint2 userkey)
1317 {
1318     OMUserDataPtr omudp=NULL;
1319     ObjMgrPtr omp;
1320     ObjMgrDataPtr omdp;
1321 
1322     omp = ObjMgrReadLock();
1323 
1324     if (entityID == 0)
1325     {
1326         omudp = omp->userdata;
1327     }
1328     else
1329     {
1330         omdp = ObjMgrFindByEntityID(omp, entityID, NULL);
1331         if (omdp != NULL)
1332             omudp = omdp->userdata;
1333     }
1334 
1335     while (omudp != NULL)
1336     {
1337         if ((omudp->procid == procid) || (! procid))
1338         {
1339             if ((omudp->proctype == proctype) || (! proctype))
1340             {
1341                 if ((omudp->userkey == userkey) || (! userkey))
1342                     break;
1343             }
1344         }
1345         omudp = omudp->next;
1346     }
1347 
1348     ObjMgrUnlock();
1349     return omudp;
1350 }
1351 /*****************************************************************************
1352 *
1353 *   ObjMgrFreeUserData(entityID, procid, proctype, userkey)
1354 *       frees OMUserData attached to entityID by procid
1355 *       if procid ==0, frees all OMUserData of proctype
1356 *       if proctype ==0, matches any proctype
1357 *       if userkey == matches any userkey
1358 *       returns TRUE if any freed
1359 *
1360 *****************************************************************************/
ObjMgrFreeUserData(Uint2 entityID,Uint2 procid,Uint2 proctype,Uint2 userkey)1361 NLM_EXTERN Boolean LIBCALL ObjMgrFreeUserData (Uint2 entityID, Uint2 procid, Uint2 proctype, Uint2 userkey)
1362 {
1363     ObjMgrPtr omp;
1364     Boolean retval = FALSE;
1365 
1366     omp = ObjMgrWriteLock();
1367     retval = ObjMgrFreeUserDataFunc(omp, entityID, procid, proctype, userkey);
1368     ObjMgrUnlock();
1369     return retval;
1370 }
1371 
1372 /*****************************************************************************
1373 *
1374 *   ObjMgrFreeUserDataFunc(omp, entityID, procid, proctype, userkey)
1375 *       frees OMUserData attached to entityID by procid
1376 *       if procid ==0, frees all OMUserData of proctype
1377 *       if proctype ==0, matches any proctype
1378 *       if userkey == matches any userkey
1379 *       returns TRUE if any freed
1380 *
1381 *****************************************************************************/
ObjMgrFreeUserDataFunc(ObjMgrPtr omp,Uint2 entityID,Uint2 procid,Uint2 proctype,Uint2 userkey)1382 static Boolean NEAR ObjMgrFreeUserDataFunc (ObjMgrPtr omp, Uint2 entityID,
1383                                 Uint2 procid, Uint2 proctype, Uint2 userkey)
1384 {
1385     OMUserDataPtr omudp=NULL, prev, next;
1386     ObjMgrDataPtr omdp = NULL;
1387     Boolean got_one = FALSE, view_left;
1388     ObjMgrTypePtr omtp = NULL;
1389     Uint2 type, options;
1390     Pointer ptr;
1391     Boolean is_write_locked;
1392 
1393     options = omp->options;
1394 
1395     if (entityID == 0)
1396     {
1397         omudp = omp->userdata;
1398     }
1399     else
1400     {
1401         omdp = ObjMgrFindByEntityID(omp, entityID, NULL);
1402         if (omdp != NULL)
1403         {
1404             omudp = omdp->userdata;
1405             options = omdp->options;
1406         }
1407     }
1408 
1409     prev = NULL;
1410     view_left = FALSE;  /* assume nothing left to receive messages */
1411     while (omudp != NULL)
1412     {
1413         next = omudp->next;
1414         if ((omudp->procid == procid) || (! procid))
1415         {
1416             if ((omudp->proctype == proctype) || (! proctype))
1417             {
1418                 if ((omudp->userkey == userkey) || (! userkey))
1419                 {
1420                     got_one = TRUE;
1421                     if (prev == NULL)
1422                     {
1423                         if (entityID == 0)
1424                             omp->userdata = next;
1425                         else
1426                             omdp->userdata = next;
1427                     }
1428                     else
1429                         prev->next = next;
1430                     if (omudp->freefunc != NULL)
1431                         (* (omudp->freefunc))(omudp->userdata.ptrvalue);
1432                     omudp = MemFree(omudp);
1433                 }
1434             }
1435         }
1436         if (omudp != NULL)
1437         {
1438             prev = omudp;
1439             if (omudp->messagefunc != NULL) /* gets messages */
1440                 view_left = TRUE;
1441         }
1442         omudp = next;
1443     }
1444 
1445     if (options & OM_OPT_FREE_IF_NO_VIEW)  /* free data if no more views */
1446     {
1447         if ((got_one) && (! view_left) && (omdp != NULL))   /* no more views */
1448         {
1449             if (! omdp->being_freed)  /* being freed by ObjMgrDelete */
1450             {
1451                 if (omdp->choice != NULL)
1452                 {
1453                     type = omdp->choicetype;
1454                     ptr = omdp->choice;
1455                 }
1456                 else
1457                 {
1458                     type = omdp->datatype;
1459                     ptr = omdp->dataptr;
1460                 }
1461 
1462                 omtp = ObjMgrTypeFind(omp, type, NULL, NULL);
1463                 if (omtp != NULL)
1464                 {
1465                     omdp->being_freed = TRUE; /* flag not to call this func */
1466                     /* get rid of extra user data */
1467                     ObjMgrFreeUserDataFunc(omp, entityID, 0, 0, 0);
1468                     is_write_locked = omp->is_write_locked;
1469                     ObjMgrUnlock();
1470                     (*(omtp->freefunc))(ptr);
1471                     if (is_write_locked)
1472                         ObjMgrWriteLock();
1473                     else
1474                         ObjMgrReadLock();
1475                 }
1476             }
1477         }
1478     }
1479     return got_one;
1480 }
1481 
1482 
1483 
1484 /*****************************************************************************
1485 *
1486 *   ObjMgrLookup(omp, data)
1487 *       Binary lookup of data in omp->datalist
1488 *       returns index (>=0) if found
1489 *       returns -1 if not found
1490 *
1491 *****************************************************************************/
ObjMgrLookup(ObjMgrPtr omp,Pointer data)1492 NLM_EXTERN Int4 LIBCALL ObjMgrLookup(ObjMgrPtr omp, Pointer data)
1493 {
1494     Int4 imin, imax, i;
1495     ObjMgrDataPtr PNTR omdpp;
1496     unsigned long tmp, datai;
1497 
1498     imin = 0;
1499     imax = omp->currobj - 1;
1500     omdpp = omp->datalist;
1501 
1502     datai = (unsigned long)data;
1503 
1504     while (imax >= imin)
1505     {
1506         i = (imax + imin)/2;
1507         tmp = (unsigned long)(omdpp[i]->dataptr);
1508         if (tmp > datai)
1509             imax = i - 1;
1510         else if (tmp < datai)
1511             imin = i + 1;
1512         else
1513             return i;
1514     }
1515 
1516     return (Int4)(-1);
1517 }
1518 
1519 /*****************************************************************************
1520 *
1521 *   ObjMgrDelete(type, data)
1522 *       deletes a pointer (data) of type (type) to the sequence manager
1523 *
1524 *****************************************************************************/
ObjMgrDelete(Uint2 type,Pointer data)1525 NLM_EXTERN Boolean LIBCALL ObjMgrDelete (Uint2 type, Pointer data)
1526 {
1527     ObjMgrPtr omp;
1528     ObjMgrDataPtr omdp;
1529     ObjMgrDataPtr PNTR omdpp, PNTR to, PNTR from;
1530     Int4 i, j;
1531     Boolean retval = FALSE;
1532 
1533     omp = ObjMgrWriteLock();  /* really remove the entity */
1534     i = ObjMgrLookup(omp, data);  /* make sure it is still current */
1535     if (i < 0)  /* not found */
1536     {
1537        /***    may not be registered with objmgr ***
1538         ErrPostEx(SEV_ERROR, 0,0, "ObjMgrDelete: pointer [%ld] type [%d] not found",
1539             (long)data, (int)type);
1540         ***/
1541         goto erret;
1542     }
1543 
1544     omdpp = omp->datalist;
1545     omdp = omdpp[i];    /* emptys always at end */
1546 
1547     if (omdp == NULL) goto erret;
1548 
1549     if (omdp->EntityID != 0)
1550     {
1551         ObjMgrSendMsgFunc(omp, omdp, OM_MSG_DEL, omdp->EntityID, 0, 0, 0, 0, 0, NULL);
1552         ObjMgrDeSelectFunc(omp, omdp->EntityID,0,0,0,NULL);
1553         if (! omdp->being_freed)  /* ObjMgrFreeUserData can call delete */
1554         {
1555             omdp->being_freed = TRUE;  /* break cycle */
1556             ObjMgrFreeUserDataFunc(omp, omdp->EntityID, 0, 0, 0);
1557         }
1558     }
1559 
1560     if (omdp->clipboard)    /* update the clipboard */
1561         omp->clipboard = NULL;
1562 
1563     if (omdp->lockcnt)
1564         ErrPostEx(SEV_ERROR, 0,0,"ObjMgrDelete: deleting locked element");
1565     else if (omdp->tempload == TL_LOADED)
1566     {
1567         if (omp->tempcnt)
1568             omp->tempcnt--;
1569         else
1570             ErrPostEx(SEV_ERROR, 0,0, "ObjMgrDelete: reducing tempcnt below 0");
1571     }
1572 
1573     /* if (omdp->EntityID != 0 && omdp->EntityID == omp->HighestEntityID)
1574         omp->HighestEntityID--; */
1575     if (omdp->EntityID != 0)
1576         ObjMgrRecycleEntityID (omdp->EntityID, omp);
1577 
1578     ObjMgrDeleteIndexOnEntityID(omp,omdp->EntityID);
1579 
1580     if (omdp->extradata != NULL && omdp->freeextra != NULL) {
1581         omdp->freeextra ((Pointer) omdp);
1582     }
1583 
1584     if (omdp->bulkIndexFree) {
1585         ObjMgrUnlock(); /* if bulk free, delete at end of BioseqFree or BioseqSetFree */
1586         return TRUE;
1587     }
1588 
1589     MemSet((Pointer)omdp, 0, sizeof(ObjMgrData));
1590     if (omp->currobj)
1591         omp->currobj--;
1592     else
1593         ErrPostEx(SEV_ERROR, 0,0, "ObjMgrDelete: reducing currobj below 0");
1594     j = omp->currobj - i;
1595     if (j)
1596     {
1597         to = omdpp + i;
1598         from = to + 1;
1599         MemMove(to, from, (size_t)(sizeof(ObjMgrDataPtr) * j));
1600     }
1601     omdpp[omp->currobj] = omdp;  /* put in pointer to empty data space */
1602 
1603 #ifdef DEBUG_OBJMGR
1604     ObjMgrDump(NULL, "ObjMgrDelete");
1605 #endif
1606 
1607     retval = TRUE;
1608 erret:
1609     ObjMgrUnlock();
1610     return retval;
1611 }
1612 
1613 /*****************************************************************************
1614 *
1615 *   ObjMgrDeleteAllInRecord()
1616 *       deletes all omdp entries in a record
1617 *
1618 *****************************************************************************/
ObjMgrDeleteAllInRecord(void)1619 NLM_EXTERN Boolean LIBCALL ObjMgrDeleteAllInRecord (
1620   void
1621 )
1622 
1623 {
1624   Int4               i, j, k, num;
1625   ObjMgrDataPtr       omdp;
1626   ObjMgrDataPtr PNTR  omdpp;
1627   ObjMgrPtr           omp;
1628   ObjMgrDataPtr PNTR  tmp;
1629 
1630   omp = ObjMgrWriteLock ();
1631 
1632   if (omp != NULL) {
1633     omdpp = omp->datalist;
1634     if (omdpp != NULL) {
1635 
1636       num = omp->currobj;
1637       tmp = (ObjMgrDataPtr PNTR) MemNew (sizeof (ObjMgrDataPtr) * (size_t) (num + 1));
1638       if (tmp != NULL) {
1639 
1640         for (i = 0, j = 0, k = 0; i < num; i++) {
1641           omdp = omdpp [i];
1642           if (omdp != NULL && omdp->bulkIndexFree) {
1643             MemSet ((Pointer) omdp, 0, sizeof (ObjMgrData));
1644             tmp [k] = omdp;
1645             k++;
1646           } else {
1647             omdpp [j] = omdpp [i];
1648             j++;
1649           }
1650         }
1651         omp->currobj = j;
1652         MemMove (omdpp + j, tmp, sizeof (ObjMgrDataPtr) * (size_t) k);
1653       }
1654 
1655       MemFree (tmp);
1656     }
1657   }
1658 
1659   ObjMgrUnlock ();
1660 
1661   return TRUE;
1662 }
1663 
1664 /*****************************************************************************
1665 *
1666 *   ObjMgrGetClipBoard()
1667 *     returns ObjMgrDataPtr to current clipboard object or NULL if none
1668 *
1669 *****************************************************************************/
ObjMgrGetClipBoard(void)1670 NLM_EXTERN ObjMgrDataPtr LIBCALL ObjMgrGetClipBoard (void)
1671 {
1672     ObjMgrPtr omp;
1673 
1674     omp = ObjMgrReadLock();
1675     ObjMgrUnlock();
1676     return omp->clipboard;
1677 }
1678 
1679 /*****************************************************************************
1680 *
1681 *   ObjMgrAddToClipBoard(entityID, ptr)
1682 *       if entityID > 0, then uses it.
1683 *       else, looks up entityID using ptr
1684 *       adds entityID if needed
1685 *       sends OM_MSG_TO_CLIPBOARD
1686 *
1687 *       Anything in the clipboard is deleted
1688 *
1689 *****************************************************************************/
ObjMgrAddToClipBoard(Uint2 entityID,Pointer ptr)1690 NLM_EXTERN Boolean LIBCALL ObjMgrAddToClipBoard (Uint2 entityID, Pointer ptr)
1691 {
1692     ObjMgrPtr omp;
1693     ObjMgrDataPtr omdp;
1694     Boolean retval = FALSE;
1695 
1696     omp = ObjMgrWriteLock();
1697     if (! entityID)
1698     {
1699         omdp = ObjMgrFindByData(omp, ptr);
1700         if (omdp != NULL)
1701         {
1702             if (omdp->parentptr != NULL)
1703             {
1704                 ErrPostEx(SEV_ERROR,0,0,"AddToClipBoard: ParentPtr != NULL");
1705                 goto erret;
1706             }
1707             /* if (omdp->EntityID == 0)
1708                 omdp->EntityID = ++(omp->HighestEntityID); */
1709             if (omdp->EntityID == 0) {
1710                 omdp->EntityID = ObjMgrNextAvailEntityID (omp);
1711                 ObjMgrRecordOmdpByEntityID (omdp->EntityID, omdp);
1712             }
1713         }
1714     }
1715     else
1716     {
1717         omdp = ObjMgrFindByEntityID(omp, entityID, NULL);
1718     }
1719 
1720     if (omdp == NULL)
1721     {
1722         ErrPostEx(SEV_ERROR,0,0,"AddToClipBoard: data not found");
1723         goto erret;
1724     }
1725 
1726     ObjMgrFreeClipBoardFunc(omp);
1727 
1728     omdp->clipboard = TRUE;
1729     omp->clipboard = omdp;
1730 
1731     ObjMgrSendMsgFunc(omp, omdp, OM_MSG_TO_CLIPBOARD, omdp->EntityID, 0, 0, 0, 0, 0, NULL);
1732 
1733     retval = TRUE;
1734 erret:
1735     ObjMgrUnlock();
1736 
1737     return retval;
1738 }
1739 
1740 /*****************************************************************************
1741 *
1742 *   ObjMgrFreeClipBoard()
1743 *     clears any data from the clipboard
1744 *
1745 *****************************************************************************/
ObjMgrFreeClipBoard(void)1746 NLM_EXTERN Boolean LIBCALL ObjMgrFreeClipBoard (void)
1747 {
1748     ObjMgrPtr omp;
1749     Boolean retval;
1750 
1751     omp = ObjMgrWriteLock();
1752     retval = ObjMgrFreeClipBoardFunc(omp);
1753     ObjMgrUnlock();
1754     return retval;
1755 }
1756 
1757 /*****************************************************************************
1758 *
1759 *   ObjMgrFreeClipBoardFunc()
1760 *     clears any data from the clipboard
1761 *
1762 *****************************************************************************/
ObjMgrFreeClipBoardFunc(ObjMgrPtr omp)1763 static Boolean NEAR ObjMgrFreeClipBoardFunc (ObjMgrPtr omp)
1764 {
1765     ObjMgrTypePtr omtp;
1766     ObjMgrDataPtr omdp;
1767     Uint2 type;
1768     Pointer ptr;
1769 
1770     omdp = omp->clipboard;
1771     if (omdp == NULL) return TRUE;
1772 
1773     if (omdp->choice != NULL)
1774     {
1775         type = omdp->choicetype;
1776         ptr = omdp->choice;
1777     }
1778     else
1779     {
1780         type = omdp->datatype;
1781         ptr = omdp->dataptr;
1782     }
1783 
1784     omtp = ObjMgrTypeFind(omp, type, NULL, NULL);
1785     if (omtp == NULL)
1786     {
1787         ErrPostEx(SEV_ERROR,0,0,"ObjMgrFreeClipBoard: cant find type [%d]", (int)type);
1788         return FALSE;
1789     }
1790     else
1791         (*(omtp->freefunc))(ptr);
1792     ObjMgrDelete(omdp->datatype, omdp->dataptr);
1793     omp->clipboard = NULL;
1794     return TRUE;
1795 }
1796 /*****************************************************************************
1797 *
1798 *   ObjMgrConnect (type, data, parenttype, parentdata)
1799 *       Adds parent info to element
1800 *       Updates EntityID
1801 *           if both are 0, assigns it by incrementing HighestEntityID
1802 *           if one is 0, assigns it the other
1803 *           if neither is 0 and not the same ID
1804 *                assigns parent to child (and cascades to its children)
1805 *
1806 *****************************************************************************/
ObjMgrConnect(Uint2 type,Pointer data,Uint2 parenttype,Pointer parentdata)1807 NLM_EXTERN Boolean LIBCALL ObjMgrConnect (Uint2 type, Pointer data, Uint2 parenttype, Pointer parentdata)
1808 {
1809     ObjMgrPtr omp;
1810     Boolean retval = FALSE;
1811 
1812     omp = ObjMgrWriteLock();
1813     retval = ObjMgrConnectFunc(omp, type, data, parenttype, parentdata);
1814     ObjMgrUnlock();
1815     return retval;
1816 }
1817 
1818 /*****************************************************************************
1819 *
1820 *   ObjMgrConnectFunc (type, data, parenttype, parentdata)
1821 *       Adds parent info to element
1822 *       Updates EntityID
1823 *           if both are 0, assigns it by incrementing HighestEntityID
1824 *           if one is 0, assigns it the other
1825 *           if neither is 0 and not the same ID
1826 *                assigns parent to child (and cascades to its children)
1827 *
1828 *****************************************************************************/
ObjMgrConnectFunc(ObjMgrPtr omp,Uint2 type,Pointer data,Uint2 parenttype,Pointer parentdata)1829 NLM_EXTERN Boolean LIBCALL ObjMgrConnectFunc (ObjMgrPtr omp, Uint2 type, Pointer data, Uint2 parenttype, Pointer parentdata)
1830 {
1831     Int4 i;
1832     ObjMgrDataPtr omdp;
1833     Boolean retval = FALSE;
1834 
1835     i = ObjMgrLookup(omp, data);
1836     if (i < 0)  /* not found */
1837     {
1838         ErrPostEx(SEV_ERROR, 0,0, "ObjMgrConnect: pointer [%ld] type [%d] not found",
1839             (long)data, (int)type);
1840         goto erret;
1841     }
1842 
1843     omdp = omp->datalist[i];
1844 
1845     if ((omdp->EntityID != 0) && (parentdata != NULL))
1846     {                         /* registered type, inform any attached procs */
1847 
1848         ObjMgrSendMsgFunc(omp, omdp, OM_MSG_CONNECT, omdp->EntityID, 0, 0, 0, 0, 0, NULL);
1849         ObjMgrDeSelectFunc(omp, omdp->EntityID,0,0,0,NULL);
1850         ObjMgrFreeUserDataFunc(omp, omdp->EntityID, 0, 0, 0);
1851 
1852         /* if (omp->HighestEntityID == omdp->EntityID) {
1853             (omp->HighestEntityID)--;
1854         } */
1855         ObjMgrRecycleEntityID (omdp->EntityID, omp);
1856         ObjMgrDeleteIndexOnEntityID (omp, omdp->EntityID);
1857         omdp->EntityID = 0;   /* reset.. now has a parent */
1858     }
1859     omdp->parenttype = parenttype;
1860     omdp->parentptr = parentdata;
1861 
1862     if (parentdata != NULL)
1863     {
1864         i = ObjMgrLookup(omp, parentdata);
1865         if (i < 0)  /* not found */
1866         {
1867             ErrPostEx(SEV_ERROR, 0,0, "ObjMgrConnect: parent pointer [%ld] type [%d] not found",
1868                 (long)parentdata, (int)parenttype);
1869             goto erret;
1870         }
1871 
1872 
1873     }
1874 
1875 #ifdef DEBUG_OBJMGR
1876     ObjMgrDump(NULL, "ObjMgrConnect");
1877 #endif
1878     retval = TRUE;
1879 erret:
1880     return retval;
1881 }
1882 /*****************************************************************************
1883 *
1884 *   ObjMgrDetach (type, data)
1885 *       Removes parent info from element
1886 *       Adds to objmgr if necessary
1887 *       Does NOT register entity
1888 *
1889 *****************************************************************************/
ObjMgrDetach(Uint2 type,Pointer data)1890 NLM_EXTERN Boolean LIBCALL ObjMgrDetach (Uint2 type, Pointer data)
1891 {
1892     ObjMgrPtr omp;
1893     Boolean retval = FALSE;
1894 
1895     omp = ObjMgrWriteLock();
1896     retval = ObjMgrDetachFunc(omp, type, data);
1897     ObjMgrUnlock();
1898     return retval;
1899 }
1900 
1901 /*****************************************************************************
1902 *
1903 *   ObjMgrDetach (type, data)
1904 *       Removes parent info from element
1905 *       Adds to objmgr if necessary
1906 *       Does NOT register entity
1907 *
1908 *****************************************************************************/
ObjMgrDetachFunc(ObjMgrPtr omp,Uint2 type,Pointer data)1909 NLM_EXTERN Boolean LIBCALL ObjMgrDetachFunc (ObjMgrPtr omp, Uint2 type, Pointer data)
1910 {
1911     Int4 i;
1912     ObjMgrDataPtr omdp;
1913     Boolean retval = FALSE;
1914 
1915     i = ObjMgrLookup(omp, data);
1916     if (i < 0)  /* not found */
1917     {
1918         retval = ObjMgrAddFunc(omp, type, data);
1919         goto erret;
1920     }
1921 
1922     omdp = omp->datalist[i];
1923     if (omdp->parentptr == NULL)  /* not connected anyway */
1924         return TRUE;
1925 
1926     omdp->parenttype = 0;
1927     omdp->parentptr = NULL;
1928     ObjMgrDeleteIndexOnEntityID (omp, omdp->EntityID);
1929     omdp->EntityID = 0;   /* reset.. now has a parent */
1930 
1931     retval = TRUE;
1932 erret:
1933     return retval;
1934 }
1935 
1936 /*****************************************************************************
1937 *
1938 *   ObjMgrSetDirtyFlag (entityID, the_flag)
1939 *     record that an entity has been changed but not yet saved.
1940 *       the_flag sets or unsets this state
1941 *
1942 *****************************************************************************/
ObjMgrSetDirtyFlag(Uint2 entityID,Boolean the_flag)1943 NLM_EXTERN Boolean LIBCALL ObjMgrSetDirtyFlag (Uint2 entityID, Boolean the_flag)
1944 {
1945     ObjMgrPtr omp;
1946     ObjMgrDataPtr omdp;
1947     Boolean retval = FALSE;
1948 
1949     if (entityID <= 0) return FALSE;
1950 
1951     omp = ObjMgrWriteLock();
1952     omdp = ObjMgrFindByEntityID(omp, entityID, NULL);
1953     if (omdp != NULL)
1954     {
1955         omdp->dirty = the_flag;
1956         retval = TRUE;
1957     }
1958     ObjMgrUnlock();
1959     return retval;
1960 }
1961 
1962 /*****************************************************************************
1963 *
1964 *   ObjMgrGetDirtyFlag (entityID)
1965 *     returns the state of the dirty flag for entityID
1966 *
1967 *****************************************************************************/
ObjMgrGetDirtyFlag(Uint2 entityID)1968 NLM_EXTERN Boolean LIBCALL ObjMgrGetDirtyFlag (Uint2 entityID)
1969 {
1970     ObjMgrPtr omp;
1971     ObjMgrDataPtr omdp;
1972     Boolean retval = FALSE;
1973 
1974     if (entityID <= 0) return retval;
1975 
1976     omp = ObjMgrReadLock();
1977     omdp = ObjMgrFindByEntityID(omp, entityID, NULL);
1978     if (omdp != NULL)
1979         retval = omdp->dirty;
1980     ObjMgrUnlock();
1981     return retval;
1982 }
1983 
1984 /*****************************************************************************
1985 *
1986 *   ObjMgrSetChoice(type, choice, data)
1987 *       Adds the ValNodePtr pointing directly to this Bioseq or BioseqSet
1988 *
1989 *****************************************************************************/
ObjMgrSetChoice(Uint2 type,ValNodePtr choice,Pointer data)1990 NLM_EXTERN Boolean LIBCALL ObjMgrSetChoice (Uint2 type, ValNodePtr choice, Pointer data)
1991 {
1992     ObjMgrPtr omp;
1993     Int4 i;
1994     ObjMgrDataPtr omdp;
1995     Boolean retval = FALSE;
1996 
1997     omp = ObjMgrWriteLock();
1998 
1999     i = ObjMgrLookup(omp, data);
2000     if (i < 0)  /* not found */
2001     {
2002         ErrPostEx(SEV_ERROR, 0,0, "ObjMgrChoice: pointer [%ld] type [%d] not found",
2003             (long)data, (int)type);
2004         goto erret;
2005     }
2006 
2007     omdp = omp->datalist[i];
2008     omdp->choicetype = type;
2009     omdp->choice = choice;
2010     retval = TRUE;
2011 erret:
2012     ObjMgrUnlock();
2013 
2014 #ifdef DEBUG_OBJMGR
2015     ObjMgrDump(NULL, "ObjMgrChoice");
2016 #endif
2017 
2018     return retval;
2019 }
2020 
2021 /*****************************************************************************
2022 *
2023 *   ObjMgrFindTop(omp, omdp)
2024 *       finds the highest parent of omdp
2025 *       returns a ObjMgrDataPtr to the top
2026 *
2027 *****************************************************************************/
ObjMgrFindTop(ObjMgrPtr omp,ObjMgrDataPtr omdp)2028 NLM_EXTERN ObjMgrDataPtr LIBCALL ObjMgrFindTop (ObjMgrPtr omp, ObjMgrDataPtr omdp)
2029 {
2030     Int4 i;
2031 
2032     if ((omp == NULL) || (omdp == NULL)) return NULL;
2033 
2034     while (omdp->parentptr != NULL)
2035     {
2036         i = ObjMgrLookup(omp, omdp->parentptr);
2037         if (i < 0)  /* not found */
2038         {
2039             ErrPostEx(SEV_ERROR, 0,0, "ObjMgrFindTop: parentptr [%ld] not found",
2040                 (long)(omdp->parentptr));
2041             return NULL;
2042         }
2043         omdp = omp->datalist[i];
2044     }
2045 
2046     return omdp;
2047 }
2048 
2049 /*****************************************************************************
2050 *
2051 *   ObjMgrWholeEntity(omdp, itemID, itemtype)
2052 *        returns TRUE if itemID, itemtype identify a complete entity omdp
2053 *       returns FALSE if these are an internal part of the entity
2054 *
2055 *****************************************************************************/
ObjMgrWholeEntity(ObjMgrDataPtr omdp,Uint4 itemID,Uint2 itemtype)2056 NLM_EXTERN Boolean LIBCALL ObjMgrWholeEntity (ObjMgrDataPtr omdp, Uint4 itemID, Uint2 itemtype)
2057 {
2058     if (omdp == NULL)
2059         return FALSE;
2060 
2061     if ((itemID == 0) && (itemtype == 0))
2062         return TRUE;
2063 
2064     if ((itemID == 1) && (itemtype == omdp->datatype))
2065         return TRUE;
2066 
2067     return FALSE;
2068 
2069 }
2070 
2071 /*****************************************************************************
2072 *
2073 *   ObjMgrFreeCache(type)
2074 *       Frees all cached objects of type and subtypes of type
2075 *           based on ObjMgrMatch()
2076 *       if type == 0, frees all cached objects
2077 *       returns TRUE if no errors occurred
2078 *
2079 *****************************************************************************/
ObjMgrFreeCache(Uint2 type)2080 NLM_EXTERN Boolean LIBCALL ObjMgrFreeCache (Uint2 type)
2081 {
2082     ObjMgrPtr omp;
2083     Boolean more_to_go = TRUE;
2084     Uint2 rettype = 0;
2085     VoidPtr retval = NULL;
2086 
2087     while (more_to_go)
2088         {
2089            omp = ObjMgrWriteLock();
2090 /*
2091                 omp = ObjMgrReadLock ();
2092 */
2093                 more_to_go = ObjMgrFreeCacheFunc(omp, type, &rettype, &retval);
2094         if (more_to_go)
2095         {
2096             switch (rettype)
2097             {
2098             case OBJ_SEQENTRY:
2099                 SeqEntryFree((SeqEntryPtr)retval);
2100                 break;
2101             case OBJ_BIOSEQ:
2102                 BioseqFree((BioseqPtr)retval);
2103                 break;
2104             case OBJ_BIOSEQSET:
2105                 BioseqSetFree((BioseqSetPtr)retval);
2106                 break;
2107             default:
2108                 break;
2109             }
2110         }
2111         ObjMgrUnlock();
2112     }
2113 
2114         /*        if(type == 0)
2115                   omp->HighestEntityID = 0; */
2116 
2117     return TRUE;
2118 }
2119 
2120 /*****************************************************************************
2121 *
2122 *   ObjMgrFreeCacheFunc(type)
2123 *       Finds next cached objects of type and subtypes of type
2124 *           based on ObjMgrMatch()
2125 *       if type == 0, frees all cached objects
2126 *       if type == OBJ_MAX, frees unlocked cached objects
2127 *       returns TRUE if no more found
2128 *
2129 *****************************************************************************/
ObjMgrFreeCacheFunc(ObjMgrPtr omp,Uint2 type,Uint2Ptr rettype,VoidPtr PNTR retval)2130 static Boolean NEAR ObjMgrFreeCacheFunc (ObjMgrPtr omp, Uint2 type, Uint2Ptr rettype, VoidPtr PNTR retval)
2131 {
2132   Int4 i, num;
2133     ObjMgrDataPtr PNTR omdpp, omdp;
2134 
2135     if (omp->hold)   /* things are being held */
2136         return FALSE;   /* nothing to do, but send a warning */
2137 
2138     omdpp = omp->datalist;
2139     num = omp->currobj;
2140     for (i = 0; i < num; i++)
2141     {
2142         omdp = omdpp[i];
2143         if ((omdp->parentptr == NULL) &&     /* top level */
2144             (omdp->tempload == TL_CACHED ||   /* cached or */
2145             (type == 0 && omdp->tempload == TL_LOADED) ||   /* temp loaded but not cached out */
2146             (type == OBJ_MAX && omdp->tempload == TL_LOADED && omdp->lockcnt == 0)))   /* unlocked but not cached out */
2147         {
2148             if (type == 0 || type == OBJ_MAX ||
2149                 (ObjMgrMatch(type, omdp->datatype)) ||
2150                 (ObjMgrMatch(type, omdp->choicetype)))
2151             {
2152                 /** here is where the freefunc should be called **/
2153 
2154                 if (omdp->choice != NULL)
2155                 {
2156                     switch (omdp->choicetype)
2157                     {
2158                         case OBJ_SEQENTRY:
2159                             *rettype = omdp->choicetype;
2160                             *retval = omdp->choice;
2161                             return TRUE;
2162                         default:
2163                             ErrPostEx(SEV_ERROR,0,0, "ObjMgrFreeCache: unsupported choicetype[%d]",
2164                                 (int)(omdp->choicetype));
2165                             break;
2166                     }
2167                 }
2168                 else
2169                 {
2170                     switch(omdp->datatype)
2171                     {
2172                         case OBJ_BIOSEQ:
2173                         case OBJ_BIOSEQSET:
2174                             *rettype = omdp->datatype;
2175                             *retval = omdp->dataptr;
2176                             return TRUE;
2177                         default:
2178                             ErrPostEx(SEV_ERROR,0,0,"ObjMgrFreeCache: usupported datatype [%d]",
2179                                 (int)(omdp->datatype));
2180                             break;
2181                     }
2182                 }
2183             }
2184         }
2185     }
2186     return FALSE;
2187 
2188 }
2189 
2190 
2191 /*****************************************************************************
2192 *
2193 *   ObjMgrMatch(type1, type2)
2194 *       returns 0 if no match
2195 *       1 if identical
2196 *       2 if 2 is a subset of 1   (e.g. 1=OBJ_SEQENTRY, 2=BIOSEQ)
2197 *       current type1 that can have subtypes are:
2198 *           OBJ_SEQENTRY
2199 *           OBJ_PUB
2200 *           OBJ_SEQANNOT
2201 *           OBJ_SEQCODE_SET
2202 *           OBJ_GENETIC_CODE_SET
2203 *
2204 *****************************************************************************/
ObjMgrMatch(Uint2 type1,Uint2 type2)2205 NLM_EXTERN Int2 LIBCALL ObjMgrMatch (Uint2 type1, Uint2 type2)
2206 {
2207     if (type1 == type2)
2208         return 1;
2209 
2210     switch (type1)
2211     {
2212         case OBJ_SEQENTRY:
2213             switch (type2)
2214             {
2215                 case OBJ_BIOSEQ:
2216                 case OBJ_BIOSEQSET:
2217                     return 2;
2218             }
2219             break;
2220         case OBJ_SEQANNOT:
2221             switch (type2)
2222             {
2223                 case OBJ_SEQFEAT:
2224                 case OBJ_SEQALIGN:
2225                 case OBJ_SEQGRAPH:
2226                     return 2;
2227             }
2228             break;
2229         case OBJ_SEQCODE_SET:
2230             switch (type2)
2231             {
2232                 case OBJ_SEQCODE:
2233                     return 2;
2234             }
2235             break;
2236         case OBJ_GENETIC_CODE_SET:
2237             switch (type2)
2238             {
2239                 case OBJ_GENETIC_CODE:
2240                     return 2;
2241             }
2242             break;
2243         default:
2244             break;
2245     }
2246 
2247     return 0;
2248 }
2249 
2250 
2251 /*****************************************************************************
2252 *
2253 *   ObjMgrGetChoiceForData(data)
2254 *       returns ValNodePtr for a BioseqPtr or BioseqSetPtr
2255 *       choice must have been put in ObjMgr using ObjMgrChoice
2256 *       the Bioseq/BioseqSets it is a part of must also be in ObjMgr
2257 *       returns NULL on failure.
2258 *
2259 *****************************************************************************/
ObjMgrGetChoiceForData(Pointer data)2260 NLM_EXTERN ValNodePtr LIBCALL ObjMgrGetChoiceForData (Pointer data)
2261 {
2262     ObjMgrPtr omp;
2263     Int4 i;
2264     ValNodePtr choice = NULL;
2265 
2266     if (data == NULL) return choice;
2267     omp = ObjMgrReadLock();
2268     i = ObjMgrLookup(omp, data);
2269     if (i < 0)
2270     {
2271         ErrPostEx(SEV_ERROR, 0,0, "ChoiceGetChoiceForData: data not in ObjMgr");
2272     }
2273     else
2274     {
2275         choice = omp->datalist[i]->choice;
2276     }
2277     ObjMgrUnlock();
2278 
2279     return choice;
2280 }
2281 
2282 /*****************************************************************************
2283 *
2284 *   ObjMgrGetEntityIDForChoice(choice)
2285 *       returns the EntityID for a ValNodePtr
2286 *       choice must have been put in ObjMgr using ObjMgrChoice
2287 *       the Bioseq/BioseqSets it is a part of must also be in ObjMgr
2288 *       This function will move up to the top of the Choice tree it may be
2289 *          in. If top level EntityID is 0, one is assigned at this point.
2290 *       If an element is moved under a different hierarchy, its EntityID will
2291 *          change.
2292 *       returns 0 on failure.
2293 *
2294 *****************************************************************************/
ObjMgrGetEntityIDForChoice(ValNodePtr choice)2295 NLM_EXTERN Uint2 LIBCALL ObjMgrGetEntityIDForChoice (ValNodePtr choice)
2296 {
2297     Pointer data;
2298 
2299     if (choice == NULL) return 0;
2300     data = choice->data.ptrvalue;
2301     if (data == NULL) return 0;
2302 
2303     return ObjMgrGetEntityIDForPointer (data);
2304 }
2305 
2306 /*****************************************************************************
2307 *
2308 *   ObjMgrGetEntityIDForPointer(data)
2309 *       returns the EntityID for any pointer, Choice or Data
2310 *       This function will move up to the top of the tree it may be
2311 *          in. If top level EntityID is 0, one is assigned at this point.
2312 *       If an element is moved under a different hierarchy, its EntityID will
2313 *          change.
2314 *
2315 *       Either ObjMgrGetEntityIDForPointer() or ObjMgrGetEntityIDForChoice()
2316 *           MUST be called to have an OM_MSG_CREATE message sent to any
2317 *           registered proceedures
2318 *
2319 *       returns 0 on failure.
2320 *
2321 *****************************************************************************/
ObjMgrGetEntityIDForPointer(Pointer ptr)2322 NLM_EXTERN Uint2 LIBCALL ObjMgrGetEntityIDForPointer (Pointer ptr)
2323 {
2324     ObjMgrPtr omp;
2325     ObjMgrDataPtr omdp;
2326     Uint2 retval = 0;
2327 
2328     if (ptr == NULL)
2329         return retval;
2330 
2331     omp = ObjMgrWriteLock(); /* (EY) */
2332     omdp = ObjMgrFindByData(omp, ptr);
2333 
2334     if (omdp == NULL) goto erret;
2335 
2336     omdp = ObjMgrFindTop(omp, omdp);
2337     if (omdp == NULL) goto erret;
2338 
2339     if (omdp->EntityID == 0)     /* need to assign it */
2340         ObjMgrAddEntityID(omp, omdp);
2341 
2342     retval = omdp->EntityID;
2343 erret:
2344     ObjMgrUnlock();
2345 
2346     return retval;
2347 }
2348 
2349 /*****************************************************************************
2350 *
2351 *   ObjMgrGetChoiceForEntityID (id)
2352 *
2353 *****************************************************************************/
ObjMgrGetChoiceForEntityID(Uint2 id)2354 NLM_EXTERN ValNodePtr LIBCALL ObjMgrGetChoiceForEntityID (Uint2 id)
2355 {
2356     ObjMgrPtr omp;
2357     ObjMgrDataPtr omdp;
2358     ValNodePtr retval = NULL;
2359 
2360     if (id <= 0) return retval;
2361 
2362     omp = ObjMgrReadLock();
2363     omdp = ObjMgrFindByEntityID(omp, id, NULL);
2364     if (omdp != NULL)
2365         retval = omdp->choice;
2366     ObjMgrUnlock();
2367     return retval;
2368 }
2369 
2370 /*****************************************************************************
2371 *
2372 *   ObjMgrLock(type, data, lockit)
2373 *       if lockit=TRUE, locks the element
2374 *       else unlocks it
2375 *       returns the current lock count or -1 on failure
2376 *
2377 *****************************************************************************/
ObjMgrLock(Uint2 type,Pointer data,Boolean lockit)2378 NLM_EXTERN Int4 LIBCALL ObjMgrLock (Uint2 type, Pointer data, Boolean lockit)
2379 {
2380     ObjMgrPtr omp;
2381     Int4 retval = -1;
2382 
2383     omp = ObjMgrWriteLock();
2384     if (omp != NULL)
2385         retval = ObjMgrLockFunc(omp, type, data, lockit);
2386     ObjMgrUnlock();
2387     return retval;
2388 }
2389 
ObjMgrLockFunc(ObjMgrPtr omp,Uint2 type,Pointer data,Boolean lockit)2390 static Int4 NEAR ObjMgrLockFunc (ObjMgrPtr omp, Uint2 type, Pointer data, Boolean lockit)
2391 {
2392     Int4 i, lockcnt = -1;
2393     ObjMgrDataPtr omdp;
2394 
2395 #ifdef DEBUG_OBJMGR
2396     Char buf[80];
2397 #endif
2398 
2399     i = ObjMgrLookup(omp, data);
2400     if (i < 0)  /* not found */
2401     {
2402         ErrPostEx(SEV_ERROR, 0,0, "ObjMgrLock: pointer [%ld] type [%d] not found",
2403             (long)data, (int)type);
2404         return lockcnt;
2405     }
2406 
2407     omdp = ObjMgrFindTop(omp, omp->datalist[i]);
2408     if (omdp == NULL) {
2409       return lockcnt;
2410     }
2411 
2412     if (lockit) {
2413         omdp->lockcnt++;
2414 
2415         /******** desktop can do this *******
2416         if (omdp->tempload == TL_CACHED)
2417         {
2418             ErrPostEx(SEV_ERROR, 0,0,"ObjMgrLock: locking a cached entity");
2419         }
2420         *************************************/
2421     }
2422     else
2423     {
2424         if (omdp->lockcnt) {
2425             omdp->lockcnt--;
2426         }
2427         else
2428         {
2429             ErrPostEx(SEV_ERROR, 0,0,"ObjMgrLock: unlocking 0 lockcnt");
2430             return lockcnt;
2431         }
2432     }
2433 
2434     lockcnt = omdp->lockcnt;
2435 
2436     if (! lockit)     /* check for automatic delete */
2437     {
2438         if ((omdp->tempload != TL_NOT_TEMP) && (! omdp->lockcnt))
2439         {
2440             omdp->touch = ObjMgrTouchCnt();   /* stamp with time */
2441             /*
2442             omp->tempcnt++;
2443             */
2444             ObjMgrReap(omp);
2445         }
2446     }
2447 
2448 
2449 #ifdef DEBUG_OBJMGR
2450     if (lockit)
2451         sprintf(buf, "ObjMgrLock   Lock [%d]", (int)i);
2452     else
2453         sprintf(buf, "ObjMgrLock   Unlock [%d]", (int)i);
2454     ObjMgrDump(NULL, buf);
2455 #endif
2456 
2457     return lockcnt;
2458 }
2459 
2460 /*****************************************************************************
2461 *
2462 *   Boolean ObjMgrSetTempLoad (ObjMgrPtr omp, Pointer ptr)
2463 *   Sets a Loaded element to "temporary"
2464 *
2465 *****************************************************************************/
ObjMgrSetTempLoad(ObjMgrPtr omp,Pointer ptr)2466 NLM_EXTERN Boolean LIBCALL ObjMgrSetTempLoad (ObjMgrPtr omp, Pointer ptr)
2467 {
2468     Int4 index;
2469     ObjMgrDataPtr omdp;
2470 
2471     index = ObjMgrLookup(omp, ptr);
2472     if (index < 0) return FALSE;
2473 
2474     omdp = ObjMgrFindTop(omp, omp->datalist[index]);
2475     if (omdp == NULL) return FALSE;
2476 
2477     if (omdp->tempload == TL_NOT_TEMP)
2478     {
2479         omdp->tempload = TL_LOADED;
2480         omp->tempcnt++;
2481     }
2482     omdp->touch = ObjMgrTouchCnt();
2483 
2484     omdp->lockcnt++;    /* protect against reaping this one */
2485     ObjMgrReap (omp);   /* check to see if we need to reap */
2486     omdp->lockcnt--;    /* reset to previous state */
2487 
2488     return TRUE;
2489 }
2490 
2491 /*****************************************************************************
2492 *
2493 *   ObjMgrReap(omp)
2494 *       Checks to see if memory needs to be cleared, and does it
2495 *
2496 *****************************************************************************/
SortDitchArrayByTouchTime(VoidPtr vp1,VoidPtr vp2)2497 static int LIBCALLBACK SortDitchArrayByTouchTime (
2498   VoidPtr vp1,
2499   VoidPtr vp2
2500 )
2501 
2502 {
2503   ObjMgrDataPtr  omdpp1, omdpp2;
2504 
2505   if (vp1 == NULL || vp2 == NULL) return 0;
2506   omdpp1 = *((ObjMgrDataPtr PNTR) vp1);
2507   omdpp2 = *((ObjMgrDataPtr PNTR) vp2);
2508   if (omdpp1 == NULL || omdpp2 == NULL) return 0;
2509 
2510   if (omdpp1->touch > omdpp2->touch) return 1;
2511   if (omdpp1->touch < omdpp2->touch) return -1;
2512 
2513   return 0;
2514 }
2515 
ObjMgrReap(ObjMgrPtr omp)2516 NLM_EXTERN Boolean LIBCALL ObjMgrReap (ObjMgrPtr omp)
2517 {
2518     Uint4 lowest;
2519     Int4 num, j;
2520     Uint2 tempcnt, i, k;
2521     ObjMgrDataPtr tmp, ditch, PNTR omdpp, PNTR ditcharray;
2522     Boolean is_write_locked, did_one = FALSE;
2523 
2524     if (omp->hold)      /* keep all tempload records around while hold is on */
2525         return FALSE;
2526 
2527     if (omp->reaping)   /* protect against recursion caused by ObjMgrSendMsg */
2528         return FALSE;
2529 
2530     tempcnt = 0;
2531     num = omp->currobj;
2532     omdpp = omp->datalist;
2533     for (j = 0; j < num; j++, omdpp++)
2534     {
2535         tmp = *omdpp;
2536         if ((tmp->tempload == TL_LOADED) && (! tmp->lockcnt))
2537         {
2538             tempcnt++;
2539         }
2540     }
2541 
2542     if (tempcnt <= omp->maxtemp) return TRUE;
2543 
2544     /* faster version */
2545 
2546     ditcharray = (ObjMgrDataPtr PNTR) MemNew (sizeof (ObjMgrDataPtr) * (tempcnt + 1));
2547     if (ditcharray != NULL) {
2548 
2549         tempcnt = 0;
2550         num = omp->currobj;
2551         omdpp = omp->datalist;
2552         for (j = 0; j < num; j++, omdpp++) {
2553             tmp = *omdpp;
2554             if ((tmp->tempload == TL_LOADED) && (! tmp->lockcnt)) {
2555                 ditcharray [(int) tempcnt] = tmp;
2556                 tempcnt++;
2557             }
2558         }
2559 
2560         StableMergeSort (ditcharray, (size_t) tempcnt, sizeof (ObjMgrDataPtr), SortDitchArrayByTouchTime);
2561 
2562         for (i = 0, k = tempcnt; i < tempcnt && k > omp->maxtemp; i++, k--) {
2563             ditch = ditcharray [(int) i];
2564             if (ditch == NULL) continue;
2565 
2566             omp->reaping = TRUE;
2567             ditch->tempload = TL_CACHED;
2568             ObjMgrSendMsgFunc(omp, ditch, OM_MSG_CACHED, ditch->EntityID, 0, 0, 0, 0, 0, NULL);
2569             omp->tempcnt--;
2570             is_write_locked = omp->is_write_locked;
2571 
2572             /* null out feature pointers in seqmgr feature indices via reap function */
2573 
2574             if (ditch->extradata != NULL && ditch->reapextra != NULL) {
2575                 ditch->reapextra ((Pointer) ditch);
2576             }
2577 
2578             if (ditch->choice != NULL) {
2579                 switch (ditch->choicetype) {
2580                     case OBJ_SEQENTRY:
2581                         did_one = TRUE;
2582                         ObjMgrUnlock();
2583                         SeqEntryFreeComponents(ditch->choice);
2584                         break;
2585                     default:
2586                         ErrPostEx(SEV_ERROR,0,0,"ObjMgrReap: ditching unknown type");
2587                         break;
2588                 }
2589             } else {
2590                 switch (ditch->datatype) {
2591                     case OBJ_BIOSEQ:
2592                         did_one = TRUE;
2593                         ObjMgrUnlock();
2594                         BioseqFreeComponents((BioseqPtr)(ditch->dataptr));
2595                         break;
2596                     case OBJ_BIOSEQSET:
2597                         did_one = TRUE;
2598                           ObjMgrUnlock();
2599                         BioseqSetFreeComponents((BioseqSetPtr)(ditch->dataptr), FALSE);
2600                         break;
2601                     default:
2602                         ErrPostEx(SEV_ERROR,0,0,"ObjMgrReap: ditching unknown type");
2603                         break;
2604                 }
2605             }
2606 
2607             if (did_one) {
2608                 if (is_write_locked) {
2609                     omp = ObjMgrWriteLock();
2610                 } else {
2611                     omp = ObjMgrReadLock();
2612                 }
2613             }
2614 
2615             omp->reaping = FALSE;
2616         }
2617 
2618         MemFree (ditcharray);
2619         return TRUE;
2620     }
2621 
2622     /* otherwise fall through to old less efficient code */
2623 
2624     while (/* omp-> */ tempcnt > omp->maxtemp)   /* time to reap */
2625     {
2626         lowest = UINT4_MAX;
2627 
2628         tempcnt = 0;
2629         num = omp->currobj;
2630         omdpp = omp->datalist;
2631         ditch = NULL;
2632         for (j = 0; j < num; j++, omdpp++)
2633         {
2634             tmp = *omdpp;
2635             if ((tmp->tempload == TL_LOADED) && (! tmp->lockcnt))
2636             {
2637                 tempcnt++;
2638                 if (lowest > tmp->touch)
2639                 {
2640                     lowest = tmp->touch;
2641                     ditch = tmp;
2642                 }
2643             }
2644         }
2645         if (ditch == NULL)    /* nothing to free */
2646             return FALSE;
2647 
2648         omp->reaping = TRUE;
2649         ditch->tempload = TL_CACHED;
2650         ObjMgrSendMsgFunc(omp, ditch, OM_MSG_CACHED, ditch->EntityID, 0, 0, 0, 0, 0, NULL);
2651         omp->tempcnt--;
2652         tempcnt--;
2653         is_write_locked = omp->is_write_locked;
2654 
2655         /* null out feature pointers in seqmgr feature indices via reap function */
2656 
2657         if (ditch->extradata != NULL && ditch->reapextra != NULL) {
2658             ditch->reapextra ((Pointer) ditch);
2659         }
2660 
2661         if (ditch->choice != NULL)
2662         {
2663             switch (ditch->choicetype)
2664             {
2665                 case OBJ_SEQENTRY:
2666                     did_one = TRUE;
2667                     ObjMgrUnlock();
2668                     SeqEntryFreeComponents(ditch->choice);
2669                     break;
2670             }
2671         }
2672         else
2673         {
2674             switch (ditch->datatype)
2675             {
2676                 case OBJ_BIOSEQ:
2677                     did_one = TRUE;
2678                     ObjMgrUnlock();
2679                     BioseqFreeComponents((BioseqPtr)(ditch->dataptr));
2680                     break;
2681                 case OBJ_BIOSEQSET:
2682                     did_one = TRUE;
2683                     ObjMgrUnlock();
2684                     BioseqSetFreeComponents((BioseqSetPtr)(ditch->dataptr), FALSE);
2685                     break;
2686                 default:
2687                     ErrPostEx(SEV_ERROR,0,0,"ObjMgrUnlock: ditching unknown type");
2688                     break;
2689             }
2690         }
2691 
2692         if (did_one)
2693         {
2694             if (is_write_locked)
2695                 omp = ObjMgrWriteLock();
2696             else
2697                 omp = ObjMgrReadLock();
2698         }
2699 
2700         omp->reaping = FALSE;
2701 
2702 #ifdef DEBUG_OBJMGR
2703     ObjMgrDump(NULL, "ObjMgrReap");
2704 #endif
2705 
2706     }
2707 
2708     return TRUE;
2709 }
2710 
2711 /*****************************************************************************
2712 *
2713 *   ObjMgrReapOne(omp)
2714 *       Reaps the single least recently accessed entity
2715 *
2716 *****************************************************************************/
ObjMgrReapOne(ObjMgrPtr omp)2717 NLM_EXTERN Boolean LIBCALL ObjMgrReapOne (ObjMgrPtr omp)
2718 {
2719     Uint4 lowest;
2720     Int4 num, j;
2721     ObjMgrDataPtr tmp, ditch, PNTR omdpp;
2722     Boolean is_write_locked, did_one = FALSE;
2723 
2724     if (omp->hold)      /* keep all tempload records around while hold is on */
2725         return FALSE;
2726 
2727     if (omp->reaping)   /* protect against recursion caused by ObjMgrSendMsg */
2728         return FALSE;
2729 
2730         lowest = UINT4_MAX;
2731 
2732         num = omp->currobj;
2733         omdpp = omp->datalist;
2734         ditch = NULL;
2735         for (j = 0; j < num; j++, omdpp++)
2736         {
2737             tmp = *omdpp;
2738             if ((tmp->tempload == TL_LOADED) && (! tmp->lockcnt))
2739             {
2740                 if (lowest > tmp->touch)
2741                 {
2742                     lowest = tmp->touch;
2743                     ditch = tmp;
2744                 }
2745             }
2746         }
2747         if (ditch == NULL)    /* nothing to free */
2748             return FALSE;
2749 
2750         omp->reaping = TRUE;
2751         ditch->tempload = TL_CACHED;
2752         ObjMgrSendMsgFunc(omp, ditch, OM_MSG_CACHED, ditch->EntityID, 0, 0, 0, 0, 0, NULL);
2753         omp->tempcnt--;
2754         is_write_locked = omp->is_write_locked;
2755 
2756         /* null out feature pointers in seqmgr feature indices via reap function */
2757 
2758         if (ditch->extradata != NULL && ditch->reapextra != NULL) {
2759             ditch->reapextra ((Pointer) ditch);
2760         }
2761 
2762         if (ditch->choice != NULL)
2763         {
2764             switch (ditch->choicetype)
2765             {
2766                 case OBJ_SEQENTRY:
2767                     did_one = TRUE;
2768                     ObjMgrUnlock();
2769                     SeqEntryFreeComponents(ditch->choice);
2770                     break;
2771             }
2772         }
2773         else
2774         {
2775             switch (ditch->datatype)
2776             {
2777                 case OBJ_BIOSEQ:
2778                     did_one = TRUE;
2779                     ObjMgrUnlock();
2780                     BioseqFreeComponents((BioseqPtr)(ditch->dataptr));
2781                     break;
2782                 case OBJ_BIOSEQSET:
2783                     did_one = TRUE;
2784                     ObjMgrUnlock();
2785                     BioseqSetFreeComponents((BioseqSetPtr)(ditch->dataptr), FALSE);
2786                     break;
2787                 default:
2788                     ErrPostEx(SEV_ERROR,0,0,"ObjMgrUnlock: ditching unknown type");
2789                     break;
2790             }
2791         }
2792 
2793         if (did_one)
2794         {
2795             if (is_write_locked)
2796                 omp = ObjMgrWriteLock();
2797             else
2798                 omp = ObjMgrReadLock();
2799         }
2800 
2801         omp->reaping = FALSE;
2802 
2803 #ifdef DEBUG_OBJMGR
2804     ObjMgrDump(NULL, "ObjMgrReapOne");
2805 #endif
2806 
2807     return TRUE;
2808 }
2809 
2810 /*****************************************************************************
2811 *
2812 *   Boolean ObjMgrIsTemp(data)
2813 *       returns TRUE if data is a temporarily loaded item
2814 *       data must be BioseqPtr or BioseqSetPtr
2815 *
2816 *****************************************************************************/
ObjMgrIsTemp(Pointer data)2817 NLM_EXTERN Boolean LIBCALL ObjMgrIsTemp (Pointer data)
2818 {
2819     ObjMgrPtr omp;
2820     Int4 i;
2821     ObjMgrDataPtr omdp;
2822     Boolean retval = FALSE;
2823 
2824     omp = ObjMgrReadLock();
2825 
2826     i = ObjMgrLookup(omp, data);
2827     if (i < 0)  /* not found */
2828     {
2829         ErrPostEx(SEV_ERROR, 0,0, "ObjMgrIsTemp: pointer [%ld] not found",
2830             (long)data);
2831         goto erret;
2832     }
2833 
2834     omdp = ObjMgrFindTop(omp, omp->datalist[i]);
2835     if (omdp == NULL) goto erret;
2836 
2837     if (omdp->tempload != TL_NOT_TEMP)
2838         retval = TRUE;
2839 erret:
2840     ObjMgrUnlock();
2841     return retval;
2842 }
2843 
2844 /*****************************************************************************
2845 *
2846 *   Boolean ObjMgrIsParent(parent, child)
2847 *       returns TRUE if child is a child of parent
2848 *       if parent = NULL, returns TRUE if child has no parent
2849 *       child must never be NULL
2850 *       returns TRUE if they are the equal
2851 *       data must be BioseqPtr or BioseqSetPtr
2852 *
2853 *****************************************************************************/
ObjMgrIsChild(Pointer parent,Pointer child)2854 NLM_EXTERN Boolean LIBCALL ObjMgrIsChild (Pointer parent, Pointer child)
2855 {
2856     ObjMgrPtr omp;
2857     Int4 i;
2858     ObjMgrDataPtr omdp, PNTR omdpp;
2859     Boolean retval = FALSE;
2860 
2861     if (child == NULL) return FALSE;
2862     if (parent == child) return TRUE;
2863 
2864     omp = ObjMgrReadLock();
2865     omdpp = omp->datalist;
2866 
2867     i = ObjMgrLookup(omp, child);
2868     if (i < 0)  /* not found */
2869     {
2870         ErrPostEx(SEV_ERROR, 0,0, "ObjMgrIsChild: pointer [%ld] not found",
2871             (long)child);
2872         goto erret;
2873     }
2874 
2875     omdp = omdpp[i];
2876     if (parent == NULL)
2877     {
2878         if (omdp->parentptr == NULL)
2879             retval = TRUE;
2880         goto erret;
2881     }
2882 
2883     while (omdp->parentptr != NULL)
2884     {
2885         if (omdp->parentptr == parent)
2886         {
2887             retval = TRUE;
2888             goto erret;
2889         }
2890         i = ObjMgrLookup(omp, omdp->parentptr);
2891         if (i < 0)
2892             goto erret;
2893         omdp = omdpp[i];
2894     }
2895 erret:
2896     ObjMgrUnlock();
2897     return retval;
2898 }
2899 
2900 /*****************************************************************************
2901 *
2902 *   ObjMgrDump(fp)
2903 *
2904 *****************************************************************************/
2905 
ObjMgrDump(FILE * fp,CharPtr title)2906 NLM_EXTERN void LIBCALL ObjMgrDump (FILE * fp, CharPtr title)
2907 {
2908     ObjMgrPtr omp;
2909     ObjMgrDataPtr omdp;
2910     Uint4 i;
2911     Char buf[128];
2912     BioseqPtr bsp;
2913     Boolean close_it = FALSE;
2914 
2915     if (fp == NULL)
2916     {
2917         fp = FileOpen("ObjMgr.log", "a");
2918         close_it = TRUE;
2919     }
2920 
2921     omp = ObjMgrGet();
2922     fprintf(fp, "\n%s currobj=%d tempcnt=%d\n", title, (int)(omp->currobj),
2923         (int)(omp->tempcnt));
2924     for (i = 0; i < omp->currobj; i++)
2925     {
2926         omdp = omp->datalist[i];
2927         fprintf(fp, "[%d] [%d %d %ld] [%d %ld] %ld (%d) %ud\n", (int)i,
2928             (int)omdp->EntityID, (int)(omdp->datatype),
2929             (long)(omdp->dataptr), (int)(omdp->parenttype),
2930             (long)(omdp->parentptr), (long)(omdp->choice), (int)(omdp->lockcnt),
2931             (omdp->touch));
2932         if ((omdp->datatype == OBJ_BIOSEQ) && (omdp->dataptr != NULL))
2933         {
2934             bsp = (BioseqPtr)(omdp->dataptr);
2935             SeqIdWrite(bsp->id, buf, PRINTID_FASTA_LONG, sizeof (buf));
2936             fprintf(fp, "[%s %ld]\n", buf, (long)(bsp));
2937         }
2938     }
2939 
2940     if (close_it)
2941         FileClose(fp);
2942     return;
2943 }
2944 
2945 /*****************************************************************************
2946 *
2947 *   Procedure Management Functions
2948 *
2949 *****************************************************************************/
2950 
2951 
2952 /*****************************************************************************
2953 *
2954 *   ObjMgrProcExtend(omp)
2955 *
2956 *****************************************************************************/
ObjMgrProcExtend(ObjMgrPtr omp)2957 static Boolean NEAR ObjMgrProcExtend (ObjMgrPtr omp)
2958 {
2959     Boolean result = FALSE;
2960     OMProcPtr omdp, prev=NULL;
2961     ObjMgrProcPtr PNTR tmp;
2962     Int4 i, j;
2963 
2964     for (omdp = omp->ncbiproc; omdp != NULL; omdp = omdp->next)
2965         prev = omdp;
2966 
2967     omdp = (OMProcPtr)MemNew(sizeof(OMProc));
2968     if (omdp == NULL) return result;
2969     tmp = (ObjMgrProcPtr PNTR)MemNew((size_t)(sizeof(ObjMgrProcPtr) * (omp->totproc + NUM_OMD)));
2970     if (tmp == NULL)
2971     {
2972         MemFree(omdp);
2973         return result;
2974     }
2975 
2976     if (prev != NULL)
2977     {
2978         prev->next = omdp;
2979         MemMove(tmp, omp->proclist, (size_t)(sizeof(ObjMgrProcPtr) *omp->totproc));
2980         MemFree(omp->proclist);
2981     }
2982     else
2983         omp->ncbiproc = omdp;
2984 
2985     j = omp->totproc;
2986 
2987     for (i = 0; i < NUM_OMD; i++, j++)
2988         tmp[j] = &(omdp->data[i]);
2989 
2990     omp->totproc += NUM_OMD;
2991     omp->proclist = tmp;
2992 
2993     result = TRUE;
2994     return result;
2995 }
2996 
2997 /*****************************************************************************
2998 *
2999 *   ObjMgrProcAdd(data, priority)
3000 *       adds an ObjMgrProc at given priority
3001 *        priority must be > 0
3002 *       highest priority function is called first.
3003 *       if priority == 0 (default)
3004 *           gets the next highest priority over previous procs of same type
3005 *       if priority == PROC_PRIORITY_HIGHEST
3006 *           is always the highest priority (first one wins)
3007 *       if priority == PROC_PRIORITY_LOWEST
3008 *           is always the lowest priority
3009 *
3010 *****************************************************************************/
ObjMgrProcAdd(ObjMgrProcPtr data,Int2 priority)3011 NLM_EXTERN Uint2  LIBCALL ObjMgrProcAdd (ObjMgrProcPtr data, Int2 priority)
3012 {
3013     ObjMgrPtr omp;
3014     ObjMgrProcPtr omdp;
3015     ObjMgrProcPtr PNTR omdpp;
3016     Int4 i;
3017     Uint2 procID;
3018     Uint2 retval = 0;
3019 
3020     omp = ObjMgrWriteLock();
3021 
3022     if (priority == 0)   /* set to next highest */
3023     {
3024         omdp = ObjMgrProcFindNext(omp, data->proctype, data->inputtype,
3025                                 data->outputtype, NULL);
3026         if (omdp != NULL)
3027             priority = omdp->priority + 10;
3028     }
3029 
3030 
3031     if (omp->currproc >= omp->totproc)
3032     {
3033         if (! ObjMgrProcExtend(omp))
3034             goto erret;
3035     }
3036 
3037     i = omp->currproc;
3038     omdpp = omp->proclist;
3039     omdp = omdpp[i];    /* emptys always at end */
3040 
3041     omp->currproc++;     /* got one more */
3042     procID = ++(omp->HighestProcID);
3043 
3044     MemMove(omdp, data, sizeof(ObjMgrProc));
3045     omdp->priority = priority;
3046     omdp->procid = procID;  /* fill in the values */
3047     omdp->proclabel = StringSave(data->proclabel);
3048     omdp->procname = StringSave(data->procname);
3049     omdp->submenu = StringSave(data->submenu);
3050     retval = procID;
3051 erret:
3052     ObjMgrUnlock();
3053 
3054     return retval;
3055 }
3056 
3057 /*****************************************************************************
3058 *
3059 *   ObjMgrProcLoadEx(proctype, procname, proclabel, inputtype, subinputtype,
3060 *              outputtype, suboutputtype,
3061 *                   data, func, priority, submenu)
3062 *       adds a new proceedure with these parameters
3063 *       returns the procid
3064 *       if a procedure of the same name and type are already loaded
3065 *           returns the procid of the loaded proc.. does not reload
3066 *
3067 *****************************************************************************/
ObjMgrProcLoadEx(Uint2 proctype,CharPtr procname,CharPtr proclabel,Uint2 inputtype,Uint2 subinputtype,Uint2 outputtype,Uint2 suboutputtype,Pointer userdata,ObjMgrGenFunc func,Int2 priority,CharPtr submenu)3068 NLM_EXTERN Uint2 ObjMgrProcLoadEx (Uint2 proctype, CharPtr procname, CharPtr proclabel,
3069                             Uint2 inputtype, Uint2 subinputtype,
3070                             Uint2 outputtype, Uint2 suboutputtype, Pointer userdata,
3071                             ObjMgrGenFunc func, Int2 priority, CharPtr submenu)
3072 {
3073     ObjMgrPtr omp;
3074     ObjMgrProcPtr ompp;
3075     ObjMgrProc ompd;
3076 
3077     omp = ObjMgrWriteLock();
3078     ompp = ObjMgrProcFind(omp, 0, procname, proctype);
3079     ObjMgrUnlock();
3080     if (ompp != NULL)  /* already enabled */
3081     {
3082         return ompp->procid;
3083     }
3084 
3085     ompp = &ompd;
3086     MemSet((Pointer)ompp, 0, sizeof(ObjMgrProc));
3087 
3088     ompp->proctype = proctype;
3089     ompp->procname = procname;
3090     ompp->proclabel = proclabel;
3091     ompp->inputtype = inputtype;
3092     ompp->subinputtype = subinputtype;
3093     ompp->outputtype = outputtype;
3094     ompp->suboutputtype = suboutputtype;
3095     ompp->procdata = userdata;
3096     ompp->func = func;
3097     ompp->submenu = submenu;
3098 
3099     return ObjMgrProcAdd(ompp, priority); /* order determines priority */
3100 
3101 }
3102 
3103 /*****************************************************************************
3104 *
3105 *   ObjMgrProcLoad(proctype, procname, proclabel, inputtype, subinputtype,
3106 *              outputtype, suboutputtype,
3107 *                   data, func, priority)
3108 *       adds a new proceedure with these parameters
3109 *       returns the procid
3110 *       if a procedure of the same name and type are already loaded
3111 *           returns the procid of the loaded proc.. does not reload
3112 *
3113 *****************************************************************************/
ObjMgrProcLoad(Uint2 proctype,CharPtr procname,CharPtr proclabel,Uint2 inputtype,Uint2 subinputtype,Uint2 outputtype,Uint2 suboutputtype,Pointer userdata,ObjMgrGenFunc func,Int2 priority)3114 NLM_EXTERN Uint2 ObjMgrProcLoad (Uint2 proctype, CharPtr procname, CharPtr proclabel,
3115                             Uint2 inputtype, Uint2 subinputtype,
3116                             Uint2 outputtype, Uint2 suboutputtype, Pointer userdata,
3117                             ObjMgrGenFunc func, Int2 priority)
3118 
3119 {
3120     return ObjMgrProcLoadEx (proctype, procname, proclabel, inputtype, subinputtype,
3121                             outputtype, suboutputtype, userdata, func, priority, NULL);
3122 }
3123 
3124 /*****************************************************************************
3125 *
3126 *   ObjMgrProcLookup(omp, procid)
3127 *       these are currently just stored in order
3128 *       returns index (>=0) if found
3129 *       returns -1 if not found
3130 *
3131 *****************************************************************************/
ObjMgrProcLookup(ObjMgrPtr omp,Uint2 procid)3132 NLM_EXTERN Int4 LIBCALL ObjMgrProcLookup(ObjMgrPtr omp, Uint2 procid)
3133 {
3134     if (omp == NULL)
3135         return (Int4)(-1);
3136 
3137     if (procid)
3138         return (Int4)(procid - 1);
3139     else
3140         return (Int4)(-1);
3141 }
3142 
3143 /*****************************************************************************
3144 *
3145 *   ObjMgrProcFind(omp, procid, procname, proctype)
3146 *       if procid != NULL looks for it
3147 *       else matches on procname and proctype
3148 *           proctype = 0, matches all proctypes
3149 *
3150 *****************************************************************************/
ObjMgrProcFind(ObjMgrPtr omp,Uint2 procid,CharPtr procname,Uint2 proctype)3151 NLM_EXTERN ObjMgrProcPtr LIBCALL ObjMgrProcFind(ObjMgrPtr omp, Uint2 procid,
3152                                         CharPtr procname, Uint2 proctype)
3153 {
3154     ObjMgrProcPtr ompp=NULL, PNTR omppp, tmp;
3155     Int4 i, imax;
3156 
3157     omppp = omp->proclist;
3158     imax = omp->currproc;
3159 
3160     if (procid)   /* procid lookup is different */
3161     {
3162         i = ObjMgrProcLookup(omp, procid);
3163         if (i >= 0)
3164             ompp = omppp[i];
3165         return ompp;
3166     }
3167 
3168     for (i = 0; i < imax; i++)
3169     {
3170         tmp = omppp[i];
3171         if ((! proctype) || (proctype == tmp->proctype))
3172         {
3173             if (! StringCmp(procname, tmp->procname))
3174                 return tmp;
3175         }
3176     }
3177     return ompp;
3178 }
3179 
3180 /*****************************************************************************
3181 *
3182 *   ObjMgrGetProcID(omp, procname, proctype)
3183 *       returns procid given procname and proctype
3184 *
3185 *****************************************************************************/
ObjMgrGetProcID(ObjMgrPtr omp,CharPtr procname,Uint2 proctype)3186 NLM_EXTERN Uint2 LIBCALL ObjMgrGetProcID (ObjMgrPtr omp, CharPtr procname, Uint2 proctype)
3187 
3188 {
3189     ObjMgrProcPtr  ompp;
3190 
3191     ompp = ObjMgrProcFind (omp, 0, procname, proctype);
3192     if (ompp == NULL) return 0;
3193     return ompp->procid;
3194 }
3195 
3196 /*****************************************************************************
3197 *
3198 *   ObjMgrProcFindNext(omp, proctype, inputtype, outputtype, last)
3199 *       looks for proctype of highest priority that
3200 *           matches inputtype and outputtype
3201 *       0 on proctype or inputtype or outputtype matches any
3202 *       if last != NULL, then gets next after last
3203 *       if omp == NULL, will ObjMgrReadLock() and Unlock() within the function
3204 *
3205 *****************************************************************************/
ObjMgrProcFindNext(ObjMgrPtr tomp,Uint2 proctype,Uint2 inputtype,Uint2 outputtype,ObjMgrProcPtr last)3206 NLM_EXTERN ObjMgrProcPtr LIBCALL ObjMgrProcFindNext (ObjMgrPtr tomp, Uint2 proctype,
3207                         Uint2 inputtype, Uint2 outputtype, ObjMgrProcPtr last)
3208 {
3209     ObjMgrPtr omp;
3210     ObjMgrProcPtr best = NULL, tmp, retval = NULL;
3211     Int4 i, bestpriority=-32766, imax, maxpriority=32767;
3212     ObjMgrProcPtr PNTR omppp;
3213     Boolean unlock = FALSE;
3214 
3215     if (tomp == NULL)
3216     {
3217         omp = ObjMgrReadLock();
3218         unlock = TRUE;
3219     }
3220     else
3221         omp = tomp;
3222 
3223     omppp = omp->proclist;
3224     imax = omp->currproc;
3225 
3226     if (last != NULL)
3227     {
3228         maxpriority = last->priority;
3229         i = ObjMgrProcLookup(omp, last->procid);
3230         i++;
3231         while (i < imax)  /* find next of equal priority */
3232         {
3233             tmp = omppp[i];
3234             if ((! proctype) || (tmp->proctype == proctype))
3235             {
3236                 if ((! inputtype) || (tmp->inputtype == inputtype))
3237                 {
3238                     if ((! outputtype) || (tmp->outputtype == outputtype))
3239                     {
3240                         if (tmp->priority == maxpriority)
3241                         {
3242                             retval = tmp;
3243                             goto erret;
3244                         }
3245                     }
3246                 }
3247             }
3248             i++;
3249         }
3250     }
3251 
3252     for (i = 0; i < imax; i++)  /* find the highest priority less than any previous */
3253     {
3254         tmp = omppp[i];
3255         if ((! proctype) || (tmp->proctype == proctype))
3256         {
3257             if ((! inputtype) || (tmp->inputtype == inputtype))
3258             {
3259                 if ((! outputtype) || (tmp->outputtype == outputtype))
3260                 {
3261                     if ((tmp->priority > bestpriority) &&
3262                         (tmp->priority < maxpriority))
3263                     {
3264                         best = tmp;
3265                         bestpriority = tmp->priority;
3266                     }
3267                 }
3268             }
3269         }
3270 
3271     }
3272 
3273     retval = best;
3274 erret:
3275     if (unlock)
3276         ObjMgrUnlock();
3277     return retval;
3278 }
3279 
ObjMgrProcOpen(ObjMgrPtr omp,Uint2 outputtype)3280 NLM_EXTERN Int2 LIBCALL ObjMgrProcOpen (ObjMgrPtr omp, Uint2 outputtype)
3281 {
3282     ObjMgrProcPtr currp=NULL;
3283     Int2 retval = OM_MSG_RET_ERROR;
3284     Boolean did_one = FALSE;
3285     OMProcControl ompc;
3286 
3287     MemSet((Pointer)(&ompc), 0, sizeof(OMProcControl));
3288     ompc.output_itemtype = outputtype;
3289 
3290     while ((currp = ObjMgrProcFindNext(omp, OMPROC_OPEN, 0, outputtype, currp)) != NULL)
3291     {
3292         ompc.proc = currp;
3293         retval = (*(currp->func)) (&ompc);
3294         did_one = TRUE;
3295         if (retval == OM_MSG_RET_DONE)
3296             break;
3297     }
3298 
3299     if (! did_one)
3300     {
3301         ErrPostEx(SEV_ERROR,0,0, "No OPEN function found");
3302         retval = OM_MSG_RET_ERROR;
3303     }
3304     return retval;
3305 }
3306 
OMGetNextUserKey(void)3307 NLM_EXTERN Uint2 LIBCALL OMGetNextUserKey (void)
3308 
3309 {
3310   ObjMgrPtr  omp;
3311   Uint2 retval = 0;
3312 
3313   omp = ObjMgrWriteLock ();
3314   if (omp == NULL) return retval;
3315   (omp->HighestUserKey)++;
3316   if (omp->HighestUserKey == 0) {
3317     (omp->HighestUserKey)++;
3318   }
3319   retval = omp->HighestUserKey;
3320   ObjMgrUnlock();
3321   return retval;
3322 }
3323 
3324 /*****************************************************************************
3325 *
3326 *   Data Type Functions
3327 *
3328 *****************************************************************************/
3329 
ObjMgrDefaultLabelFunc(Pointer data,CharPtr buffer,Int2 buflen,Uint1 content)3330 static Int2 LIBCALLBACK ObjMgrDefaultLabelFunc ( Pointer data, CharPtr buffer, Int2 buflen, Uint1 content)
3331 {
3332     ObjMgrPtr omp;
3333     ObjMgrDataPtr omdp;
3334     ObjMgrTypePtr omtp;
3335     CharPtr label=NULL;
3336     static CharPtr defaultlabel="NoLabel";
3337     Int2 retval = 0;
3338 
3339     label = defaultlabel;
3340     omp = ObjMgrReadLock();
3341     omdp = ObjMgrFindByData(omp, data);
3342     if (omdp != NULL)
3343     {
3344         omtp = ObjMgrTypeFind(omp, omdp->datatype, NULL, NULL);
3345         if (omtp != NULL)
3346         {
3347             if (omtp->label != NULL)
3348                 label = omtp->label;
3349             else if (omtp->name != NULL)
3350                 label = omtp->name;
3351             else
3352                 label = omtp->asnname;
3353         }
3354     }
3355 
3356     retval = LabelCopy(buffer, label, buflen);
3357     ObjMgrUnlock();
3358     return retval;
3359 }
3360 
ObjMgrDefaultSubTypeFunc(Pointer ptr)3361 static Uint2 LIBCALLBACK ObjMgrDefaultSubTypeFunc (Pointer ptr)
3362 {
3363     return 0;
3364 }
3365 
3366 /*****************************************************************************
3367 *
3368 *   ObjMgrTypeExtend(omp)
3369 *
3370 *****************************************************************************/
ObjMgrTypeExtend(ObjMgrPtr omp)3371 static Boolean NEAR ObjMgrTypeExtend (ObjMgrPtr omp)
3372 {
3373     Boolean result = FALSE;
3374     OMTypePtr omdp, prev=NULL;
3375     ObjMgrTypePtr PNTR tmp;
3376     Int4 i, j;
3377 
3378     for (omdp = omp->ncbitype; omdp != NULL; omdp = omdp->next)
3379         prev = omdp;
3380 
3381     omdp = (OMTypePtr)MemNew(sizeof(OMType));
3382     if (omdp == NULL) return result;
3383     tmp = (ObjMgrTypePtr PNTR)MemNew((size_t)(sizeof(ObjMgrTypePtr) * (omp->tottype + NUM_OMD)));
3384     if (tmp == NULL)
3385     {
3386         MemFree(omdp);
3387         return result;
3388     }
3389 
3390     if (prev != NULL)
3391     {
3392         prev->next = omdp;
3393         MemMove(tmp, omp->typelist, (size_t)(sizeof(ObjMgrTypePtr) * omp->tottype));
3394         MemFree(omp->typelist);
3395     }
3396     else
3397         omp->ncbitype = omdp;
3398 
3399     j = omp->tottype;
3400 
3401     for (i = 0; i < NUM_OMD; i++, j++)
3402         tmp[j] = &(omdp->data[i]);
3403 
3404     omp->tottype += NUM_OMD;
3405     omp->typelist = tmp;
3406 
3407     result = TRUE;
3408     return result;
3409 }
3410 
3411 /*****************************************************************************
3412 *
3413 *   ObjMgrTypeAddFunc(omp, type, data)
3414 *       adds a pointer (data) of type (type) to the sequence manager
3415 *       Currently this MUST be predefined and < OBJ_MAX
3416 *
3417 *****************************************************************************/
ObjMgrTypeAdd(ObjMgrTypePtr data)3418 NLM_EXTERN Uint2 LIBCALL ObjMgrTypeAdd (ObjMgrTypePtr data)
3419 {
3420     ObjMgrPtr omp;
3421     ObjMgrTypePtr omdp;
3422     ObjMgrTypePtr PNTR omdpp;
3423     Int4 i, imin, imax;
3424     Uint2 tmp, type,retval = 0;
3425 
3426     if (data == NULL) return retval;
3427 
3428     omp = ObjMgrWriteLock();
3429 
3430     type = data->datatype;
3431     if ((! type) || (type >= OBJ_MAX))
3432     {
3433         /***
3434         type = ++(omp->HighestObjMgrType);
3435         ***/
3436 
3437         ErrPostEx(SEV_ERROR, 0,0, "ObjMgrTypeAdd: Can't register new object types yet");
3438         goto erret;
3439     }
3440 
3441     if (omp->currtype >= omp->tottype)
3442     {
3443         if (! ObjMgrTypeExtend(omp))
3444             goto erret;
3445     }
3446 
3447     i = omp->currtype;
3448     omdpp = omp->typelist;
3449     omdp = omdpp[i];    /* emptys always at end */
3450 
3451     imin = 0;                   /* find where it goes */
3452     imax = omp->currtype-1;
3453 
3454     if ((i) && (type < omdpp[imax]->datatype))
3455     {
3456         i = (imax + imin) / 2;
3457         while (imax > imin)
3458         {
3459             tmp = omdpp[i]->datatype;
3460             if (tmp > type)
3461                 imax = i - 1;
3462             else if (tmp < type)
3463                 imin = i + 1;
3464             else
3465                 break;
3466             i = (imax + imin)/2;
3467         }
3468 
3469         if (type > omdpp[i]->datatype)     /* check for off by 1 */
3470             i++;
3471 
3472         imax = omp->currtype - 1;     /* open the array */
3473         while (imax >= i)
3474         {
3475             omdpp[imax+1] = omdpp[imax];
3476             imax--;
3477         }
3478     }
3479 
3480     omdpp[i] = omdp;    /* put in the pointer in order */
3481     omp->currtype++;     /* got one more */
3482 
3483     MemMove(omdp, data, sizeof(ObjMgrType));
3484     omdp->datatype = type;  /* fill in the values */
3485     omdp->asnname = StringSave(data->asnname);
3486     omdp->label = StringSave(data->label);
3487     omdp->name = StringSave(data->name);
3488     if (omdp->labelfunc == NULL)
3489         omdp->labelfunc = ObjMgrDefaultLabelFunc;
3490     if (omdp->subtypefunc == NULL)
3491         omdp->subtypefunc = ObjMgrDefaultSubTypeFunc;
3492     retval = type;
3493 erret:
3494     ObjMgrUnlock();
3495     return retval;
3496 }
3497 
3498 /*****************************************************************************
3499 *
3500 *   ObjMgrTypeLoad(args)
3501 *
3502 *****************************************************************************/
ObjMgrTypeLoad(Uint2 type,CharPtr asnname,CharPtr label,CharPtr name,AsnTypePtr atp,OMNewFunc newfunc,AsnReadFunc asnread,AsnWriteFunc asnwrite,OMFreeFunc freefunc,OMLabelFunc labelfunc,OMSubTypeFunc subtypefunc)3503 NLM_EXTERN Uint2 LIBCALL ObjMgrTypeLoad ( Uint2 type, CharPtr asnname,
3504         CharPtr label, CharPtr name, AsnTypePtr atp, OMNewFunc newfunc,
3505         AsnReadFunc asnread, AsnWriteFunc asnwrite, OMFreeFunc freefunc,
3506         OMLabelFunc labelfunc, OMSubTypeFunc subtypefunc)
3507 {
3508     ObjMgrType omt;
3509     Uint2 newtype;
3510 
3511     MemSet((Pointer)(&omt), 0, sizeof(ObjMgrType));
3512     omt.datatype = type;
3513     omt.asnname = asnname;
3514     omt.label = label;
3515     omt.name = name;
3516     omt.atp = atp;
3517     omt.newfunc = newfunc;
3518     omt.asnread = asnread;
3519     omt.asnwrite = asnwrite;
3520     omt.freefunc = freefunc;
3521     omt.labelfunc = labelfunc;
3522     omt.subtypefunc = subtypefunc;
3523 
3524     newtype = ObjMgrTypeAdd(&omt);
3525 
3526     return newtype;
3527 }
3528 
3529 /*****************************************************************************
3530 *
3531 *   ObjMgrTypeLookup(omp, data)
3532 *       Binary lookup of data in omp->typelist
3533 *       returns index (>=0) if found
3534 *       returns -1 if not found
3535 *
3536 *****************************************************************************/
ObjMgrTypeLookup(ObjMgrPtr omp,Uint2 data)3537 NLM_EXTERN Int4 LIBCALL ObjMgrTypeLookup(ObjMgrPtr omp, Uint2 data)
3538 {
3539     Int4 imin, imax, i;
3540     ObjMgrTypePtr PNTR omdpp;
3541     Uint2 tmp;
3542 
3543     imin = 0;
3544     imax = omp->currtype - 1;
3545     omdpp = omp->typelist;
3546 
3547     while (imax >= imin)
3548     {
3549         i = (imax + imin)/2;
3550         tmp = omdpp[i]->datatype;
3551         if (tmp > data)
3552             imax = i - 1;
3553         else if (tmp < data)
3554             imin = i + 1;
3555         else
3556             return i;
3557     }
3558 
3559     return (Int4)(-1);
3560 }
3561 
3562 /*****************************************************************************
3563 *
3564 *   ObjMgrTypeFind(omp, type, asnname, name)
3565 *       returns the objmgrptr by looking for
3566 *           type: if type != 0
3567 *           asnname: if asnname != NULL
3568 *           name: if name != NULL
3569 *       in that order of preference.
3570 *       if omp == NULL, then does temporary read lock in this function
3571 *       returns NULL if can't match on highest priority key
3572 *
3573 *****************************************************************************/
ObjMgrTypeFind(ObjMgrPtr tomp,Uint2 type,CharPtr asnname,CharPtr name)3574 NLM_EXTERN ObjMgrTypePtr LIBCALL ObjMgrTypeFind (ObjMgrPtr tomp, Uint2 type, CharPtr asnname, CharPtr name)
3575 {
3576     ObjMgrTypePtr omtp = NULL;
3577     ObjMgrTypePtr PNTR omdpp;
3578     Int4 i, imax, result;
3579     ObjMgrPtr omp;
3580     Boolean unlock = FALSE;
3581 
3582     if (tomp == NULL)
3583     {
3584         omp = ObjMgrReadLock();
3585         unlock = TRUE;
3586     }
3587     else
3588         omp = tomp;
3589 
3590     omdpp = omp->typelist;
3591     imax = omp->currtype;
3592     if (type)
3593     {
3594         i = ObjMgrTypeLookup(omp, type);
3595         if (i >= 0)
3596             omtp = omdpp[i];
3597     }
3598     else
3599     {
3600         for (i = 0; i < imax; i++)
3601         {
3602             if (asnname != NULL)
3603                 result = StringCmp(omdpp[i]->asnname, asnname);
3604             else
3605                 result = StringCmp(omdpp[i]->name, name);
3606             if (! result)
3607             {
3608                 omtp = omdpp[i];
3609                 break;
3610             }
3611         }
3612     }
3613 
3614     if (unlock)
3615         ObjMgrUnlock();
3616 
3617     return omtp;
3618 }
3619 
3620 /*****************************************************************************
3621 *
3622 *   ObjMgrTypeSetLabelFunc(type, labelfunc)
3623 *       replaces the labelfunc for type with a new one
3624 *       can also set it for the first time
3625 *
3626 *****************************************************************************/
ObjMgrTypeSetLabelFunc(Uint2 type,OMLabelFunc labelfunc)3627 NLM_EXTERN Boolean LIBCALL ObjMgrTypeSetLabelFunc(Uint2 type, OMLabelFunc labelfunc)
3628 {
3629     ObjMgrPtr omp;
3630     ObjMgrTypePtr omtp;
3631     Boolean retval = FALSE;
3632 
3633     omp = ObjMgrWriteLock();
3634     omtp = ObjMgrTypeFind(omp, type, NULL, NULL);
3635     if (omtp != NULL)
3636     {
3637         omtp->labelfunc = labelfunc;
3638         retval = TRUE;
3639     }
3640     ObjMgrUnlock();
3641     return retval;
3642 }
3643 
3644 /**************************************************************************
3645 *
3646 * ObjMgrTypeFindNext(omp, omtp)
3647 *    returns next ObjMgrType after omtp
3648 *    Exhaustively traverses registered types if omtp starts as NULL
3649 *
3650 ***************************************************************************/
ObjMgrTypeFindNext(ObjMgrPtr omp,ObjMgrTypePtr last)3651 NLM_EXTERN ObjMgrTypePtr LIBCALL ObjMgrTypeFindNext (ObjMgrPtr omp, ObjMgrTypePtr last)
3652 {
3653     ObjMgrTypePtr PNTR omdpp;
3654     Int4 i, imax;
3655     Boolean got_it = FALSE;
3656 
3657     omdpp = omp->typelist;
3658     imax = omp->currtype;
3659     if (last == NULL)   /* take the first one */
3660         got_it = TRUE;
3661     for (i = 0; i < imax; i++)
3662     {
3663         if (got_it)
3664             return omdpp[i];
3665 
3666         if (omdpp[i] == last)
3667             got_it = TRUE;
3668     }
3669 
3670     return NULL;
3671 }
3672 
3673 /*****************************************************************************
3674 *
3675 *   Selection Functions for data objects
3676 *
3677 *****************************************************************************/
ObjMgrSendSelMsg(ObjMgrPtr omp,Uint2 entityID,Uint4 itemID,Uint2 itemtype,Uint1 regiontype,Pointer region)3678 static Boolean NEAR ObjMgrSendSelMsg (ObjMgrPtr omp, Uint2 entityID,
3679          Uint4 itemID, Uint2 itemtype, Uint1 regiontype, Pointer region)
3680 {
3681         ObjMgrDataPtr omdp;
3682         OMMsgStruct ommds;
3683 
3684         omdp = ObjMgrFindByEntityID(omp, entityID, NULL);
3685         if (omdp == NULL)
3686            return FALSE;
3687 
3688         MemSet((Pointer)(&ommds), 0, sizeof(OMMsgStruct));
3689         ommds.message = OM_MSG_SELECT;
3690         ommds.entityID = entityID;
3691         ommds.itemtype = itemtype;
3692         ommds.itemID = itemID;
3693         ommds.regiontype = regiontype;
3694         ommds.region = region;
3695 
3696         ObjMgrSendStructMsgFunc(omp, omdp, &ommds);
3697     return TRUE;
3698 }
3699 
ObjMgrSendDeSelMsg(ObjMgrPtr omp,Uint2 entityID,Uint4 itemID,Uint2 itemtype,Uint1 regiontype,Pointer region)3700 static Boolean NEAR ObjMgrSendDeSelMsg (ObjMgrPtr omp, Uint2 entityID,
3701          Uint4 itemID, Uint2 itemtype, Uint1 regiontype, Pointer region)
3702 {
3703         ObjMgrDataPtr omdp;
3704         OMMsgStruct ommds;
3705 
3706         omdp = ObjMgrFindByEntityID(omp, entityID, NULL);
3707         if (omdp == NULL)
3708            return FALSE;
3709 
3710         MemSet((Pointer)(&ommds), 0, sizeof(OMMsgStruct));
3711         ommds.message = OM_MSG_DESELECT;
3712         ommds.entityID = entityID;
3713         ommds.itemtype = itemtype;
3714         ommds.itemID = itemID;
3715         ommds.regiontype = regiontype;
3716         ommds.region = region;
3717 
3718     ObjMgrSendStructMsgFunc(omp, omdp, &ommds);
3719     return TRUE;
3720 }
3721 
ObjMgrAddSelStruct(ObjMgrPtr omp,Uint2 entityID,Uint4 itemID,Uint2 itemtype,Uint1 regiontype,Pointer region)3722 static SelStructPtr NEAR ObjMgrAddSelStruct (ObjMgrPtr omp, Uint2 entityID,
3723          Uint4 itemID, Uint2 itemtype, Uint1 regiontype, Pointer region)
3724 {
3725     SelStructPtr ssp, tmp;
3726 
3727     tmp = omp->sel;
3728 
3729     if (tmp != NULL)
3730     {
3731         while (tmp->next != NULL)
3732             tmp = tmp->next;
3733     }
3734 
3735     ssp = MemNew(sizeof(SelStruct));
3736     if (tmp != NULL)
3737     {
3738         tmp->next = ssp;
3739         ssp->prev = tmp;
3740     }
3741     else
3742         omp->sel = ssp;
3743 
3744     ssp->entityID = entityID;
3745     ssp->itemID = itemID;
3746     ssp->itemtype = itemtype;
3747     ssp->regiontype = regiontype;
3748     ssp->region = region;
3749 
3750     return ssp;
3751 }
3752 
3753 
ObjMgrDeSelectStructFunc(ObjMgrPtr omp,SelStructPtr ssp)3754 static Boolean NEAR ObjMgrDeSelectStructFunc (ObjMgrPtr omp, SelStructPtr ssp)
3755 {
3756     SelStructPtr next, prev;
3757 
3758     if (ssp == NULL)
3759         return FALSE;
3760 
3761     next = ssp->next;
3762     prev = ssp->prev;
3763     if (prev != NULL)
3764         prev->next = next;
3765     else
3766         omp->sel = next;
3767     if (next != NULL)
3768         next->prev = prev;
3769 
3770         ObjMgrSendDeSelMsg (omp, ssp->entityID, ssp->itemID, ssp->itemtype, ssp->regiontype, ssp->region);
3771 
3772     ObjMgrRegionFree(omp, ssp->regiontype, ssp->region); /* free any region */
3773 
3774     MemFree(ssp);
3775 
3776     return TRUE;
3777 }
3778 
ObjMgrDeSelectAllFunc(ObjMgrPtr omp)3779 static Boolean NEAR ObjMgrDeSelectAllFunc (ObjMgrPtr omp)
3780 {
3781     SelStructPtr tmp, prev;
3782 
3783     tmp = omp->sel;
3784     if (tmp == NULL)
3785         return TRUE;
3786 
3787     prev = NULL;
3788 
3789     while (tmp->next != NULL)
3790     {
3791         prev = tmp;
3792         tmp = tmp->next;
3793     }
3794 
3795     while (tmp != NULL)
3796     {
3797         ObjMgrDeSelectStructFunc(omp, tmp);
3798         tmp = prev;
3799         if (tmp != NULL)
3800             prev = tmp->prev;
3801     }
3802 
3803     return TRUE;
3804 }
3805 
ObjMgrRegionMatch(Uint1 regiontype1,Pointer region1,Uint1 regiontype2,Pointer region2)3806 static Boolean NEAR ObjMgrRegionMatch (Uint1 regiontype1, Pointer region1,
3807                     Uint1 regiontype2, Pointer region2)
3808 {
3809     SeqLocPtr slp;
3810     SeqIntPtr sip1, sip2;
3811 
3812     if (regiontype1 != regiontype2) return FALSE;
3813     if (! regiontype1) return FALSE;
3814     if ((region1 == NULL) || (region2 == NULL))     return FALSE;
3815 
3816     switch (regiontype1)
3817     {
3818         case OM_REGION_SEQLOC:    /* SeqLocs of type SeqInt */
3819             slp = (SeqLocPtr)region1;
3820             sip1 = (SeqIntPtr)(slp->data.ptrvalue);
3821             slp = (SeqLocPtr)(region2);
3822             sip2 = (SeqIntPtr)(slp->data.ptrvalue);
3823             if (sip1 == NULL || sip2 == NULL) return FALSE;
3824             if ( ((sip1->from == sip2->from) &&
3825                 (sip1->to == sip2->to)))
3826                        /* get rid of (sip1->strand == sip2->strand) */
3827                     return TRUE;
3828             break;
3829         default:
3830             break;
3831     }
3832     return FALSE;
3833 }
3834 
3835 /*
3836 static Pointer NEAR ObjMgrRegionCopy (ObjMgrPtr omp, Uint1 regiontype, Pointer region)
3837 {
3838     Pointer newregion = NULL;
3839 
3840     if (region != NULL)
3841     {
3842         switch (regiontype)
3843         {
3844             case OM_REGION_SEQLOC:
3845                 newregion = ObjMgrMemCopyFunc(omp, OBJ_SEQLOC, region, FALSE);
3846                 break;
3847             default:
3848                 break;
3849         }
3850     }
3851     return newregion;
3852 }
3853 */
3854 
ObjMgrRegionFree(ObjMgrPtr omp,Uint1 regiontype,Pointer region)3855 static Pointer NEAR ObjMgrRegionFree (ObjMgrPtr omp, Uint1 regiontype, Pointer region)
3856 {
3857     if (region != NULL)
3858     {
3859         switch (regiontype)
3860         {
3861             case OM_REGION_SEQLOC:
3862                 ObjMgrFreeFunc(omp, OBJ_SEQLOC, region, FALSE);
3863                 break;
3864             default:
3865                 break;
3866         }
3867     }
3868 
3869     return NULL;
3870 }
3871 
3872 /*****************************************************************************
3873 *
3874 *   ObjMgrSelect(entityID, itemID, itemtype)
3875 *      if entityID == 0, just deselects everything
3876 *      if entityID,itemID, itemtype already selected, deselects everything else
3877 *      if something else selected, deselects it first, then selects requested
3878 *        item
3879 *      returns TRUE if item is now currently selected, FALSE if not
3880 *
3881 *****************************************************************************/
ObjMgrSelect(Uint2 entityID,Uint4 itemID,Uint2 itemtype,Uint1 regiontype,Pointer region)3882 NLM_EXTERN Boolean LIBCALL ObjMgrSelect (Uint2 entityID, Uint4 itemID, Uint2 itemtype,
3883                                     Uint1 regiontype, Pointer region)
3884 {
3885     ObjMgrPtr omp;
3886     Boolean retval = FALSE;
3887 
3888     omp = ObjMgrWriteLock();
3889     retval = ObjMgrSelectFunc(omp, entityID, itemID, itemtype,
3890                 regiontype, region);
3891     ObjMgrUnlock();
3892     return retval;
3893 }
3894 
3895 
3896 /*****************************************************************************
3897 *
3898 *   ObjMgrSelect(entityID, itemID, itemtype)
3899 *      if entityID == 0, just deselects everything
3900 *      if entityID,itemID, itemtype already selected, deselects everything else
3901 *      if something else selected, deselects it first, then selects requested
3902 *        item
3903 *      returns TRUE if item is now currently selected, FALSE if not
3904 *
3905 *****************************************************************************/
ObjMgrSelectFunc(ObjMgrPtr omp,Uint2 entityID,Uint4 itemID,Uint2 itemtype,Uint1 regiontype,Pointer region)3906 static Boolean NEAR ObjMgrSelectFunc (ObjMgrPtr omp, Uint2 entityID, Uint4 itemID, Uint2 itemtype,
3907                                     Uint1 regiontype, Pointer region)
3908 {
3909     SelStructPtr ssp, next;
3910     Boolean was_selected = FALSE, is_selected, remove_this, retval = TRUE;
3911 
3912 
3913     if (entityID == 0)    /* desktop */
3914     {
3915         ObjMgrDeSelectAllFunc(omp);
3916         goto erret;
3917     }
3918     else
3919     {
3920         ssp = omp->sel;
3921         while (ssp != NULL)
3922         {
3923             remove_this = TRUE;
3924             next = ssp->next;
3925             if (ssp->entityID == entityID)
3926             {
3927                 if ((ssp->itemID == itemID) || (! itemID))
3928                 {
3929                     if ((ssp->itemtype == itemtype) || (! itemtype))
3930                     {
3931                         if ((ssp->regiontype == regiontype) || (! regiontype))
3932                         {
3933                             is_selected = TRUE;
3934                             if (regiontype)
3935                                 is_selected = ObjMgrRegionMatch(ssp->regiontype,
3936                                     ssp->region, regiontype, region);
3937                             if (is_selected)
3938                             {
3939                                 remove_this = FALSE;
3940                                 was_selected = TRUE;
3941                             }
3942                         }
3943                     }
3944                 }
3945             }
3946             if (remove_this)
3947                 ObjMgrDeSelectStructFunc(omp, ssp);
3948 
3949             ssp = next;
3950         }
3951     }
3952 
3953     if (was_selected)  /* no more action needed */
3954     {
3955         retval = TRUE;
3956     }
3957     else
3958     {
3959         ssp = ObjMgrAddSelStruct(omp, entityID, itemID, itemtype, regiontype, region);
3960 
3961         if (ssp != NULL)
3962             retval = ObjMgrSendSelMsg(omp, entityID, itemID, itemtype, regiontype, region);;
3963     }
3964 
3965 erret:
3966     return retval;
3967 
3968 }
3969 
SeqLocChangeIntervalle(SeqLocPtr slp,Int4 start,Int4 stop)3970 static SeqLocPtr SeqLocChangeIntervalle (SeqLocPtr slp, Int4 start, Int4 stop)
3971 {
3972         SeqIntPtr sip;
3973 
3974         sip = (SeqIntPtr)(slp->data.ptrvalue);
3975         if (start > -1)
3976                 sip->from = start;
3977         if (stop > -1)
3978                 sip->to = stop;
3979         return slp;
3980 }
3981 
ObjMgrRegionComp(Pointer region1,Pointer region2,Boolean direction2_plus)3982 static Int2 NEAR ObjMgrRegionComp (Pointer region1,Pointer region2, Boolean direction2_plus)
3983 {
3984         SeqLocPtr slp1, slp2;
3985         Int2      res;
3986 
3987         if ((region1 == NULL) || (region2 == NULL))
3988            return FALSE;
3989 
3990         slp1 = (SeqLocPtr)region1;
3991         slp2 = (SeqLocPtr)region2;
3992         res = SeqLocCompare (slp1,slp2);
3993         if (res == SLC_NO_MATCH)
3994         {
3995            if (SeqLocStop(slp1) == SeqLocStart(slp2)-1)
3996               return 2;
3997            if (SeqLocStart(slp1) == SeqLocStop(slp2)+1)
3998               return 3;
3999            return 0;
4000         }
4001         if (res == SLC_A_EQ_B)
4002            return 1;
4003         if (res == SLC_B_IN_A)
4004         {
4005        if (SeqLocStart(slp1)==SeqLocStart(slp2))
4006               return 5;
4007            if (SeqLocStop(slp1)==SeqLocStop(slp2))
4008               return 6;
4009            if (direction2_plus)
4010               return 5;
4011            else
4012               return 6;
4013         }
4014         if (res == SLC_A_IN_B)
4015            return 4;
4016         if (res == SLC_A_OVERLAP_B)
4017         {
4018            if (SeqLocStart(slp1) < SeqLocStart(slp2))
4019               return 2;
4020            if (SeqLocStart(slp1) > SeqLocStart(slp2))
4021               return 3;
4022         }
4023         return 0;
4024 }
4025 
4026 
ObjMgrSelectFunc2(ObjMgrPtr omp,Uint2 entityID,Uint4 itemID,Uint2 itemtype,Uint1 regiontype,Pointer region)4027 static Boolean NEAR ObjMgrSelectFunc2
4028 (ObjMgrPtr omp, Uint2 entityID, Uint4 itemID, Uint2 itemtype, Uint1 regiontype, Pointer region)
4029 {
4030         SelStructPtr ssp, next;
4031         Boolean      retval = FALSE;
4032     SeqLocPtr    tmp = NULL,
4033                      tmp2 = NULL;
4034         Int2         res=0;
4035     Boolean direction_plus = TRUE;
4036 
4037         if (entityID == 0)    /* desktop */
4038         {
4039                 ObjMgrDeSelectAllFunc(omp);
4040                 goto erret;
4041         }
4042         else if (region)
4043         {
4044 /***** Colombe Patrick ****/
4045 /** send Seq_strand_minus seqloc of selection when the cursor moves to the left **/
4046 /** the Seq_strand_minus is now change to Seq_strand_plus     for ever **/
4047 
4048            if (SeqLocStrand(region)==Seq_strand_minus)
4049        {
4050 SeqIntPtr sit;
4051 SeqLocPtr slp;
4052                 slp = (SeqLocPtr)region;
4053           sit = (SeqIntPtr)(slp->data.ptrvalue);
4054           sit->strand = Seq_strand_plus;
4055               direction_plus=FALSE;
4056        }
4057 /***** Colombe Patrick ****/
4058                 ssp = omp->sel;
4059                 while (ssp != NULL && res == 0)
4060                 {
4061                         next = ssp->next;
4062                         if (ssp->entityID == entityID)
4063                         {
4064                                 if ((ssp->itemID == itemID) || (! itemID))
4065                                 {
4066                                         if ((ssp->itemtype == itemtype) || (! itemtype))
4067                                         {
4068                                                 if (ssp->regiontype && regiontype)
4069                                                 {
4070                                                         res = ObjMgrRegionComp (ssp->region, region, direction_plus);
4071                             if (res>0)
4072                                 break;
4073                                                 }
4074                                         }
4075                                 }
4076                         }
4077                         ssp = next;
4078                 }
4079         }
4080         if (res==2)  /* extend ssp->region to right */
4081         {
4082                 SeqLocChangeIntervalle ((SeqLocPtr)ssp->region, -1, SeqLocStop(region));
4083                 retval=ObjMgrSendSelMsg (omp, entityID, itemID, itemtype, ssp->regiontype, ssp->region);
4084         }
4085         else if (res==3)   /* extend ssp->region to left */
4086         {
4087                 SeqLocChangeIntervalle ((SeqLocPtr)ssp->region, SeqLocStart(region), -1);
4088                 retval=ObjMgrSendSelMsg (omp, entityID, itemID, itemtype, ssp->regiontype, ssp->region);
4089         }
4090         else if (res==4)   /* extend ssp->regiontype both sides */
4091         {
4092                 SeqLocChangeIntervalle ((SeqLocPtr)ssp->region, SeqLocStart(region), SeqLocStop(region));
4093                 retval=ObjMgrSendSelMsg (omp, entityID, itemID, itemtype, ssp->regiontype, ssp->region);
4094         }
4095         else if (res==5)  /* shrink ssp->region from right */
4096         {
4097                 tmp = SeqLocIntNew (SeqLocStart((SeqLocPtr)ssp->region), SeqLocStop((SeqLocPtr)region), 0, SeqLocId(region));
4098                 tmp2 = SeqLocIntNew (SeqLocStop((SeqLocPtr)region)+1, SeqLocStop((SeqLocPtr)ssp->region), 0, SeqLocId(region));
4099                 SeqLocChangeIntervalle ((SeqLocPtr)ssp->region, -1, (Int4)(SeqLocStop(region)));
4100         ValNodeFree (tmp);
4101                 retval=ObjMgrSendDeSelMsg (omp, entityID, itemID, itemtype, OM_REGION_SEQLOC, tmp2);
4102 
4103         ValNodeFree (tmp2);
4104         }
4105         else if (res==6) /* shrink ssp->region from left */
4106         {
4107                 tmp = SeqLocIntNew (SeqLocStart((SeqLocPtr)region), SeqLocStop((SeqLocPtr)ssp->region), 0, SeqLocId(region));
4108                 tmp2 = SeqLocIntNew (SeqLocStart((SeqLocPtr)ssp->region), SeqLocStart((SeqLocPtr)region)-1, 0, SeqLocId(region));
4109                 SeqLocChangeIntervalle ((SeqLocPtr)ssp->region, (Int4)(SeqLocStart(region)), -1);
4110         ValNodeFree (tmp);
4111                 retval=ObjMgrSendDeSelMsg (omp, entityID, itemID, itemtype, OM_REGION_SEQLOC, tmp2);
4112         ValNodeFree (tmp2);
4113         }
4114         else if (res==0)
4115         {
4116                 ssp = ObjMgrAddSelStruct(omp, entityID, itemID, itemtype, regiontype, region);
4117                 if (ssp != NULL)
4118                         retval=ObjMgrSendSelMsg (omp, entityID, itemID, itemtype, regiontype, region);
4119         }
4120 
4121 erret:
4122         return (Boolean)(res>0);
4123 
4124 }
4125 
CheckRedondantSelect(ObjMgrPtr omp)4126 static Boolean NEAR CheckRedondantSelect (ObjMgrPtr omp)
4127 {
4128         SelStructPtr ssp1 = NULL,
4129                 ssp2 = NULL,
4130                 next1,
4131                 next2 = NULL, pre2 = NULL;
4132         SeqLocPtr    tmp;
4133         Boolean      retval = FALSE;
4134         Int2         res=0;
4135 
4136         if (omp!=NULL)
4137         {
4138                 ssp1 = omp->sel;
4139                 while (ssp1 != NULL && res==0)
4140                 {
4141                    next1 = ssp1->next;
4142                    ssp2=next1;
4143                    pre2=ssp1;
4144                    while (ssp2!=NULL && res==0)
4145                    {
4146                        next2 = ssp2->next;
4147                         if (ssp1->entityID == ssp2->entityID)
4148                         {
4149                                 if (ssp1->itemID == ssp2->itemID)
4150                                 {
4151                                         if (ssp1->itemtype == ssp2->itemtype)
4152                                         {
4153                                                 if (ssp1->regiontype && ssp2->regiontype)
4154                                                 {
4155                                                         res = ObjMgrRegionComp (ssp1->region, ssp2->region, TRUE);
4156                             if (res>0)
4157                                 break;
4158                                                 }
4159                                         }
4160                                 }
4161                         }
4162                         ssp2 = next2;
4163                    }
4164                    if (res==0)
4165             ssp1 = next1;
4166                 }
4167         }
4168     if (res==1)
4169     {
4170                pre2->next=next2;
4171                ssp2=MemFree(ssp2);
4172                 ObjMgrSendSelMsg (omp, ssp1->entityID, ssp1->itemID, ssp1->itemtype, 0, 0);
4173                 retval=TRUE;
4174     }
4175         else if (res==2)  /* extend ssp->regiontype to right */
4176         {
4177                 SeqLocChangeIntervalle ((SeqLocPtr)ssp1->region, -1, SeqLocStop(ssp2->region));
4178                pre2->next=next2;
4179                ssp2=MemFree(ssp2);
4180                 ObjMgrSendSelMsg (omp, ssp1->entityID, ssp1->itemID, ssp1->itemtype, 0, 0);
4181                 retval=TRUE;
4182         }
4183         else if (res==3)   /* extend ssp->regiontype to left */
4184         {
4185                 SeqLocChangeIntervalle ((SeqLocPtr)ssp1->region, SeqLocStart(ssp2->region), -1);
4186                pre2->next=next2;
4187                ssp2=MemFree(ssp2);
4188                 ObjMgrSendSelMsg (omp, ssp1->entityID, ssp1->itemID, ssp1->itemtype, 0, 0);
4189                 retval=TRUE;
4190         }
4191         else if (res==4)   /* extend ssp->regiontype both sides */
4192         {
4193                 SeqLocChangeIntervalle ((SeqLocPtr)ssp1->region, SeqLocStart(ssp2->region), SeqLocStop(ssp2->region));
4194                pre2->next=next2;
4195                ssp2=MemFree(ssp2);
4196                 ObjMgrSendSelMsg (omp, ssp1->entityID, ssp1->itemID, ssp1->itemtype, 0, 0);
4197                 retval=TRUE;
4198         }
4199         else if (res==5)  /* shrink ssp->region from right */
4200         {
4201         tmp = SeqLocIntNew (SeqLocStart((SeqLocPtr)ssp1->region), SeqLocStop(ssp2->region), 0, SeqLocId(ssp2->region));
4202                 SeqLocChangeIntervalle ((SeqLocPtr)ssp1->region, -1, SeqLocStop(ssp2->region));
4203                pre2->next=next2;
4204                ssp2=MemFree(ssp2);
4205                 ObjMgrSendDeSelMsg (omp, ssp1->entityID, ssp1->itemID, ssp1->itemtype, 0, 0);
4206         ValNodeFree (tmp);
4207                 retval=TRUE;
4208         }
4209         else if (res==6) /* shrink ssp->region from left */
4210         {
4211                 tmp = SeqLocIntNew (SeqLocStart(ssp2->region), SeqLocStop((SeqLocPtr)ssp1->region), 0, SeqLocId(ssp2->region));
4212                 SeqLocChangeIntervalle ((SeqLocPtr)ssp1->region, SeqLocStart(ssp2->region), -1);
4213                pre2->next=next2;
4214                ssp2=MemFree(ssp2);
4215                 ObjMgrSendDeSelMsg (omp, ssp1->entityID, ssp1->itemID, ssp1->itemtype, 0, 0);
4216         ValNodeFree (tmp);
4217                 retval=TRUE;
4218         }
4219         return retval;
4220 }
4221 
4222 
4223 
4224 /*****************************************************************************
4225 *
4226 *   ObjMgrSetColor(entityID, itemID, itemtype, regiontype, region, rgb);
4227 *      Sets color of object in displays
4228 *      if regiontype != 0, and restricts to region
4229 *      rgb is a pointer to a Uint1[3] array containing an RGB value.
4230 *
4231 *****************************************************************************/
ObjMgrSetColor(Uint2 entityID,Uint4 itemID,Uint2 itemtype,Uint1 regiontype,Pointer region,Uint1Ptr rgb)4232 NLM_EXTERN Boolean LIBCALL ObjMgrSetColor (Uint2 entityID, Uint4 itemID,
4233                                         Uint2 itemtype, Uint1 regiontype,
4234                                         Pointer region, Uint1Ptr rgb)
4235 {
4236     ObjMgrPtr omp;
4237     ObjMgrDataPtr omdp;
4238     OMMsgStruct ommds;
4239     Boolean retval = FALSE;
4240 
4241     omp = ObjMgrReadLock();
4242 
4243     if (rgb == NULL) goto erret;
4244 
4245     omdp = ObjMgrFindByEntityID(omp, entityID, NULL);
4246     if (omdp == NULL) goto erret;
4247 
4248     MemSet((Pointer)(&ommds), 0, sizeof(OMMsgStruct));
4249     ommds.message = OM_MSG_SETCOLOR;
4250     ommds.entityID = entityID;
4251     ommds.itemtype = itemtype;
4252     ommds.itemID = itemID;
4253     ommds.regiontype = regiontype;
4254     ommds.region = region;
4255         ommds.rgb[0] = rgb[0];
4256         ommds.rgb[1] = rgb[1];
4257         ommds.rgb[2] = rgb[2];
4258 
4259                                 /* send the message */
4260     ObjMgrSendStructMsgFunc(omp, omdp, &ommds);
4261                                 /* free the region */
4262     retval = TRUE;
4263 erret:
4264     ObjMgrUnlock();
4265 
4266     return retval;
4267 }
4268 /*****************************************************************************
4269 *
4270 *   ObjMgrDeSelect(entityID, itemID, itemtype)
4271 *       if this item was selected, then deselects and returns TRUE
4272 *       else returns FALSE
4273 *
4274 *****************************************************************************/
4275 
ObjMgrDeSelect(Uint2 entityID,Uint4 itemID,Uint2 itemtype,Uint1 regiontype,Pointer region)4276 NLM_EXTERN Boolean LIBCALL ObjMgrDeSelect (Uint2 entityID, Uint4 itemID, Uint2 itemtype,
4277                                     Uint1 regiontype, Pointer region)
4278 {
4279     ObjMgrPtr omp;
4280     Boolean retval=FALSE;
4281 
4282     omp = ObjMgrWriteLock();
4283     retval = ObjMgrDeSelectFunc (omp, entityID, itemID, itemtype,
4284                 regiontype, region);
4285     ObjMgrUnlock();
4286     return retval;
4287 }
4288 
4289 
4290 /*****************************************************************************
4291 *
4292 *   ObjMgrDeSelect(entityID, itemID, itemtype)
4293 *       if this item was selected, then deselects and returns TRUE
4294 *       else returns FALSE
4295 *
4296 *****************************************************************************/
4297 
ObjMgrDeSelectFunc(ObjMgrPtr omp,Uint2 entityID,Uint4 itemID,Uint2 itemtype,Uint1 regiontype,Pointer region)4298 static Boolean NEAR ObjMgrDeSelectFunc (ObjMgrPtr omp, Uint2 entityID, Uint4 itemID, Uint2 itemtype,
4299                                     Uint1 regiontype, Pointer region)
4300 {
4301     SelStructPtr tmp, next;
4302     Boolean retval=FALSE, tret, do_it;
4303     SeqLocPtr slp;
4304 
4305     if (entityID == 0)
4306     {
4307         retval = ObjMgrDeSelectAllFunc(omp);
4308         goto erret;
4309     }
4310 
4311     tmp = omp->sel;
4312     while (tmp != NULL)
4313     {
4314         next = tmp->next;
4315         do_it = FALSE;
4316         if (tmp->entityID == entityID)
4317         {
4318             if ((! itemtype) || (itemtype == tmp->itemtype))
4319             {
4320                 if ((! itemID) || (itemID == tmp->itemID))
4321                 {
4322                     if ((tmp->regiontype == regiontype) || (! regiontype))
4323                     {
4324                         do_it = TRUE;
4325                         if (regiontype)
4326                             do_it = ObjMgrRegionMatch(tmp->regiontype,
4327                                 tmp->region, regiontype, region);
4328                         if (do_it)
4329                         {
4330                             tret = ObjMgrDeSelectStructFunc(omp, tmp);
4331                             if (tret)
4332                                 retval = TRUE;
4333                         }
4334                                                 else if (SeqLocCompare(tmp->region, region)==SLC_B_IN_A)
4335                         {
4336                             if (SeqLocStart(tmp->region)==SeqLocStart(region))
4337                             {
4338                                         SeqLocChangeIntervalle ((SeqLocPtr)tmp->region, (Int4)(SeqLocStop(region)+1), -1);
4339                                         retval=ObjMgrSendDeSelMsg (omp, entityID, itemID, itemtype, OM_REGION_SEQLOC, region);
4340                             }
4341                             else if (SeqLocStop(tmp->region)==SeqLocStop(region))
4342                             {
4343                                 SeqLocChangeIntervalle ((SeqLocPtr)tmp->region, -1, (Int4)(SeqLocStart(region)-1));
4344                                 retval=ObjMgrSendDeSelMsg (omp, entityID, itemID, itemtype, OM_REGION_SEQLOC, region);
4345                             }
4346                             else {
4347                                 slp=SeqLocIntNew(SeqLocStop(region)+1, SeqLocStop((SeqLocPtr)tmp->region), 0, SeqLocId(tmp->region));
4348                                  SeqLocChangeIntervalle ((SeqLocPtr)tmp->region, -1, (Int4)(SeqLocStart(region)-1));
4349                                         ObjMgrAddSelStruct(omp, entityID, itemID, itemtype, regiontype, slp);
4350                                                                 retval=ObjMgrSendDeSelMsg (omp, entityID, itemID, itemtype, OM_REGION_SEQLOC, region);
4351 
4352                             }
4353                         }
4354                     }
4355                 }
4356             }
4357         }
4358         tmp = next;
4359     }
4360 
4361 erret:
4362     return retval;
4363 }
4364 
ObjMgrAlsoSelect(Uint2 entityID,Uint4 itemID,Uint2 itemtype,Uint1 regiontype,Pointer region)4365 NLM_EXTERN Boolean LIBCALL ObjMgrAlsoSelect (Uint2 entityID, Uint4 itemID,
4366                      Uint2 itemtype, Uint1 regiontype, Pointer region)
4367 {
4368     ObjMgrPtr omp;
4369     Boolean retval;
4370                 /* if already selected, just deselect */
4371 /**
4372     if (ObjMgrDeSelect(entityID, itemID, itemtype, regiontype, region))
4373         return FALSE;
4374 **/
4375     omp = ObjMgrWriteLock();
4376 
4377     retval = ObjMgrSelectFunc2 (omp, entityID, itemID, itemtype, regiontype, region);
4378     if (retval) {
4379         while (retval)
4380             retval=CheckRedondantSelect (omp);
4381     }
4382     ObjMgrUnlock();
4383 
4384         return retval;
4385 
4386 }
4387 
ObjMgrDeSelectAll(void)4388 NLM_EXTERN Boolean LIBCALL ObjMgrDeSelectAll (void)
4389 {
4390     ObjMgrPtr omp;
4391     Boolean retval = FALSE;
4392 
4393     omp = ObjMgrWriteLock();
4394     retval = ObjMgrDeSelectAllFunc(omp);
4395     ObjMgrUnlock();
4396     return retval;
4397 }
4398 
ObjMgrGetSelected(void)4399 NLM_EXTERN SelStructPtr LIBCALL ObjMgrGetSelected (void)
4400 {
4401     ObjMgrPtr omp;
4402     SelStructPtr sel;
4403 
4404     omp = ObjMgrReadLock();
4405     sel = omp->sel;
4406     ObjMgrUnlock();
4407     return sel;
4408 }
4409 
4410 /*****************************************************************************
4411 *
4412 *   ObjMgrSendMsg(msg, entityID, itemID, itemtype)
4413 *       Directly invokes the objmgr messaging system
4414 *       should be used cautiously
4415 *
4416 *****************************************************************************/
ObjMgrSendMsg(Uint2 msg,Uint2 entityID,Uint4 itemID,Uint2 itemtype)4417 NLM_EXTERN Boolean LIBCALL ObjMgrSendMsg(Uint2 msg, Uint2 entityID, Uint4 itemID, Uint2 itemtype)
4418 {
4419     ObjMgrPtr omp;
4420     ObjMgrDataPtr omdp;
4421     Boolean retval = FALSE;
4422 
4423     if (msg == OM_MSG_UPDATE) {
4424         SeqMgrClearFeatureIndexes (entityID, NULL);
4425     } else if (msg == OM_MSG_DEL) {
4426         SeqMgrClearFeatureIndexes (entityID, NULL);
4427       ObjMgrDeSelect (entityID, itemID, itemtype, 0, NULL);
4428     }
4429     omp = ObjMgrReadLock();
4430     omdp = ObjMgrFindByEntityID(omp, entityID, NULL);
4431     if (omdp != NULL)
4432     {
4433         ObjMgrSendMsgFunc(omp, omdp, msg, entityID, itemID, itemtype, 0, 0, 0, NULL);
4434         retval = TRUE;
4435     }
4436     ObjMgrUnlock();
4437     return retval;
4438 }
4439 
4440 
ObjMgrSendMsgOnlyFeatLabelChange(Uint2 msg,Uint2 entityID,Uint4 itemID,Uint2 itemtype)4441 NLM_EXTERN Boolean LIBCALL ObjMgrSendMsgOnlyFeatLabelChange (Uint2 msg, Uint2 entityID, Uint4 itemID, Uint2 itemtype)
4442 {
4443     ObjMgrPtr omp;
4444     ObjMgrDataPtr omdp;
4445     Boolean retval = FALSE;
4446 
4447     if (msg == OM_MSG_UPDATE) {
4448         SeqMgrRedoFeatByLabelIndexes (entityID, NULL);
4449     } else if (msg == OM_MSG_DEL) {
4450         SeqMgrRedoFeatByLabelIndexes (entityID, NULL);
4451       ObjMgrDeSelect (entityID, itemID, itemtype, 0, NULL);
4452     }
4453     omp = ObjMgrReadLock();
4454     omdp = ObjMgrFindByEntityID(omp, entityID, NULL);
4455     if (omdp != NULL)
4456     {
4457         ObjMgrSendMsgFunc(omp, omdp, msg, entityID, itemID, itemtype, 0, 0, 0, NULL);
4458         retval = TRUE;
4459     }
4460     ObjMgrUnlock();
4461     return retval;
4462 }
4463 
4464 
4465 
ObjMgrSendMsgNoFeatureChange(Uint2 msg,Uint2 entityID,Uint4 itemID,Uint2 itemtype)4466 NLM_EXTERN Boolean LIBCALL ObjMgrSendMsgNoFeatureChange(Uint2 msg, Uint2 entityID, Uint4 itemID, Uint2 itemtype)
4467 {
4468     ObjMgrPtr omp;
4469     ObjMgrDataPtr omdp;
4470     Boolean retval = FALSE;
4471 
4472     if (msg == OM_MSG_UPDATE) {
4473       SeqMgrRedoDescriptorIndexes (entityID, NULL);
4474     } else if (msg == OM_MSG_DEL) {
4475       SeqMgrRedoDescriptorIndexes (entityID, NULL);
4476       ObjMgrDeSelect (entityID, itemID, itemtype, 0, NULL);
4477     }
4478 
4479     omp = ObjMgrReadLock();
4480     omdp = ObjMgrFindByEntityID(omp, entityID, NULL);
4481     if (omdp != NULL)
4482     {
4483         ObjMgrSendMsgFunc(omp, omdp, msg, entityID, itemID, itemtype, 0, 0, 0, NULL);
4484         retval = TRUE;
4485     }
4486     ObjMgrUnlock();
4487     return retval;
4488 }
4489 
4490 
ObjMgrSendProcMsg(Uint2 msg,Uint2 entityID,Uint4 itemID,Uint2 itemtype,Uint2 fromProcID,Uint2 toProcID,Pointer procmsgdata)4491 NLM_EXTERN Boolean LIBCALL ObjMgrSendProcMsg(Uint2 msg, Uint2 entityID, Uint4 itemID, Uint2 itemtype,
4492                                              Uint2 fromProcID, Uint2 toProcID, Pointer procmsgdata)
4493 {
4494     ObjMgrPtr omp;
4495     ObjMgrDataPtr omdp;
4496     Boolean retval = FALSE;
4497 
4498     omp = ObjMgrReadLock();
4499     omdp = ObjMgrFindByEntityID(omp, entityID, NULL);
4500     if (omdp != NULL)
4501     {
4502         ObjMgrSendMsgFunc(omp, omdp, msg, entityID, itemID, itemtype, 0, fromProcID, toProcID, procmsgdata);
4503         retval = TRUE;
4504     }
4505     ObjMgrUnlock();
4506     return retval;
4507 }
4508 
ObjMgrSendRowMsg(Uint2 msg,Uint2 entityID,Uint4 itemID,Uint2 itemtype,Uint2 rowID)4509 NLM_EXTERN Boolean LIBCALL ObjMgrSendRowMsg(Uint2 msg, Uint2 entityID, Uint4 itemID, Uint2 itemtype, Uint2 rowID)
4510 {
4511     ObjMgrPtr omp;
4512     ObjMgrDataPtr omdp;
4513     Boolean retval = FALSE;
4514 
4515     omp = ObjMgrReadLock();
4516     omdp = ObjMgrFindByEntityID(omp, entityID, NULL);
4517     if (omdp != NULL)
4518     {
4519         ObjMgrSendMsgFunc(omp, omdp, msg, entityID, itemID, itemtype, rowID, 0, 0, NULL);
4520         retval = TRUE;
4521     }
4522     ObjMgrUnlock();
4523     return retval;
4524 }
4525 
4526 /*****************************************************************************
4527 *
4528 *   ObjMgrGenericAsnTextFileRead(filename, datatypeptr, entityIDptr)
4529 *      reads an asn1 text file for any datatype registered with the ObjMgr.
4530 *      filename may contain a path
4531 *      scans the start of the file to figure out the type.
4532 *
4533 *      if it fails, it returns NULL
4534 *      if it succeeds, it returns a Pointer to the loaded data object
4535 *          if datatypeptr is not NULL, fills it in with the proper OBJ_...
4536 *          if entityIDptr is not NULL,
4537 *                 it registers the data with the object manager
4538 *                 it fills in entityIDptr with the entityID of the loaded object
4539 *
4540 *****************************************************************************/
ObjMgrGenericAsnTextFileRead(CharPtr filename,Uint2Ptr datatypeptr,Uint2Ptr entityIDptr)4541 NLM_EXTERN Pointer LIBCALL ObjMgrGenericAsnTextFileRead (CharPtr filename,
4542                                    Uint2Ptr datatypeptr, Uint2Ptr entityIDptr)
4543 {
4544     Char line[255];
4545     FILE * fp;
4546     AsnIoPtr aip;
4547     Pointer ptr = NULL;
4548     Int2 ct, i;
4549     ObjMgrPtr omp;
4550     ObjMgrTypePtr omtp = NULL;
4551 
4552     if (filename == NULL)
4553         return ptr;
4554 
4555     if (datatypeptr != NULL) *datatypeptr = 0;
4556     if (entityIDptr != NULL) *entityIDptr = 0;
4557 
4558     fp = FileOpen(filename, "r");
4559     ct = FileRead(line, 1, 255, fp);
4560     for (i = 0; i < ct; i++)
4561     {
4562         if (line[i] == ':')
4563         {
4564             if ((line[i+1] == ':') && (line[i+2] == '='))
4565             {
4566                 line[i] = '\0';
4567                 i--;
4568                 while ((i >= 0) && (IS_WHITESP(line[i])))
4569                 {
4570                     line[i] = '\0';
4571                     i--;
4572                 }
4573                 while ((i >= 0) && (! IS_WHITESP(line[i])))
4574                     i--;
4575                 omp = ObjMgrReadLock();
4576                 omtp = ObjMgrTypeFind(omp, 0, &(line[i+1]), NULL);
4577                 ObjMgrUnlock();
4578                 if (omtp == NULL)
4579                 {
4580                     FileClose(fp);
4581                     ErrPostEx(SEV_ERROR, 0,0, "Can't read ASN.1 type [%s]",
4582                         &(line[i+1]));
4583                     return ptr;
4584                 }
4585                 break;
4586             }
4587         }
4588     }
4589 
4590     if (omtp == NULL)
4591     {
4592         FileClose(fp);
4593         ErrPostEx(SEV_ERROR,0,0,"Don't know how to read file [%s]", filename);
4594         return ptr;
4595     }
4596 
4597     fseek(fp, (long)(i+1), SEEK_SET);
4598     aip = AsnIoNew(ASNIO_TEXT_IN, fp, NULL, NULL, NULL);
4599     if (aip != NULL)
4600         aip->fname = StringSave(filename);
4601     ptr = (*(omtp->asnread))(aip, NULL);
4602     AsnIoClose(aip);
4603     if (ptr == NULL)
4604     {
4605         ErrPostEx(SEV_ERROR,0,0,"Couldn't read [%s], type [%s]", filename, omtp->asnname);
4606     }
4607     else
4608     {
4609         if (datatypeptr != NULL)
4610             *datatypeptr = omtp->datatype;
4611         if (entityIDptr != NULL)
4612             *entityIDptr = ObjMgrRegister(omtp->datatype, ptr);
4613     }
4614 
4615     return ptr;
4616 }
4617 
4618 /***********************************************************************************
4619 *
4620 *  ObjMgrMemCopy(type, ptr)
4621 *    Uses AsnIoMemCopy to make a copy of any ObjMgr supported type
4622 *    ObjMgrType for "type" must have been previously loaded
4623 *
4624 ***********************************************************************************/
ObjMgrMemCopy(Uint2 type,Pointer ptr)4625 NLM_EXTERN Pointer LIBCALL ObjMgrMemCopy (Uint2 type, Pointer ptr)
4626 {
4627     Pointer newptr = NULL;
4628     ObjMgrPtr omp;
4629 
4630     if (ptr == NULL) return newptr;
4631 
4632      omp = ObjMgrReadLock();
4633     newptr = ObjMgrMemCopyFunc(omp, type, ptr, TRUE);
4634 
4635     return newptr;
4636 }
4637 
ObjMgrMemCopyFunc(ObjMgrPtr omp,Uint2 type,Pointer ptr,Boolean unlock)4638 static Pointer NEAR ObjMgrMemCopyFunc (ObjMgrPtr omp, Uint2 type, Pointer ptr, Boolean unlock)
4639 {
4640     Pointer newptr = NULL;
4641     ObjMgrTypePtr omtp;
4642 
4643     if (ptr == NULL) {
4644 
4645             if (unlock)
4646         ObjMgrUnlock();
4647 
4648             return newptr;
4649         }
4650 
4651     omtp = ObjMgrTypeFind(omp, type, NULL, NULL);
4652     if (unlock)
4653         ObjMgrUnlock();
4654     if (omtp == NULL) return newptr;
4655 
4656     newptr = AsnIoMemCopy(ptr, omtp->asnread, omtp->asnwrite);
4657 
4658     return newptr;
4659 }
4660 
4661 /***********************************************************************************
4662 *
4663 *  ObjMgrFree(type, ptr)
4664 *    ObjMgrType for "type" must have been previously loaded
4665 *
4666 ***********************************************************************************/
ObjMgrFree(Uint2 type,Pointer ptr)4667 NLM_EXTERN Pointer LIBCALL ObjMgrFree (Uint2 type, Pointer ptr)
4668 {
4669     Pointer newptr = NULL;
4670     ObjMgrPtr omp;
4671 
4672     if (ptr == NULL) return newptr;
4673 
4674      omp = ObjMgrReadLock();
4675     newptr = ObjMgrFreeFunc(omp, type, ptr, TRUE);
4676 
4677     return newptr;
4678 }
4679 
ObjMgrFreeByEntityID(Uint2 entityID)4680 NLM_EXTERN Pointer LIBCALL ObjMgrFreeByEntityID (Uint2 entityID)
4681 {
4682     ObjMgrDataPtr omdp;
4683     Uint2 type;
4684     Pointer ptr;
4685 
4686     if (entityID < 1) return NULL;
4687     omdp = ObjMgrGetData (entityID);
4688     if (omdp == NULL) return NULL;
4689 
4690     if (omdp->choice != NULL) {
4691         type = omdp->choicetype;
4692         ptr = omdp->choice;
4693     } else {
4694         type = omdp->datatype;
4695         ptr = omdp->dataptr;
4696     }
4697 
4698     return ObjMgrFree (type, ptr);
4699 }
4700 
ObjMgrFreeFunc(ObjMgrPtr omp,Uint2 type,Pointer ptr,Boolean unlock)4701 static Pointer NEAR ObjMgrFreeFunc (ObjMgrPtr omp, Uint2 type, Pointer ptr, Boolean unlock)
4702 {
4703     Pointer newptr = NULL;
4704     ObjMgrTypePtr omtp;
4705 
4706     if (ptr == NULL) {
4707             if (unlock)
4708         ObjMgrUnlock();
4709             return newptr;
4710         }
4711 
4712     omtp = ObjMgrTypeFind(omp, type, NULL, NULL);
4713 
4714     if (unlock)
4715         ObjMgrUnlock();
4716     if (omtp == NULL) return newptr;
4717     (*(omtp->freefunc))(ptr);
4718 
4719     return newptr;
4720 }
4721 
ObjMgrResetAll(void)4722 NLM_EXTERN void LIBCALL ObjMgrResetAll (void)
4723 {
4724     Int4 ret;
4725 
4726     if (global_omp == NULL)
4727         return;
4728 
4729     ret = NlmMutexLockEx(&omp_mutex);  /* protect this section */
4730     if (ret) { /* error */
4731         ErrPostEx(SEV_FATAL,0,0,"ObjMgrResetAll failed [%ld]", (long)ret);
4732         return;
4733     }
4734 
4735     global_omp = (ObjMgrPtr) MemFree(global_omp);
4736     NlmRWdestroy(omp_RWlock);
4737     omp_RWlock = NULL;
4738 
4739     NlmMutexUnlock(omp_mutex);
4740 
4741     return;
4742 }
4743 
4744 static CharPtr objmgrtypestrs [] = {
4745   "OBJ_ALL", "OBJ_SEQENTRY", "OBJ_BIOSEQ", "OBJ_BIOSEQSET", "OBJ_SEQDESC",
4746   "OBJ_SEQANNOT", "OBJ_ANNOTDESC", "OBJ_SEQFEAT", "OBJ_SEQALIGN", "OBJ_SEQGRAPH",
4747   "OBJ_SEQSUB", "OBJ_SUBMIT_BLOCK", "OBJ_SEQSUB_CONTACT", "13", "OBJ_BIOSEQ_MAPFEAT",
4748   "OBJ_BIOSEQ_SEG", "OBJ_SEQHIST", "OBJ_SEQHIST_ALIGN", "OBJ_BIOSEQ_DELTA", "19",
4749   "OBJ_PUB", "OBJ_SEQFEAT_CIT", "OBJ_SEQSUB_CIT", "OBJ_MEDLINE_ENTRY", "OBJ_PUB_SET",
4750   "OBJ_SEQLOC", "OBJ_SEQID", "OBJ_SEQCODE", "OBJ_SEQCODE_SET", "OBJ_GENETIC_CODE",
4751   "OBJ_GENETIC_CODE_SET", "OBJ_TEXT_REPORT", "OBJ_FASTA", "OBJ_VIBRANT_PICTURE", "OBJ_PROJECT"
4752 };
4753 
4754 static CharPtr temploadstrs [] = {
4755   "TL_NOT_TEMP", "TL_LOADED", "TL_CACHED"
4756 };
4757 
4758 static CharPtr proctypestrs [] = {
4759   "0", "OMPROC_OPEN", "OMPROC_DELETE", "OMPROC_VIEW", "OMPROC_EDIT",
4760   "OMPROC_SAVE", "OMPROC_CUT", "OMPROC_COPY", "OMPROC_PASTE", "OMPROC_ANALYZE",
4761   "OMPROC_FIND", "OMPROC_REPLACE", "OMPROC_FILTER", "OMPROC_FETCH",
4762 };
4763 
PrintABool(FILE * fp,CharPtr str,Boolean val)4764 static void PrintABool (FILE *fp, CharPtr str, Boolean val)
4765 
4766 {
4767   if (val) {
4768     fprintf (fp, "%s TRUE\n", str);
4769   } else {
4770     fprintf (fp, "%s FALSE\n", str);
4771   }
4772 }
4773 
ReportOnEntity(ObjMgrDataPtr omdp,ObjMgrPtr omp,Boolean selected,Uint4 itemID,Uint2 itemtype,Int2 index,FILE * fp)4774 static void ReportOnEntity (ObjMgrDataPtr omdp, ObjMgrPtr omp, Boolean selected,
4775                             Uint4 itemID, Uint2 itemtype, Int2 index, FILE *fp)
4776 
4777 {
4778   BioseqPtr      bsp;
4779   BioseqSetPtr   bssp;
4780   Char           buf [50];
4781   OMUserDataPtr  omudp;
4782 
4783   if (omdp == NULL || fp == NULL) return;
4784   if (selected) {
4785     fprintf (fp, "Data Element\n\n");
4786     fprintf (fp, "  EntityID %d selected\n", (int) omdp->EntityID);
4787     fprintf (fp, "  ItemID %d, Itemtype %d\n", (int) itemID, (int) itemtype);
4788   } else if (omdp->parentptr == NULL) {
4789     fprintf (fp, "Top Data Element %d\n\n", (int) index);
4790     fprintf (fp, "  EntityID %d\n", (int) omdp->EntityID);
4791   } else {
4792     fprintf (fp, "Inner Data Element %d\n\n", (int) index);
4793     fprintf (fp, "  EntityID %d\n", (int) omdp->EntityID);
4794   }
4795   if (omdp->datatype < OBJ_MAX) {
4796     fprintf (fp, "  Datatype %s", objmgrtypestrs [omdp->datatype]);
4797     if (omdp->datatype == OBJ_BIOSEQ) {
4798       bsp = (BioseqPtr) omdp->dataptr;
4799       if (bsp != NULL) {
4800         SeqIdWrite (bsp->id, buf, PRINTID_FASTA_LONG, sizeof (buf) - 1);
4801         fprintf (fp, " %s, length %ld", buf, (long) bsp->length);
4802       }
4803     } else if (omdp->datatype == OBJ_BIOSEQSET) {
4804       bssp = (BioseqSetPtr) omdp->dataptr;
4805       if (bssp != NULL) {
4806         fprintf (fp, " class %d", (int) bssp->_class);
4807       }
4808     }
4809     fprintf (fp, "\n");
4810   } else {
4811     fprintf (fp, "  Unregistered datatype %d\n", (int) omdp->datatype);
4812   }
4813   fprintf (fp, "  Lockcnt %d\n", (int) omdp->lockcnt);
4814   if (omdp->tempload < 3) {
4815     fprintf (fp, "  Tempload %s\n", temploadstrs [omdp->tempload]);
4816   } else {
4817     fprintf (fp, "  Unrecognized tempload %d\n", (int) omdp->tempload);
4818   }
4819   PrintABool (fp, "  Clipboard", omdp->clipboard);
4820   PrintABool (fp, "  Dirty", omdp->dirty);
4821   PrintABool (fp, "  Being_freed", omdp->being_freed);
4822   PrintABool (fp, "  Free", omdp->free);
4823   fprintf (fp, "\n");
4824   for (omudp = omdp->userdata; omudp != NULL; omudp = omudp->next) {
4825     if (omudp->proctype <= OMPROC_MAX) {
4826       fprintf (fp, "    Proctype %s\n", proctypestrs [omudp->proctype]);
4827     } else {
4828       fprintf (fp, "    Unrecognized proctype %d\n", (int) omudp->proctype);
4829     }
4830     fprintf (fp, "    Procid %d\n", (int) omudp->procid);
4831     fprintf (fp, "    Userkey %d\n", (int) omudp->userkey);
4832     fprintf (fp, "\n");
4833   }
4834 }
4835 
4836 
ObjMgrReportProc(FILE * fp)4837 NLM_EXTERN void LIBCALL ObjMgrReportProc (FILE *fp)
4838 
4839 {
4840   Uint4          j;
4841   Uint4          num;
4842   ObjMgrPtr      omp;
4843   ObjMgrDataPtr  omdp;
4844   ObjMgrDataPtr  PNTR omdpp;
4845 
4846   if (fp == NULL) return;
4847   omp = ObjMgrGet ();
4848   if (omp == NULL) return;
4849   fprintf (fp, "Object Manager\n\n");
4850   fprintf (fp, "  HighestEntityID %d\n", (int) omp->HighestEntityID);
4851   fprintf (fp, "  Totobj %d\n", (int) omp->totobj);
4852   fprintf (fp, "  Currobj %d\n", (int) omp->currobj);
4853   fprintf (fp, "  Maxtemp %d\n", (int) omp->maxtemp);
4854   fprintf (fp, "  Tempcnt %d\n", (int) omp->tempcnt);
4855   fprintf (fp, "  Hold %d\n", (int) omp->hold);
4856   PrintABool (fp, "  Reaping", omp->reaping);
4857   PrintABool (fp, "  Is_write_locked", omp->is_write_locked);
4858   fprintf (fp, "\n");
4859   num = omp->currobj;
4860   for (j = 0, omdpp = omp->datalist; j < num && omdpp != NULL; j++, omdpp++) {
4861     omdp = *omdpp;
4862     if (omdp->parentptr == NULL) {
4863       ReportOnEntity (omdp, omp, FALSE, 0, 0, j + 1, fp);
4864     }
4865   }
4866   for (j = 0, omdpp = omp->datalist; j < num && omdpp != NULL; j++, omdpp++) {
4867     omdp = *omdpp;
4868     if (omdp->parentptr != NULL) {
4869       ReportOnEntity (omdp, omp, FALSE, 0, 0, j + 1, fp);
4870     }
4871   }
4872 }
4873 
4874 
ObjMgrReportFunc(CharPtr filename)4875 NLM_EXTERN void LIBCALL ObjMgrReportFunc (CharPtr filename)
4876 
4877 {
4878   FILE           *fp;
4879   Uint4          j;
4880   Uint4          num;
4881   ObjMgrPtr      omp;
4882   ObjMgrDataPtr  omdp;
4883   ObjMgrDataPtr  PNTR omdpp;
4884 
4885   omp = ObjMgrGet ();
4886   if (omp == NULL) return;
4887   fp = FileOpen (filename, "w");
4888   fprintf (fp, "Object Manager\n\n");
4889   fprintf (fp, "  HighestEntityID %d\n", (int) omp->HighestEntityID);
4890   fprintf (fp, "  Totobj %d\n", (int) omp->totobj);
4891   fprintf (fp, "  Currobj %d\n", (int) omp->currobj);
4892   fprintf (fp, "  Maxtemp %d\n", (int) omp->maxtemp);
4893   fprintf (fp, "  Tempcnt %d\n", (int) omp->tempcnt);
4894   fprintf (fp, "  Hold %d\n", (int) omp->hold);
4895   PrintABool (fp, "  Reaping", omp->reaping);
4896   PrintABool (fp, "  Is_write_locked", omp->is_write_locked);
4897   fprintf (fp, "\n");
4898   num = omp->currobj;
4899   for (j = 0, omdpp = omp->datalist; j < num && omdpp != NULL; j++, omdpp++) {
4900     omdp = *omdpp;
4901     if (omdp->parentptr == NULL) {
4902       ReportOnEntity (omdp, omp, FALSE, 0, 0, j + 1, fp);
4903     }
4904   }
4905   for (j = 0, omdpp = omp->datalist; j < num && omdpp != NULL; j++, omdpp++) {
4906     omdp = *omdpp;
4907     if (omdp->parentptr != NULL) {
4908       ReportOnEntity (omdp, omp, FALSE, 0, 0, j + 1, fp);
4909     }
4910   }
4911   FileClose (fp);
4912 }
4913 
4914 
ObjMgrCountAssignedEntityIDs(void)4915 static Uint4 LIBCALL ObjMgrCountAssignedEntityIDs (void)
4916 
4917 {
4918   Uint4  count = 0, val;
4919   Int2   idx, jdx;
4920 
4921   NlmMutexLockEx (&entityid_array_mutex);
4922   ObjMgrWriteLock ();
4923 
4924   if (! assignedIDsInited) {
4925     ObjMgrInitAssignedIDArray ();
4926   }
4927 
4928   for (idx = 0; idx < 2048; idx++) {
4929     val = assignedIDsArray [idx];
4930     if (val == 0xFFFFFFFF) {
4931       count += 32;
4932     } else if (val > 0) {
4933       for (jdx = 0; jdx < 32; jdx++) {
4934         if ((val & assignedIDsBitIdx [jdx]) != 0) {
4935           count++;
4936         }
4937       }
4938     }
4939   }
4940 
4941   ObjMgrUnlock ();
4942   NlmMutexUnlock (entityid_array_mutex);
4943 
4944   return count;
4945 }
4946 
ObjMgrStatusString(CharPtr str,size_t len)4947 NLM_EXTERN Boolean LIBCALL ObjMgrStatusString (CharPtr str, size_t len)
4948 
4949 {
4950   Char       buf [256];
4951   ObjMgrPtr  omp;
4952 
4953   if (str == NULL || len < 1) return FALSE;
4954   *str = '\0';
4955   buf [0] = '\0';
4956   omp = ObjMgrGet ();
4957   if (omp == NULL) return FALSE;
4958 
4959   sprintf (buf, "HighID %5d  NumIDs %5d  TotObj %5d  TempObj %5d",
4960            (int) omp->HighestEntityID,
4961            (int) ObjMgrCountAssignedEntityIDs (),
4962            (int) omp->totobj, (int) omp->tempcnt);
4963 
4964   StringNCpy_0 (str, buf, len);
4965   return TRUE;
4966 }
4967 
4968 NLM_EXTERN void LIBCALL
ObjMgrAddIndexOnEntityID(ObjMgrPtr omp,Uint2 entityID,ObjMgrDataPtr omdp)4969 ObjMgrAddIndexOnEntityID(ObjMgrPtr omp,Uint2 entityID,ObjMgrDataPtr omdp)
4970 {
4971     Uint1   h,l;
4972 
4973     h=entityID >> 8;
4974     l=entityID & 0xff;
4975     if(omp==NULL) omp=ObjMgrGet();
4976     if(omp){
4977         if(!omp->entityID_index){
4978             omp->entityID_index=MemNew(256*sizeof(*omp->entityID_index));
4979         }
4980         if(!omp->entityID_index[h]){
4981             omp->entityID_index[h]=MemNew(256*sizeof(**omp->entityID_index));
4982         }
4983         omp->entityID_index[h][l]=omdp;
4984     }
4985 }
4986 
4987 
4988 NLM_EXTERN void LIBCALL
ObjMgrDeleteIndexOnEntityID(ObjMgrPtr omp,Uint2 entityID)4989 ObjMgrDeleteIndexOnEntityID(ObjMgrPtr omp,Uint2 entityID)
4990 {
4991     Uint1   h,l;
4992 
4993         h=entityID >> 8;
4994         l=entityID & 0xff;
4995     if(omp==NULL) omp=ObjMgrGet();
4996     if(omp && omp->entityID_index && omp->entityID_index[h]){
4997         omp->entityID_index[h][l]=NULL;
4998     }
4999 }
5000 
5001 
5002 NLM_EXTERN ObjMgrDataPtr LIBCALL
ObjMgrLookupIndexOnEntityID(ObjMgrPtr omp,Uint2 entityID)5003 ObjMgrLookupIndexOnEntityID(ObjMgrPtr omp,Uint2 entityID)
5004 {
5005     Uint1   h,l;
5006 
5007         h=entityID >> 8;
5008         l=entityID & 0xff;
5009     if(omp==NULL) omp=ObjMgrGet();
5010     if(omp && omp->entityID_index && omp->entityID_index[h]){
5011         return omp->entityID_index[h][l];
5012     } else {
5013         return NULL;
5014     }
5015 }
5016 
DeleteRemainingViews(Uint2 entityID)5017 NLM_EXTERN Boolean DeleteRemainingViews (Uint2 entityID)
5018 {
5019   OMUserDataPtr omudp;
5020   Boolean found_desktop = FALSE, has_other = FALSE, removed_one;
5021   Uint2 procid;
5022   Uint4               i, num;
5023   ObjMgrDataPtr       omdp;
5024   ObjMgrDataPtr PNTR  omdpp;
5025   ObjMgrPtr           omp;
5026 
5027   if (entityID == 0) return FALSE;
5028   omp = ObjMgrWriteLock();
5029   if (omp == NULL)
5030   {
5031     return FALSE;
5032   }
5033 
5034   procid = ObjMgrGetProcID(omp, "NCBI DeskTop", OMPROC_EDIT);
5035 
5036   omdpp = omp->datalist;
5037   if (omdpp != NULL) {
5038     for (i = 0; i < omp->currobj && !has_other; i++) {
5039       if (omdpp[i] != NULL && omdpp[i]->EntityID == entityID && !omdpp[i]->being_freed) {
5040         omudp = omdpp[i]->userdata;
5041         while (omudp != NULL && !has_other) {
5042             if (omudp->procid != procid) {
5043                 has_other = TRUE;
5044             }
5045             omudp = omudp->next;
5046         }
5047       }
5048     }
5049     if (!has_other) {
5050       removed_one = TRUE;
5051       while (removed_one && omp->currobj > 0) {
5052         removed_one = FALSE;
5053         num = omp->currobj;
5054         omdpp = omp->datalist;
5055         for (i = 0; i < num && ! removed_one; i++) {
5056           omdp = omdpp [i];
5057           if (omdp != NULL && omdp->EntityID == entityID) {
5058             omudp = omdp->userdata;
5059             if (omudp != NULL) {
5060               ObjMgrFreeUserDataFunc (omp, entityID, omudp->procid, omudp->proctype, omudp->userkey);
5061               removed_one = TRUE;
5062             }
5063           }
5064         }
5065       }
5066     }
5067   }
5068 
5069   ObjMgrUnlock ();
5070   return found_desktop;
5071 }
5072