source: trunk/src/archiving/ew2mseed/ew2mseed_utils.c @ 5391

Revision 5391, 19.3 KB checked in by paulf, 5 years ago (diff)

minor patch to logit call, thanks to Aaron Ferris for the catch

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*=====================================================================
2// Copyright (C) 2000,2001 Instrumental Software Technologies, Inc.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions
6// are met:
7// 1. Redistributions of source code, or portions of this source code,
8//    must retain the above copyright notice, this list of conditions
9//    and the following disclaimer.
10// 2. Redistributions in binary form must reproduce the above copyright
11//    notice, this list of conditions and the following disclaimer in
12//    the documentation and/or other materials provided with the
13//    distribution.
14// 3. All advertising materials mentioning features or use of this
15//    software must display the following acknowledgment:
16//    "This product includes software developed by Instrumental
17//    Software Technologies, Inc. (http://www.isti.com)"
18// 4. If the software is provided with, or as part of a commercial
19//    product, or is used in other commercial software products the
20//    customer must be informed that "This product includes software
21//    developed by Instrumental Software Technologies, Inc.
22//    (http://www.isti.com)"
23// 5. The names "Instrumental Software Technologies, Inc." and "ISTI"
24//    must not be used to endorse or promote products derived from
25//    this software without prior written permission. For written
26//    permission, please contact "info@isti.com".
27// 6. Products derived from this software may not be called "ISTI"
28//    nor may "ISTI" appear in their names without prior written
29//    permission of Instrumental Software Technologies, Inc.
30// 7. Redistributions of any form whatsoever must retain the following
31//    acknowledgment:
32//    "This product includes software developed by Instrumental
33//    Software Technologies, Inc. (http://www.isti.com/)."
34// THIS SOFTWARE IS PROVIDED BY INSTRUMENTAL SOFTWARE
35// TECHNOLOGIES, INC. "AS IS" AND ANY EXPRESSED OR IMPLIED
36// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38// DISCLAIMED.  IN NO EVENT SHALL INSTRUMENTAL SOFTWARE TECHNOLOGIES,
39// INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
40// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
41// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
42// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
43// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
44// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
45// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
46// OF THE POSSIBILITY OF SUCH DAMAGE.
47//=====================================================================
48//  A current version of the software can be found at
49//                http://www.isti.com
50//  Bug reports and comments should be directed to
51//  Instrumental Software Technologies, Inc. at info@isti.com
52//=====================================================================
53// This work was funded by the IRIS Data Management Center
54// http://www.iris.washington.edu
55//=====================================================================
56*/
57/*
58**   THIS FILE IS UNDER RCS - DO NOT MODIFY UNLESS YOU HAVE
59**   CHECKED IT OUT USING THE COMMAND CHECKOUT.
60**
61**    $Id$
62**
63**      Revision history:
64**      $Log$
65**      Revision 1.1  2010/03/10 17:14:58  paulf
66**      first check in of ew2mseed to EW proper
67**
68**      Revision 1.5  2007/04/13 19:43:22  hal
69**      use flock instead of lockf when compiling under cygwin (which lacks lockf)
70**     
71**      Revision 1.4  2007/04/12 19:21:04  hal
72**      Added ew7.0+ support (-dSUPPORT_SCNL) and linux port (-D_LINUX)
73**     
74**      -Hal
75**     
76**      Revision 1.3  2002/12/19 00:35:00  ilya
77**      Byteswapping in shorts and doubles is fixed
78**     
79**      Revision 1.2  2002/04/02 14:42:01  ilya
80**      Version 02-Apr-2002: catchup algorithm
81**     
82**      Revision 1.1.1.1  2002/01/24 18:32:05  ilya
83**      Exporting only ew2mseed!
84**     
85**      Revision 1.1.1.1  2001/11/20 21:47:00  ilya
86**      First CVS commit
87**     
88 * Revision 1.7  2001/03/15  16:42:52  comserv
89 *      void signal_handler() modified to accomodate SIGALRM
90 *
91 * Revision 1.6  2001/02/06  17:19:32  comserv
92 * Functions logFailedSCN() resetWsTrace() are moved to ew2mseed_utils.c
93 * Functions  logFailedSCN() and  checkLock() are changed, so you can actually
94 * write data into them, and still use them for locking. int lockfd is now a global
95 * variable
96 *
97 * Revision 1.5  2001/02/06  05:53:29  comserv
98 * Added code  to make sure is that the content of the lockfile is truncated to zero.
99 * We now write SCNs which we cannot process in this file
100 *
101 * Revision 1.4  2001/01/18  21:58:20  comserv
102 * checkForGaps is modified to detect snippet overlaps
103 *
104 * Revision 1.4  2001/01/18  21:58:20  comserv
105 * checkForGaps is modified to detect snippet overlaps
106 *
107 * Revision 1.3  2001/01/17  21:56:54  comserv
108 * prerelease version ; copyright statement
109 *
110 * Revision 1.2  2001/01/08  22:55:31  comserv
111 * locking function is added
112 *
113 * Revision 1.1  2000/11/17  06:56:57  comserv
114 * Initial revision
115 *
116*/
117
118/* Standard includes */
119#include <stdio.h>
120#include <string.h>
121#include <stdlib.h>
122#include <errno.h>
123#include <sys/types.h>
124#include <sys/stat.h>
125#include <dirent.h>
126#include <signal.h>
127#include <unistd.h>
128#include <fcntl.h>
129#include <math.h>
130
131#ifdef _CYGWIN
132#  include <sys/file.h>
133#endif
134
135/* Includes from Earthworm distribution */
136#include "earthworm.h"
137
138/* Local includes */
139#include "ew2mseed.h"
140#include "swap.h"
141#include "qlib2.h"
142
143/* Global variable */
144int lockfd = -1;
145
146/***************************************************************************/
147  double getReqEndTime (double startTime, double SampRate, int samples)
148  {
149        double endTime;
150        endTime = startTime + (double)samples/SampRate;
151        return endTime; 
152  }
153
154
155/*****************************************************************************/
156/* Define how many UNCOMPRESSED bytes from WS we have to request to fill     */
157/* for sure a single MiniSEED record                                         */ 
158/* IGD 03/28/02 highWaterMark is assuming possible increase in the size of   */
159/* the requested snippet                                                     */
160/****************************************************************************/
161  long int assumeSnippetSize (int logRec, short CompAlg, short RecNum, 
162                int highWaterMark)
163  { 
164        long int bytes;
165       
166        /*Must be larger than the maximum */
167        if (CompAlg == STEIM1)
168                bytes = 2 * logRec * RecNum * highWaterMark * sizeof(int);
169        else if(CompAlg == STEIM2)
170                bytes = 4 * logRec * RecNum * highWaterMark * sizeof(int);
171        else    {
172                fprintf(stderr, "fatal error in assumeSnippetSize: %d is not supported compression algorithm\n", CompAlg);
173                logit("pt", "fatal error in assumeSnippetSize: %d is not supported compression algorithm\n", CompAlg);
174                return -1;
175                }
176        return bytes;
177  }
178
179/***************************************************************************/
180
181  void makeSNCLoop (RINGS *rn)
182  {
183        int i; 
184        struct SCN_ring *scn_head;
185
186        scn_head = rn->scnRing; 
187
188        for (i=0; i < rn->SCN_avail-1; i++)
189                rn->scnRing = rn->scnRing->next;
190       
191        rn->scnRing->next = scn_head;   
192
193
194  } 
195/***************************************************************************/
196/************************************************************************/
197/*  checkForGaps:                                                       */
198/*      Reads in the sampling rate, time of the last sample of the      */ 
199/*      previous snippet and the first sample of the current snippet.   */
200/*      Checks for the data consistency                                 */
201/*  returns:                                                            */
202/*      0 if there is no gaps (tears) or overlaps                       */
203/*      positive double gap in seconds or negative overlap in seconds   */
204/*                                                                      */
205/************************************************************************/ 
206  double checkForGaps (double prevEndTime, double startTime, double sampRate)
207  {
208        double smallValue, invSampRate;
209
210        invSampRate = 1./sampRate;
211        smallValue = invSampRate/10.;
212
213        /* Here is the gap
214         ****************************/ 
215        if ((prevEndTime + invSampRate + smallValue) < startTime )
216                return (startTime - prevEndTime - invSampRate);  /*positive */
217
218        /* Here is the overlap
219         ***************************/
220        if ((prevEndTime + invSampRate - smallValue) > startTime )
221                return (startTime - prevEndTime - invSampRate); /* negative */
222
223        return 0;
224  }
225/****************************************************************************/
226  long ew2mseedAddData (int *buffer, char *msg_p, long position, int bufLen, char swap, int bytesPerSample)
227  {     float *fBuf = NULL;
228        double *dBuf = NULL;
229        int *iBuf = NULL;
230        short *sBuf= NULL;
231        int i;
232
233        if (swap == 't' && bytesPerSample == 8) /*t8 SUN IEEE double precision real */
234        {
235                dBuf = (double *) msg_p;
236                for (i = 0; i< bufLen; i ++)
237                {
238                        double tmp;
239                        tmp = *(sBuf + i);
240#if defined _INTEL
241                        ew2mseed_SwapDouble(&tmp, 't'); 
242#endif
243                        *(buffer + i+ position) = (int)tmp;     
244                }
245        }       
246        else if (swap == 't' && bytesPerSample == 4) /*t4 SUN IEEE single precision real */
247        {
248                fBuf = (float *) msg_p;
249                for (i = 0; i< bufLen; i ++)
250                {
251                        *(buffer + i+ position) = (int) *(fBuf + i);
252#if defined _INTEL
253                        SwapInt(buffer+i+position);
254#endif 
255                }       
256        }
257        else if (swap == 's' && bytesPerSample == 4) /*s4 SUN IEEE integer */
258        {
259                iBuf = (int *) msg_p;
260                for (i = 0; i< bufLen; i ++)
261                {
262                        *(buffer + i+ position) = (int) *(iBuf + i);
263#if defined _INTEL
264                        SwapInt(buffer+i+position);
265#endif
266                }               
267        }
268        else if (swap == 's' && bytesPerSample == 2) /*s2 SUN IEEE short integer */
269        {       
270                sBuf = (short *) msg_p;
271                for (i = 0; i< bufLen; i ++)
272                {
273                        short tmp;
274                        tmp = *(sBuf + i);
275#if defined _INTEL
276                        ew2mseed_SwapShort(&tmp, 's');
277#endif 
278                        *(buffer + i+ position) = (int) tmp;
279                }
280        }
281        else if (swap == 'f' && bytesPerSample == 8) /*f8 VAX/Intel IEEE double precision real */
282        {
283                dBuf = (double *) msg_p;
284                for (i = 0; i< bufLen; i ++)
285                {
286                        double tmp;
287                        tmp = *(sBuf + i);
288#if defined _SPARC
289                        ew2mseed_SwapDouble(&tmp, 'f');
290#endif 
291                        *(buffer + i+ position) = (int) tmp;
292                }       
293        }
294        else if (swap == 'f' && bytesPerSample == 4) /*f4 VAX/Intel IEEE single precision real */
295        {
296                fBuf = (float *) msg_p;
297                for (i = 0; i< bufLen; i ++)
298                {
299                        *(buffer + i+ position) = (int) *(fBuf + i);
300#if defined _SPARC
301                        SwapInt(buffer+i+position);
302#endif         
303                }
304        }
305        else if (swap == 'i' && bytesPerSample == 4) /*i4 VAX/Intel IEEE integer */
306        {
307                iBuf = (int *) msg_p;
308                for (i = 0; i< bufLen; i ++)
309                {
310                        *(buffer + i+ position) = (int) *(iBuf + i);
311#if defined _SPARC
312                        SwapInt(buffer+i+position);
313#endif
314                }               
315        }
316        else if (swap == 'i' && bytesPerSample == 2) /*i2 VAX/Intel IEEE short integer */       
317        {
318                sBuf = (short *) msg_p;
319                for (i = 0; i< bufLen; i ++)
320                {
321                        short tmp;
322                        tmp = *(sBuf + i);
323#if defined _SPARC
324                        ew2mseed_SwapShort(&tmp, 'i');
325#endif 
326                        *(buffer + i+ position) = (int) tmp; 
327                }               
328        }
329        else
330        {
331                return -1;
332        }
333
334        return (position + bufLen);
335  }
336
337/****************************************************************************/
338  int getBufferShift (double reqStarttime, double actStarttime, double samprate)
339  {
340        int myshift;
341        double timeDiff;
342        double verySmall = 0.000001;
343
344        if (reqStarttime < actStarttime)
345        {
346                if (reqStarttime + 0.5/samprate >= actStarttime )
347                        return 0;       
348                else
349                        return -1;
350        }
351
352        timeDiff = reqStarttime - actStarttime;
353        myshift = (int) nearbyint(timeDiff * samprate);
354        while (1)
355        {
356                if ( actStarttime + myshift/samprate - reqStarttime >= (0.5/samprate))
357                {
358                        if (fabs(actStarttime + myshift/samprate - reqStarttime - 0.5/samprate) < verySmall )
359                        {
360                                printf("fabs = %f\n", fabs(actStarttime + myshift/samprate - reqStarttime - 0.5/samprate));
361                                break;
362                        }
363                        myshift--;
364                }
365                else if (actStarttime + myshift/samprate - reqStarttime < -0.5/samprate)
366                {
367                        myshift++;
368                }
369                else
370                        break;
371        }       
372/*      printf("%d %f %f %f\n", myshift, actStarttime + myshift/samprate - reqStarttime, samprate,  timeDiff); */
373        return myshift;
374       
375  } 
376
377/****************************************************************************/
378
379  int checkCompilationFlags (char *prog)
380  {     int retVal = -2;
381#ifdef _SPARC
382        retVal = 1;
383#endif
384#ifdef  _INTEL
385        retVal = 1;
386#endif
387        if(retVal == -2)
388        {
389        fprintf(stderr, "-------------------------------------------------------\n");
390        fprintf(stderr, "%s should be compiled with -D_SPARC or -D_INTEL flags only!\n", prog);
391        fprintf(stderr, "Please recompile the program with this flag\n");
392        fprintf(stderr, "-------------------------------------------------------\n");
393        }
394
395        return(retVal);
396  }
397
398  char *strDate( double epochTime, char *dd)
399  {
400        /* Warning: dd should be allocated outside ! */
401
402
403        /* SEC1970 is a convertion from epoch to julian seconds */
404        date20(epochTime + SEC1970, dd);
405        return dd;
406  }
407
408/**********************************************************/
409
410  double findNewFileJulTime (double jtime)
411  {     
412        double nextDayJtime;
413        EXT_TIME ext_time;
414 
415        ext_time = int_to_ext (tepoch_to_int(jtime));
416        ext_time.hour = 0;
417        ext_time.minute = 0;
418        ext_time.second = 0;
419        ext_time.usec = 0;
420        /* next day */
421        nextDayJtime = int_to_tepoch(ext_to_int(ext_time)) + 24 * 60 *60;
422        return (nextDayJtime);
423 }
424  /* IGD 03/14/01 Modified for SIGALRM and
425   *********************************/
426  void signal_handler (int sig)
427  {
428        if (sig == SIGUSR1)     
429                ew_signal_flag = EW2MSEED_MAKE_REPORT; 
430        else if (sig == SIGALRM)
431                ew_signal_flag = EW2MSEED_ALARM; 
432        else
433                ew_signal_flag = EW2MSEED_TERMINATE;
434        signal(sig, signal_handler); /*Re-install handler */   
435  }
436
437  void finish_handler (RINGS *rn)
438  {
439        fprintf(stderr, "TERMINATION SIGNAL ARRIVED\n");
440        fprintf(stderr, "PROGRAM EXITS NOW\n");
441        logit("pt", "TERMINATION SIGNAL ARRIVED\n");
442        logit("pt", "PROGRAM EXITS NOW\n");
443        ew_signal_flag = EW2MSEED_OK;
444        exit(0);       
445  }
446 
447  void ew2mseedGenReport (RINGS *p_rn)
448  {
449
450
451        fprintf(stderr, "STATE-OF-HEALTH REPORT REQUEST RECEIVED\n");
452        ew2mseed_logconfig(p_rn);
453
454        fprintf(stderr, "REPORT IS WRITTEN INTO THE LOG FILE\n");
455        ew_signal_flag = EW2MSEED_OK;
456       
457       
458  }
459
460  int checkLock (char * lockfile)
461  {
462        int status;
463        if (lockfile == NULL)
464        {
465                fprintf(stderr, "This instance of ew2mseed does not use the locking mechanism!\n");
466                fprintf(stderr, "Multiple copies of ew2mseed are allowed to write into a single data file\n");
467                fprintf(stderr, "To enable locking set LockFile parameter in the configuration file\n");
468                logit ("", "This instance of ew2mseed does not use the locking mechanism!\n");
469                logit("", "Multiple copies of ew2mseed are allowed to write into a single data file\n");
470                logit("", "To enable locking set LockFile parameter in the configuration file\n");
471                return(0);
472        }
473
474        if ((lockfd = open (lockfile, O_RDWR|O_CREAT,0644)) < 0) 
475        {
476                fprintf (stderr, "Error in ew2mseed: Unable to open lockfile: %s\n", lockfile);
477                logit ("pt", "Error in ew2mseed: Unable to open lockfile: %s\n", lockfile);
478                return (-1);
479        }       
480#ifdef _CYGWIN
481        if ((status=flock(lockfd, LOCK_EX|LOCK_NB)) < 0)
482#else
483        if ((status=lockf (lockfd, F_TLOCK, 0)) < 0)
484#endif
485        {
486                fprintf (stderr, "Error in ew2mseed: Unable to lock lockfile: %s status=%d errno=%d\n", 
487                                lockfile, status, errno);
488                logit ("pt", "Error in ew2mseed Unable to lock daemon lockfile: %s status=%d errno=%d\n", 
489                                lockfile, status, errno);
490                return(-2);
491        }
492        close(lockfd);
493       
494        if ((lockfd = open (lockfile, O_RDWR|O_CREAT|O_TRUNC,0644)) < 0) 
495        {
496                fprintf (stderr, "Error in ew2mseed: Unable to open lockfile: %s\n", lockfile);
497                logit ("pt", "Error in ew2mseed: Unable to open lockfile: %s\n", lockfile);
498                return (-1);
499        }
500
501#ifdef _CYGWIN
502        if ((status=flock(lockfd, LOCK_EX|LOCK_NB)) < 0)
503#else
504        if ((status=lockf (lockfd, F_TLOCK, 0)) < 0)
505#endif
506        {
507                fprintf (stderr, "Error in ew2mseed: Unable to lock lockfile: %s status=%d errno=%d\n", 
508                                lockfile, status, errno);
509                logit ("pt", "Error in ew2mseed Unable to lock daemon lockfile: %s status=%d errno=%d\n", 
510                                lockfile, status, errno);
511                return(-2);
512        }
513        return(1); /*Success */
514       
515  }
516/*---------------------------------------------------------*/
517/* IGD 02/05/01 a function to reset TRACE_REQ * strucuture */
518
519        int resetWsTrace (TRACE_REQ* trace, double startTime, double endTime)
520        {
521                trace->bufLen = 0;
522                trace->reqStarttime = startTime;
523                trace->reqEndtime = endTime;
524                free(trace->pBuf);
525                trace->pBuf = (char *)NULL;
526                trace->timeout = 0;
527                trace->actStarttime = 0;
528                trace->actEndtime = 0;
529                trace->actLen = 0;
530                trace->retFlag = 0;
531                return 0;
532        }
533
534/* IGD this function is added on 02/05/01 */
535
536        void logFailedSCN (struct SCN_ring *failedTrace, char *lockFN) 
537        {
538               
539                char line[100];
540                char locId[5];
541                char alg[7];
542                memset(&locId[0], '\0', 5);
543                if (failedTrace->locId[0] == '\000')
544                        strcpy(locId, "NONE");
545                else
546                        strncpy(locId, failedTrace->locId, 2); 
547                if (failedTrace->CompAlg == 11)
548                        strcpy(alg, "STEIM2");
549                else if  (failedTrace->CompAlg == 10)
550                        strcpy(alg, "STEIM1");
551                else
552                        strcpy(alg, "ALG???");
553                sprintf(line, "SCNLocSZ %s %s %s %s %d %s\n",
554                        failedTrace->traceRec.sta, failedTrace->traceRec.chan,
555                        failedTrace->traceRec.net, locId, failedTrace->logRec, alg);
556
557                logit("pt", "Trace %s is removed from ew2mseed loop\n", line);
558
559                if (lockfd == -1 )
560                        fprintf(stderr,  "Trace %s is removed from ew2mseed loop\n", line);
561                else   
562                        write(lockfd, line, strlen(line));
563                return;
564        }
565
566 
567/* IGD 03/29/02 Computes priority for catchup algorithm */
568       
569void  updatePriorityValues(RINGS *rn)
570{
571 struct SCN_ring *scn_head;
572 int i; 
573 int j = 0;
574 double meanSystemTime = 0;
575 double timeFromTank = 0;       
576 int priorityFactor = 3600 * 24; /* 1 day */
577 int priority;
578 int TankPriority;
579 int previous_priority;
580               
581        /* Get the ring start */
582        scn_head = rn->scnRing;
583
584        for (i = 0; i< rn->SCN_avail; i++)     
585        {
586                /* Process uninitialized cases */
587                if (rn->scnRing->prevStarttime <= 0 ||
588                        rn->scnRing->prevEndtime <= 0)
589                {
590                        rn->scnRing->lastRequestTime = -1;
591                } 
592                else /* Normal cases */
593                {
594                        rn->scnRing->lastRequestTime =
595                                        rn->scnRing->prevEndtime;
596                        meanSystemTime += rn->scnRing->lastRequestTime;
597                        j++;
598                }
599                rn->scnRing = rn->scnRing->next;
600        }
601       
602        meanSystemTime /= j;
603
604        /* distribute priorities */
605        for (i = 0; i< rn->SCN_avail; i++)     
606        {       
607                /* See how far away we are from tank start */
608                timeFromTank = rn->scnRing->lastRequestTime -
609                        rn->scnRing->tankStarttime;
610                if (timeFromTank < 900) /* 15 mins */
611                        TankPriority = rn->PriorityHighWater;
612                else if (timeFromTank < 1800)
613                        TankPriority = rn->PriorityHighWater/2;
614                else 
615                        TankPriority = 1;
616
617                previous_priority = rn->scnRing->priority;
618
619                priority = (meanSystemTime - rn->scnRing->lastRequestTime) /
620                                priorityFactor;
621                if (TankPriority > priority)
622                        priority = TankPriority;
623 
624                if (priority < 0)
625                        rn->scnRing->priority  = 1;
626                else if (priority > rn->PriorityHighWater)
627                        rn->scnRing->priority = rn->PriorityHighWater;
628                else
629                        rn->scnRing->priority = priority;
630
631                rn->scnRing->timeInterval = rn->scnRing->timeInterval / previous_priority * rn->scnRing->priority;     
632
633                if (rn->verbosity > 3)
634                {
635                        logit("pt", "           SCN-%d   = %7s %7s %7s %7s : priority (%1d) %10.1f secs later than mean\n",
636                                i, rn->scnRing->traceRec.sta, 
637                                rn->scnRing->traceRec.chan, 
638                                rn->scnRing->traceRec.net,
639                                rn->scnRing->locId, 
640                                rn->scnRing->priority,
641                                meanSystemTime - rn->scnRing->lastRequestTime);
642
643                        logit("pt", "           SCN-%d   = %7s %7s %7s %7s:  time interval is set to %f s\n",
644                                i, rn->scnRing->traceRec.sta, 
645                                rn->scnRing->traceRec.chan, 
646                                rn->scnRing->traceRec.net,
647                                rn->scnRing->locId, 
648                                rn->scnRing->timeInterval);
649
650                }       
651                rn->scnRing = rn->scnRing->next;
652
653       
654        }
655
656        /* Set back the start of the ring */
657        rn->scnRing = scn_head;
658
659        return;
660}
Note: See TracBrowser for help on using the repository browser.