~ubuntu-branches/ubuntu/utopic/gridengine/utopic

« back to all changes in this revision

Viewing changes to source/libs/sgeobj/sge_range.c

  • Committer: Bazaar Package Importer
  • Author(s): Mark Hymers
  • Date: 2008-06-25 22:36:13 UTC
  • Revision ID: james.westby@ubuntu.com-20080625223613-tvd9xlhuoct9kyhm
Tags: upstream-6.2~beta2
ImportĀ upstreamĀ versionĀ 6.2~beta2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
/*___INFO__MARK_BEGIN__*/
 
3
 
 
4
/*************************************************************************
 
5
 * 
 
6
 *  The Contents of this file are made available subject to the terms of
 
7
 *  the Sun Industry Standards Source License Version 1.2
 
8
 * 
 
9
 *  Sun Microsystems Inc., March, 2001
 
10
 * 
 
11
 * 
 
12
 *  Sun Industry Standards Source License Version 1.2
 
13
 *  =================================================
 
14
 *  The contents of this file are subject to the Sun Industry Standards
 
15
 *  Source License Version 1.2 (the "License"); You may not use this file
 
16
 *  except in compliance with the License. You may obtain a copy of the
 
17
 *  License at http://gridengine.sunsource.net/Gridengine_SISSL_license.html
 
18
 * 
 
19
 *  Software provided under this License is provided on an "AS IS" basis,
 
20
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 
21
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 
22
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 
23
 *  See the License for the specific provisions governing your rights and
 
24
 *  obligations concerning the Software.
 
25
 * 
 
26
 *   The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 
27
 * 
 
28
 *   Copyright: 2001 by Sun Microsystems, Inc.
 
29
 * 
 
30
 *   All Rights Reserved.
 
31
 * 
 
32
 ************************************************************************/
 
33
 
 
34
/*___INFO__MARK_END__*/
 
35
 
 
36
#include <stdio.h>
 
37
#include <stdlib.h>
 
38
#include <string.h>
 
39
#include <sys/stat.h>
 
40
#include <ctype.h>
 
41
 
 
42
#include "sgermon.h"
 
43
#include "symbols.h"
 
44
#include "sge.h"
 
45
#include "sge_time.h"
 
46
#include "sge_log.h"
 
47
#include "sge_unistd.h"
 
48
#include "sge_dstring.h"
 
49
#include "sge_prog.h"
 
50
#include "sge_string.h"
 
51
#include "sge_all_listsL.h"
 
52
#include "sge_host.h"
 
53
#include "sge_sched.h"
 
54
#include "cull_sort.h"
 
55
#include "usage.h"
 
56
#include "parse.h"
 
57
#include "sge_parse_num_par.h"
 
58
#include "show_job.h"
 
59
#include "sge_range.h"
 
60
#include "sge_schedd_text.h"
 
61
#include "sge_answer.h"
 
62
 
 
63
#include "msg_sgeobjlib.h"
 
64
 
 
65
#define RANGE_SEPARATOR_CHARS ","
 
66
#define RANGE_LAYER BASIS_LAYER
 
67
 
 
68
 
 
69
static bool range_is_overlapping(const lListElem *range1,
 
70
                                 const lListElem *range2);
 
71
 
 
72
static void expand_range_list(lListElem *r, lList **rl);
 
73
 
 
74
/* we keep a descending sorted list of non overlapping ranges */
 
75
/* MT-NOTE: expand_range_list() is MT safe */
 
76
static void expand_range_list(lListElem *r, lList **rl)
 
77
{
 
78
   u_long32 rmin, rmax, rstep;
 
79
   lListElem *ep, *rr;
 
80
 
 
81
   DENTER(TOP_LAYER, "expand_range_list");
 
82
 
 
83
   rmin = lGetUlong(r, RN_min);
 
84
   rmax = lGetUlong(r, RN_max);
 
85
   rstep = lGetUlong(r, RN_step);
 
86
 
 
87
   /* create list */
 
88
   if (!*rl) {
 
89
      *rl = lCreateList("ranges", RN_Type);
 
90
   }
 
91
 
 
92
   if (lGetNumberOfElem(*rl) != 0) {
 
93
      ep = lFirst(*rl);
 
94
      while (ep) {
 
95
 
 
96
         if (rstep != lGetUlong(ep, RN_step) || rstep > 1 ||
 
97
             lGetUlong(ep, RN_step) > 1) {
 
98
            lInsertElem(*rl, NULL, r);
 
99
            break;
 
100
         } else if (rmin > lGetUlong(ep, RN_max)) {
 
101
 
 
102
            /* 
 
103
             ** r and ep are non-overlapping and r is to be
 
104
             ** sorted ahead of ep.
 
105
             */
 
106
            lInsertElem(*rl, NULL, r);
 
107
            break;
 
108
 
 
109
         } else if (rmax < lGetUlong(ep, RN_min)) {
 
110
            /* 
 
111
             ** r and ep are non-overlapping and r is to be
 
112
             ** sorted after ep ==> go for the next iteration
 
113
             */
 
114
            ep = lNext(ep);
 
115
            if (!ep) {
 
116
               /* We are at the end of the list ==> append r */
 
117
               lAppendElem(*rl, r);
 
118
            }
 
119
 
 
120
            continue;
 
121
 
 
122
         } else if ((rmax <= lGetUlong(ep, RN_max)) &&
 
123
                    (rmin >= lGetUlong(ep, RN_min))) {
 
124
 
 
125
            /* 
 
126
             ** r is fully contained within ep ==> delete it 
 
127
             */
 
128
            lFreeElem(&r);
 
129
            break;
 
130
 
 
131
         } else if (rmin < lGetUlong(ep, RN_min)) {
 
132
 
 
133
            /* 
 
134
             ** ep is either fully contained within r
 
135
             ** or r overlaps ep at ep's bottom ==>
 
136
             ** overwrite ep and see if further list elements
 
137
             ** are covered also;
 
138
             */
 
139
            if (rmax > lGetUlong(ep, RN_max)) {
 
140
               /* r contains ep */
 
141
               lSetUlong(ep, RN_max, rmax);
 
142
            }
 
143
            lSetUlong(ep, RN_min, rmin);
 
144
 
 
145
            /* we're already sure we can free r */
 
146
            lFreeElem(&r);
 
147
            rr = ep;
 
148
            ep = lNext(ep);
 
149
            while (ep) {
 
150
               if (rmin < lGetUlong(ep, RN_min)) {
 
151
 
 
152
                  /* it also contains this one */
 
153
                  r = ep;
 
154
                  ep = lNext(ep);
 
155
                  lRemoveElem(*rl, &r);
 
156
 
 
157
               } else if (rmin <= lGetUlong(ep, RN_max)) {
 
158
 
 
159
                  /* these overlap ==> glue them */
 
160
                  lSetUlong(rr, RN_min, lGetUlong(ep, RN_min));
 
161
 
 
162
                  r = ep;
 
163
                  ep = lNext(ep);
 
164
                  lRemoveElem(*rl, &r);
 
165
                  break;
 
166
 
 
167
               } else
 
168
                  /* they are non overlapping */
 
169
                  break;
 
170
 
 
171
               ep = lNext(ep);
 
172
            }
 
173
 
 
174
            /* we're now sure we inserted it */
 
175
            break;
 
176
         } else if (rmax > lGetUlong(ep, RN_max)) {
 
177
            /*
 
178
             ** r and ep overlap and r starts above ep
 
179
             ** ==> glue them
 
180
             */
 
181
            lSetUlong(ep, RN_max, rmax);
 
182
            lFreeElem(&r);
 
183
            break;
 
184
         }
 
185
      }
 
186
   } else {
 
187
      lAppendElem(*rl, r);
 
188
   }
 
189
 
 
190
   DRETURN_VOID;
 
191
}
 
192
 
 
193
/****** sgeobj/range/range_correct_end() **************************************
 
194
*  NAME
 
195
*     range_correct_end() -- correct end of a range element 
 
196
*
 
197
*  SYNOPSIS
 
198
*     static void range_correct_end(lListElem *this_range) 
 
199
*
 
200
*  FUNCTION
 
201
*     This function modifies the the 'end' id of the 'this_range' 
 
202
*     element if it is not correct. After the modification the 
 
203
*     'end' id is the last valid id which is part of the range. 
 
204
*
 
205
*  INPUTS
 
206
*     lListElem *this_range - RN_Type 
 
207
*
 
208
*  RESULT
 
209
*     'this_range' will be modified 
 
210
*
 
211
*  EXAMPLE
 
212
*     1-6:2 (1,3,5) will be modified to 1-5:2 
 
213
*
 
214
*  SEE ALSO
 
215
*     sgeobj/range/RN_Type 
 
216
*******************************************************************************/
 
217
void range_correct_end(lListElem *this_range)
 
218
{
 
219
   DENTER(RANGE_LAYER, "range_correct_end");
 
220
   if (this_range != NULL) {
 
221
      u_long32 start, end, step;
 
222
 
 
223
      range_get_all_ids(this_range, &start, &end, &step);
 
224
      if (step > 0) {
 
225
         if ((end - start) % step) {
 
226
            u_long32 factor;
 
227
 
 
228
            factor = (end - start) / step;
 
229
            end = start + factor * step;
 
230
            range_set_all_ids(this_range, start, end, step);
 
231
         }
 
232
      } else {
 
233
         step = end - start;
 
234
      }
 
235
      range_set_all_ids(this_range, start, end, step);
 
236
   }
 
237
   DRETURN_VOID;
 
238
}
 
239
 
 
240
/****** sgeobj/range/range_is_overlapping() ***********************************
 
241
*  NAME
 
242
*     range_is_overlapping() -- Do two ranges interleave? 
 
243
*
 
244
*  SYNOPSIS
 
245
*     static bool range_is_overlapping(const lListElem *this_elem, 
 
246
*                                      const lListElem *range) 
 
247
*
 
248
*  FUNCTION
 
249
*     True will be returned when the given ranges interleave. This
 
250
*     does not necessaryly mean that certain ids exist in both ranges. 
 
251
*
 
252
*  INPUTS
 
253
*     const lListElem *this_elem - RN_Type 
 
254
*     const lListElem *range - RN_Type 
 
255
*
 
256
*  RESULT
 
257
*     static bool - false or true 
 
258
*
 
259
*  EXAMPLE
 
260
*     1-5:3    4-10:7      => true 
 
261
*     1-5:3    5-10:6      => true 
 
262
*     1-5:3    6-10:4      => false 
 
263
*
 
264
*  SEE ALSO
 
265
*     sgeobj/range/RN_Type 
 
266
*
 
267
*  NOTES
 
268
*     MT-NOTE: range_is_overlapping() is MT safe
 
269
*******************************************************************************/
 
270
static bool range_is_overlapping(const lListElem *this_elem,
 
271
                                 const lListElem *range)
 
272
{
 
273
   bool ret = false;
 
274
 
 
275
   DENTER(RANGE_LAYER, "range_is_overlapping");
 
276
   if (this_elem != NULL && range != NULL) {
 
277
      u_long32 start1, end1, step1;
 
278
      u_long32 start2, end2, step2;
 
279
 
 
280
      range_get_all_ids(this_elem, &start1, &end1, &step1);
 
281
      range_get_all_ids(range, &start2, &end2, &step2);
 
282
      if (end1 >= start2) {
 
283
         ret = true;
 
284
      }
 
285
   }
 
286
   DRETURN(ret);
 
287
}
 
288
 
 
289
/****** sgeobj/range/range_list_initialize() **********************************
 
290
*  NAME
 
291
*     range_list_initialize() -- (Re)initialize a range list 
 
292
*
 
293
*  SYNOPSIS
 
294
*     void range_list_initialize(lList **this_list, 
 
295
*                                lList **answer_list) 
 
296
*
 
297
*  FUNCTION
 
298
*     'this_list' will be created if it does not exist. If it already
 
299
*     exists all elements contained in this list will be removed. 
 
300
*
 
301
*  INPUTS
 
302
*     lList **this_list  - Pointer to a RN_Type-list 
 
303
*     lList **answer_list - Pointer to a AN_Type-list or NULL
 
304
*
 
305
*  RESULT
 
306
*     *this_list will be an empty RN_Type list
 
307
*     *answer_list may contain error messages 
 
308
*
 
309
*  SEE ALSO
 
310
*     sgeobj/range/RN_Type 
 
311
*******************************************************************************/
 
312
void range_list_initialize(lList **this_list, lList **answer_list)
 
313
{
 
314
   DENTER(RANGE_LAYER, "range_list_initialize");
 
315
   if (this_list != NULL) {
 
316
      if (*this_list != NULL) {
 
317
         lListElem *range;
 
318
         lListElem *next_range;
 
319
 
 
320
         /* 
 
321
          * EB: CLEANUP: implement a new CULL function lEmptyList(lList *list)
 
322
          */
 
323
 
 
324
         next_range = lFirst(*this_list);
 
325
         while ((range = next_range)) {
 
326
            next_range = lNext(range);
 
327
 
 
328
            lRemoveElem(*this_list, &range);
 
329
         }
 
330
      } else {
 
331
         *this_list = lCreateList("", RN_Type);
 
332
         if (*this_list == NULL) {
 
333
            answer_list_add(answer_list, "unable to create range list",
 
334
                            STATUS_ERROR1, ANSWER_QUALITY_ERROR);
 
335
         }
 
336
      }
 
337
   }
 
338
   DRETURN_VOID;
 
339
}
 
340
 
 
341
/****** sgeobj/range/range_list_get_number_of_ids() ***************************
 
342
*  NAME
 
343
*     range_list_get_number_of_ids() -- Determines the number of ids 
 
344
*
 
345
*  SYNOPSIS
 
346
*     u_long32 range_list_get_number_of_ids(const lList *this_list) 
 
347
*
 
348
*  FUNCTION
 
349
*     This function determines the number of ids contained 
 
350
*     in 'this_list'. If 'this_list' is NULL then 0 will be returned.
 
351
*
 
352
*  INPUTS
 
353
*     const lList *this_list - RN_Type list 
 
354
*
 
355
*  RESULT
 
356
*     u_long32 - number of ids
 
357
*
 
358
*  EXAMPLE
 
359
*     1-5:2, 7-10:3, 20-23:1 (1, 3, 5, 7, 10, 20, 21, 22, 23) => 9
 
360
*
 
361
*  SEE ALSO
 
362
*     sgeobj/range/RN_Type 
 
363
*
 
364
*  NOTE
 
365
*     MT-NOTE: range_list_get_number_of_ids() is MT safe
 
366
*******************************************************************************/
 
367
u_long32 range_list_get_number_of_ids(const lList *this_list)
 
368
{
 
369
   u_long32 ret = 0;
 
370
   lListElem *range;
 
371
 
 
372
   DENTER(RANGE_LAYER, "range_list_get_number_of_ids");
 
373
   for_each(range, this_list) {
 
374
      ret += range_get_number_of_ids(range);
 
375
   }
 
376
   DRETURN(ret);
 
377
}
 
378
 
 
379
/****** sgeobj/range/range_get_number_of_ids() ********************************
 
380
*  NAME
 
381
*     range_get_number_of_ids() -- Number of ids within a range
 
382
*
 
383
*  SYNOPSIS
 
384
*     u_long32 range_get_number_of_ids(const lList *this_elem) 
 
385
*
 
386
*  FUNCTION
 
387
*     This function determines the number of ids contained 
 
388
*     in 'this_elem' 
 
389
*
 
390
*  INPUTS
 
391
*     const lList *this_elem - RN_Type element 
 
392
*
 
393
*  RESULT
 
394
*     u_long32 - number of ids
 
395
*
 
396
*  EXAMPLE
 
397
*     1-5:2 (1, 3, 5)   => 3
 
398
*
 
399
*  SEE ALSO
 
400
*     sgeobj/range/RN_Type 
 
401
*******************************************************************************/
 
402
u_long32 range_get_number_of_ids(const lListElem *this_elem)
 
403
{
 
404
   u_long32 start, end, step, ret;
 
405
 
 
406
   DENTER(RANGE_LAYER, "range_get_number_of_ids");
 
407
   range_get_all_ids(this_elem, &start, &end, &step);
 
408
   ret = 1 + (end - start) / step;
 
409
   DRETURN(ret);
 
410
}
 
411
 
 
412
/****** sgeobj/range/range_list_print_to_string() *****************************
 
413
*  NAME
 
414
*     range_list_print_to_string() -- Print range list into the string 
 
415
*
 
416
*  SYNOPSIS
 
417
*     void range_list_print_to_string(const lList *this_list, 
 
418
*                                     dstring *string, bool ignore_step,
 
419
*                                     bool comma_as_separator) 
 
420
*
 
421
*  FUNCTION
 
422
*     Print all ranges given in 'this_list' into the dynamic 'string'.
 
423
*     If 'this_list' is NULL then the word "UNDEFINED" will be added
 
424
*     to 'string'. If 'ignore_step' is 'true' then the stepsize of all
 
425
*     ranges will be suppressed.
 
426
*
 
427
*  INPUTS
 
428
*     const lList *this_list     - RN_Type 
 
429
*     dstring *string            - dynamic string 
 
430
*     bool ignore_step           - ignore step for printing
 
431
*     bool comma_as_separator    - use the format 1,2,3 instead of 1-2:
 
432
*     bool print_always_as_range - even if the range has only one id
 
433
*
 
434
*  RESULT
 
435
*     string will be modified
 
436
*
 
437
*  SEE ALSO
 
438
*     sgeobj/range/RN_Type 
 
439
*******************************************************************************/
 
440
void
 
441
range_list_print_to_string(const lList *this_list,
 
442
                           dstring *string, bool ignore_step,
 
443
                           bool comma_as_separator, bool print_always_as_range)
 
444
{
 
445
   DENTER(RANGE_LAYER, "range_list_print_to_string");
 
446
   if (string != NULL) {
 
447
      if (this_list != NULL) {
 
448
         lListElem *range;
 
449
 
 
450
         for_each(range, this_list) {
 
451
            u_long32 start, end, step;
 
452
 
 
453
            range_get_all_ids(range, &start, &end, &step);
 
454
            range_to_dstring(start, end, step, string, ignore_step, 
 
455
                             comma_as_separator, print_always_as_range);
 
456
         }
 
457
      } else {
 
458
         sge_dstring_append(string, "UNDEFINED");
 
459
      }
 
460
   }
 
461
   DRETURN_VOID;
 
462
}
 
463
 
 
464
/****** sgeobj/range/range_list_get_first_id() ********************************
 
465
*  NAME
 
466
*     range_list_get_first_id() -- First id contained in the list
 
467
*
 
468
*  SYNOPSIS
 
469
*     u_long32 range_list_get_first_id(const lList *range_list, 
 
470
*                                      lList **answer_list) 
 
471
*
 
472
*  FUNCTION
 
473
*     The first id of the first range element of the list will 
 
474
*     be returned. If 'range_list' is NULL or empty 0 will be
 
475
*     returned and 'answer_list' will be filled with an error 
 
476
*     message.
 
477
*
 
478
*  INPUTS
 
479
*     const lList *range_list - RN_Type list  
 
480
*     lList **answer_list     - Pointer to an AN_Type list 
 
481
*
 
482
*  RESULT
 
483
*     u_long32 - First id or 0
 
484
*
 
485
*  SEE ALSO
 
486
*     sgeobj/range/RN_Type 
 
487
*     sgeobj/range/range_list_get_last_id()
 
488
*
 
489
*  NOTES
 
490
*     MT-NOTE: range_list_get_first_id() is MT safe
 
491
 
 
492
******************************************************************************/
 
493
u_long32 range_list_get_first_id(const lList *range_list, lList **answer_list)
 
494
{
 
495
   u_long32 start = 0;
 
496
   lListElem *range = NULL;
 
497
 
 
498
   DENTER(RANGE_LAYER, "range_list_get_first_id");
 
499
   range = lFirst(range_list);
 
500
   if (range) {
 
501
      u_long32 end, step;
 
502
 
 
503
      range_get_all_ids(range, &start, &end, &step);
 
504
   } else {
 
505
      answer_list_add(answer_list, "range_list containes no elements",
 
506
                      STATUS_ERROR1, ANSWER_QUALITY_ERROR);
 
507
   }
 
508
   DRETURN(start);
 
509
}
 
510
 
 
511
/****** sgeobj/range/range_list_get_last_id() *********************************
 
512
*  NAME
 
513
*     range_list_get_last_id() -- Returns last id contained in the list
 
514
*
 
515
*  SYNOPSIS
 
516
*     u_long32 range_list_get_last_id(const lList *range_list, 
 
517
*                                    lList **answer_list) 
 
518
*
 
519
*  FUNCTION
 
520
*     The last id of the last range element of the list will be 
 
521
*     returned. If 'range_list' is NULL or empty 0 will be
 
522
*     returned and 'answer_list' will be filled with an error
 
523
*     message. 
 
524
*
 
525
*  INPUTS
 
526
*     const lList *range_list - RN_Type list  
 
527
*     lList **answer_list     - Pointer to an AN_Type list 
 
528
*
 
529
*  RESULT
 
530
*     u_long32 - Last id or 0
 
531
*
 
532
*  SEE ALSO
 
533
*     sgeobj/range/RN_Type 
 
534
*     sgeobj/range/range_list_get_first_id()
 
535
******************************************************************************/
 
536
u_long32 range_list_get_last_id(const lList *range_list, lList **answer_list)
 
537
{
 
538
   u_long32 end = 0;
 
539
   lListElem *range = NULL;
 
540
 
 
541
   DENTER(RANGE_LAYER, "range_list_get_last_id");
 
542
   range = lLast(range_list);
 
543
   if (range) {
 
544
      u_long32 start, step;
 
545
      range_get_all_ids(range, &start, &end, &step);
 
546
   } else {
 
547
      answer_list_add(answer_list, "range_list containes no elements",
 
548
                      STATUS_ERROR1, ANSWER_QUALITY_ERROR);
 
549
   }
 
550
   DRETURN(end);
 
551
}
 
552
 
 
553
/****** sgeobj/range/range_list_get_average() *********************************
 
554
*  NAME
 
555
*     range_list_get_average() -- Return average of all numbers in range.
 
556
*
 
557
*  SYNOPSIS
 
558
*     double range_list_get_average(const lList *this_list) 
 
559
*
 
560
*  FUNCTION
 
561
*     The average of all numbers in the range is returned. For an empty 
 
562
*     range 0 is returned.
 
563
*
 
564
*  INPUTS
 
565
*     const lList *this_list - RN_Type list  
 
566
*     u_long32 upperbound    - This is used as range upperbound if non-0
 
567
*
 
568
*  RESULT
 
569
*     double - the average
 
570
*
 
571
*  NOTES
 
572
*     MT-NOTES: range_list_get_average() is MT safe
 
573
*******************************************************************************/
 
574
double range_list_get_average(const lList *this_list, u_long32 upperbound)
 
575
{
 
576
   lListElem *range;
 
577
   double sum = 0.0;
 
578
   u_long32 id, min, max, step;
 
579
   int n = 0;
 
580
 
 
581
   for_each (range, this_list) {
 
582
      range_get_all_ids(range, &min, &max, &step);
 
583
      if (upperbound != 0) {
 
584
         max = MIN(max, upperbound);
 
585
      }   
 
586
      for (id=min; id<=max; id+= step) {
 
587
         sum += id;
 
588
         n++;
 
589
      }
 
590
   }
 
591
   return (n > 0) ? (sum/n) : 0;
 
592
}
 
593
 
 
594
/******asgeobj/range/range_list_sort_uniq_compress() **************************
 
595
*  NAME
 
596
*     range_list_sort_uniq_compress() -- makes lists fit as a fiddle 
 
597
*
 
598
*  SYNOPSIS
 
599
*     void range_list_sort_uniq_compress(lList *range_list, 
 
600
*                                        lList **answer_list) 
 
601
*
 
602
*  FUNCTION
 
603
*     After a call to this function 'range_list' fulfills 
 
604
*     following conditions:
 
605
*        (1) all ids are in ascending order
 
606
*        (2) each id is contained in the list only once
 
607
*        (3) ids are grouped so that a min of range elements exist 
 
608
*
 
609
*  INPUTS
 
610
*     lList *range_list   - RN_Type list 
 
611
*     lList **answer_list - Pointer to an AN_Type list 
 
612
*     bool correct_end    - if true, range_list is treated as id enumeration
 
613
*
 
614
*  RESULT
 
615
*     range_list will be modified 
 
616
*
 
617
*  EXAMPLE
 
618
*     12-12:7,1-7:1,3-5:2,14-16:2   => 1-7:1,12-16:2
 
619
*
 
620
*  SEE ALSO
 
621
*     sgeobj/range/RN_Type 
 
622
*
 
623
*  NOTES
 
624
*     MT-NOTE: range_list_sort_uniq_compress() is MT safe
 
625
******************************************************************************/
 
626
void range_list_sort_uniq_compress(lList *range_list, lList **answer_list, bool correct_end)
 
627
{
 
628
   DENTER(RANGE_LAYER, "range_list_sort_uniq_compress");
 
629
   if (range_list) {
 
630
      lListElem *range1, *next_range1;
 
631
      lListElem *range2, *next_range2;
 
632
      lList *tmp_list;
 
633
 
 
634
      /*
 
635
       * Sort the incomming stuff
 
636
       */
 
637
      lPSortList(range_list, "%I+", RN_min);
 
638
 
 
639
      /* 
 
640
       * Remove overlapping ranges
 
641
       */
 
642
      tmp_list = lCreateList("", RN_Type);
 
643
      if (tmp_list) {
 
644
         for (next_range1 = lFirst(range_list); (range1 = next_range1); next_range1 = lNext(range1)) {
 
645
            next_range2 = lNext(next_range1);
 
646
            if (correct_end)
 
647
               range_correct_end(range1);
 
648
            while ((range2 = next_range2)) {
 
649
               next_range2 = lNext(range2);
 
650
               if (correct_end)
 
651
                  range_correct_end(range2);
 
652
               if (range_is_overlapping(range1, range2)) {
 
653
                  range2 = lDechainElem(range_list, range2);
 
654
                  lAppendElem(tmp_list, range2);
 
655
               } else {
 
656
                  break;
 
657
               }
 
658
            }
 
659
         }
 
660
 
 
661
         /*
 
662
          * Insert all removed entries at the correct position
 
663
          */
 
664
         for_each(range1, tmp_list) {
 
665
            u_long32 start1, end1, step1;
 
666
 
 
667
            range_get_all_ids(range1, &start1, &end1, &step1);
 
668
            for (; start1 <= end1; start1 += step1) {
 
669
               range_list_insert_id(&range_list, answer_list, start1);
 
670
            }
 
671
         }
 
672
 
 
673
         lFreeList(&tmp_list);
 
674
 
 
675
         /*
 
676
          * Join sequenced ranges
 
677
          */
 
678
         range_list_compress(range_list);
 
679
      } else {
 
680
         answer_list_add(answer_list, "unable to create range list",
 
681
                         STATUS_ERROR1, ANSWER_QUALITY_ERROR);
 
682
      }
 
683
   }
 
684
   DRETURN_VOID;
 
685
}
 
686
 
 
687
/****** sgeobj/range/range_list_compress() ************************************
 
688
*  NAME
 
689
*     range_list_compress() -- Joins sequenced ranges within a list 
 
690
*
 
691
*  SYNOPSIS
 
692
*     void range_list_compress(lList *range_list) 
 
693
*
 
694
*  FUNCTION
 
695
*     Consecutive ranges within the list will be joined by this 
 
696
*     function. Following pre-conditions have to be fulfilled, so 
 
697
*     that this function works correctly:
 
698
*        (1) ids have to be in ascending order
 
699
*        (2) Only the first/last id of a range may be contained
 
700
*            in the predecessor/successor range
 
701
*
 
702
*  INPUTS
 
703
*     lList *range_list - RN_Type list 
 
704
*
 
705
*  RESULT
 
706
*     'range_list' will be modified 
 
707
*
 
708
*  EXAMPLE
 
709
*     1-3:1,4-5:1,6-8:2,8-10:2   => 1-5:1,6-10:2 
 
710
*
 
711
*  SEE ALSO
 
712
*     sgeobj/range/RN_Type 
 
713
*
 
714
*  NOTES
 
715
*     MT-NOTE: range_list_compress() is MT safe
 
716
******************************************************************************/
 
717
void range_list_compress(lList *range_list)
 
718
{
 
719
   DENTER(RANGE_LAYER, "range_list_compress");
 
720
   if (range_list != NULL) {
 
721
      lListElem *range1 = NULL;
 
722
      lListElem *range2 = NULL;
 
723
      lListElem *next_range1 = lFirst(range_list);
 
724
      lListElem *next_range2 = lNext(next_range1);
 
725
 
 
726
      while ((range1 = next_range1) && (range2 = next_range2)) {
 
727
         u_long32 start1, end1, step1;
 
728
         u_long32 start2, end2, step2;
 
729
 
 
730
         range_get_all_ids(range1, &start1, &end1, &step1);
 
731
         range_get_all_ids(range2, &start2, &end2, &step2);
 
732
         if (end1 + step1 == start2 && step1 == step2) {
 
733
            end1 = end2;
 
734
            step1 = step2;
 
735
            range_set_all_ids(range1, start1, end1, step1);
 
736
            lRemoveElem(range_list, &range2);
 
737
            range2 = NULL;
 
738
            next_range1 = range1;
 
739
         } else if (start1 == end1 && step1 == 1 && end1 == start2 - step2) {
 
740
            end1 = end2;
 
741
            step1 = step2;
 
742
            range_set_all_ids(range1, start1, end1, step1);
 
743
            lRemoveElem(range_list, &range2);
 
744
            range2 = NULL;
 
745
            next_range1 = range1;
 
746
         } else if (start2 == end2 && step2 == 1 && end1 + step1 == end2) {
 
747
            end1 = end2;
 
748
            range_set_all_ids(range1, start1, end1, step1);
 
749
            lRemoveElem(range_list, &range2);
 
750
            range2 = NULL;
 
751
            next_range1 = range1;
 
752
         } else if (start1 == end1 && start2 == end2 && step1 == step2 &&
 
753
                    step1 == 1) {
 
754
            end1 = start2;
 
755
            step1 = end1 - start1;
 
756
            range_set_all_ids(range1, start1, end1, step1);
 
757
            lRemoveElem(range_list, &range2);
 
758
            range2 = NULL;
 
759
            next_range1 = range1;
 
760
         } else {
 
761
            next_range1 = lNext(range1);
 
762
         }
 
763
         next_range2 = lNext(next_range1);
 
764
      }
 
765
   }
 
766
   DRETURN_VOID;
 
767
}
 
768
 
 
769
/****** sgeobj/range/range_list_is_id_within() ********************************
 
770
*  NAME
 
771
*     range_list_is_id_within() -- Is id contained in range list? 
 
772
*
 
773
*  SYNOPSIS
 
774
*     bool 
 
775
*     range_list_is_id_within(const lList *range_list, u_long32 id) 
 
776
*
 
777
*  FUNCTION
 
778
*     True is returned by this function if 'id' is part of at least
 
779
*     one range element of 'range_list' 
 
780
*
 
781
*  INPUTS
 
782
*     const lList *range_list - RN_Type list
 
783
*     u_long32 id             - id 
 
784
*
 
785
*  RESULT
 
786
*     bool - true or false 
 
787
*
 
788
*  SEE ALSO
 
789
*     sgeobj/range/RN_Type 
 
790
*
 
791
*  NOTES
 
792
*     MT-NOTE: range_list_is_id_within() is MT safe
 
793
*******************************************************************************/
 
794
bool range_list_is_id_within(const lList *range_list, u_long32 id)
 
795
{
 
796
   lListElem *range = NULL;
 
797
   bool ret = false;
 
798
 
 
799
   DENTER(RANGE_LAYER, "range_list_is_id_within");
 
800
   for_each(range, range_list) {
 
801
      if (range_is_id_within(range, id)) {
 
802
         ret = true;
 
803
         break;
 
804
      }
 
805
   }
 
806
   DRETURN(ret);
 
807
}
 
808
 
 
809
/****** sgeobj/range/range_list_containes_id_less_than() **********************
 
810
*  NAME
 
811
*     range_list_containes_id_less_than() -- has id less than x 
 
812
*
 
813
*  SYNOPSIS
 
814
*     bool range_list_containes_id_less_than(const lList *range_list, 
 
815
*                                            u_long32 id) 
 
816
*
 
817
*  FUNCTION
 
818
*     Is at least one id in the "range_list" less than "id" 
 
819
*
 
820
*  INPUTS
 
821
*     const lList *range_list - RN_Type list 
 
822
*     u_long32 id             - number 
 
823
*
 
824
*  RESULT
 
825
*     bool - true or false
 
826
*******************************************************************************/
 
827
bool range_list_containes_id_less_than(const lList *range_list, u_long32 id)
 
828
{
 
829
   lListElem *range = NULL;
 
830
   bool ret = false;
 
831
 
 
832
   DENTER(RANGE_LAYER, "range_list_containes_id_less_than");
 
833
   for_each(range, range_list) {
 
834
      if (range_containes_id_less_than(range, id)) {
 
835
         ret = true;
 
836
         break;
 
837
      }
 
838
   }
 
839
   DRETURN(ret);
 
840
}
 
841
 
 
842
/****** sgeobj/range/range_list_is_empty() ************************************
 
843
*  NAME
 
844
*     range_list_is_empty() -- check if id lists containes ids 
 
845
*
 
846
*  SYNOPSIS
 
847
*     bool range_list_is_empty(const lList *range_list) 
 
848
*
 
849
*  FUNCTION
 
850
*     Returns true if "range_list" containes no ids. 
 
851
*
 
852
*  INPUTS
 
853
*     const lList *range_list - RN_Type list 
 
854
*
 
855
*  RESULT
 
856
*     bool - true or false
 
857
*
 
858
*  SEE ALSO
 
859
*     sgeobj/range/RN_Type
 
860
******************************************************************************/
 
861
bool range_list_is_empty(const lList *range_list)
 
862
{
 
863
   return (range_list_get_number_of_ids(range_list) == 0 ? true : false);
 
864
}
 
865
 
 
866
/****** sgeobj/range/range_containes_id_less_than() ***************************
 
867
*  NAME
 
868
*     range_containes_id_less_than() -- is one id less than given id 
 
869
*
 
870
*  SYNOPSIS
 
871
*     bool 
 
872
*     range_containes_id_less_than(const lListElem *range, u_long32 id) 
 
873
*
 
874
*  FUNCTION
 
875
*     This function tests if at least one id in "range" is less 
 
876
*     than "id" 
 
877
*
 
878
*  INPUTS
 
879
*     const lListElem *range - RN_Type element 
 
880
*     u_long32 id            - number 
 
881
*
 
882
*  RESULT
 
883
*     bool - true or false
 
884
******************************************************************************/
 
885
bool range_containes_id_less_than(const lListElem *range, u_long32 id)
 
886
{
 
887
   bool ret = false;
 
888
 
 
889
   DENTER(RANGE_LAYER, "range_containes_id_less_than");
 
890
   if (range) {
 
891
      u_long32 start, end, step;
 
892
 
 
893
      range_get_all_ids(range, &start, &end, &step);
 
894
      if (start < id) {
 
895
         ret = true;
 
896
      }
 
897
   }
 
898
   DRETURN(ret);
 
899
}
 
900
 
 
901
/****** sgeobj/range/range_is_id_within() *************************************
 
902
*  NAME
 
903
*     range_is_id_within() -- Is id contained in range? 
 
904
*
 
905
*  SYNOPSIS
 
906
*     bool range_is_id_within(const lListElem *range, u_long32 id) 
 
907
*
 
908
*  FUNCTION
 
909
*     True is returned by this function if 'id' is part of 'range' 
 
910
*
 
911
*  INPUTS
 
912
*     const lListElem *range - RN_Type element 
 
913
*     u_long32 id            - id 
 
914
*
 
915
*  RESULT
 
916
*     bool - true or false
 
917
*
 
918
*  SEE ALSO
 
919
*     sgeobj/range/RN_Type 
 
920
*
 
921
*  NOTES
 
922
*     MT-NOTE: range_is_id_within() is MT safe
 
923
******************************************************************************/
 
924
bool range_is_id_within(const lListElem *range, u_long32 id)
 
925
{
 
926
   bool ret = false;
 
927
 
 
928
   DENTER(RANGE_LAYER, "range_is_id_within");
 
929
   if (range) {
 
930
      u_long32 start, end, step;
 
931
 
 
932
      range_get_all_ids(range, &start, &end, &step);
 
933
      if (id >= start && id <= end && ((id - start) % step) == 0) {
 
934
         ret = true;
 
935
      }
 
936
   }
 
937
   DRETURN(ret);
 
938
}
 
939
 
 
940
/****** sgeobj/range/range_list_remove_id() ***********************************
 
941
*  NAME
 
942
*     range_list_remove_id() -- remove an id from a range list 
 
943
*
 
944
*  SYNOPSIS
 
945
*     void 
 
946
*     range_list_remove_id(lList **range_list, lList **answer_list, 
 
947
*                          u_long32 id) 
 
948
*
 
949
*  FUNCTION
 
950
*     'id' will be removed from 'range_list'. 
 
951
*
 
952
*  INPUTS
 
953
*     lList **range_list  - pointer to a RN_Type list 
 
954
*     lList **answer_list - pointer to a AN_Type list 
 
955
*     u_long32 id         - new id 
 
956
*
 
957
*  RESULT
 
958
*     range_list and answer_list may be modified 
 
959
*
 
960
*  SEE ALSO
 
961
*     sgeobj/range/RN_Type 
 
962
******************************************************************************/
 
963
void range_list_remove_id(lList **range_list, lList **answer_list, u_long32 id)
 
964
{
 
965
   lListElem *range = NULL;
 
966
 
 
967
   DENTER(RANGE_LAYER, "range_list_remove_id");
 
968
   if (range_list != NULL && *range_list != NULL) {
 
969
      lListElem *next_range = lFirst(*range_list);
 
970
 
 
971
      while ((range = next_range) != NULL) {
 
972
         u_long32 start, end, step;
 
973
 
 
974
         next_range = lNext(range);
 
975
         range_get_all_ids(range, &start, &end, &step);
 
976
         if (id >= start && id <= end && ((id - start) % step) == 0) {
 
977
            if ((id == start) && ((id == end) || (id + step > end))) {
 
978
               lRemoveElem(*range_list, &range);
 
979
               break;
 
980
            } else if (id == start) {
 
981
               start += step;
 
982
               range_set_all_ids(range, start, end, step);
 
983
               break;
 
984
            } else if (id == end) {
 
985
               end -= step;
 
986
               range_set_all_ids(range, start, end, step);
 
987
               break;
 
988
            } else {
 
989
               lListElem *new_range = lCreateElem(RN_Type);
 
990
 
 
991
               if (new_range != NULL) {
 
992
                  range_set_all_ids(range, start, id - step, step);
 
993
                  range_set_all_ids(new_range, id + step, end, step);
 
994
                  lInsertElem(*range_list, range, new_range);
 
995
               } else {
 
996
                  answer_list_add(answer_list, "unable to split range element",
 
997
                                  STATUS_ERROR1, ANSWER_QUALITY_ERROR);
 
998
               }
 
999
               break;
 
1000
            }
 
1001
         }
 
1002
      }
 
1003
      if (lGetNumberOfElem(*range_list) == 0) {
 
1004
         lFreeList(range_list);
 
1005
      }
 
1006
   }
 
1007
   DRETURN_VOID;
 
1008
}
 
1009
 
 
1010
/****** sgeobj/range/range_list_move_first_n_ids() ****************************
 
1011
*  NAME
 
1012
*     range_list_move_first_n_ids() -- split a range list 
 
1013
*
 
1014
*  SYNOPSIS
 
1015
*     void range_list_move_first_n_ids(lList **range_list, 
 
1016
*                                      lList **answer_list, 
 
1017
*                                      lList **range_list2, 
 
1018
*                                      u_long32 n) 
 
1019
*
 
1020
*  FUNCTION
 
1021
*     The first 'n' ids within 'range_list' will be moved into 
 
1022
*     'range_list2'. Error messages may be found in 'answer_list' 
 
1023
*
 
1024
*  INPUTS
 
1025
*     lList **range_list  - pointer to a RN_Type list (source) 
 
1026
*     lList **answer_list - pointer to an AN_Type list 
 
1027
*     lList **range_list2 - pointer to a RN_Type list (destination) 
 
1028
*     u_long32 n          - number of ids 
 
1029
*
 
1030
*  RESULT
 
1031
*     range_list, range_list2, answer_list may be modified 
 
1032
*
 
1033
*  SEE ALSO
 
1034
*     sgeobj/range/RN_Type 
 
1035
******************************************************************************/
 
1036
void range_list_move_first_n_ids(lList **range_list, lList **answer_list,
 
1037
                                 lList **range_list2, u_long32 n)
 
1038
{
 
1039
   DENTER(RANGE_LAYER, "range_list_move_first_n_ids");
 
1040
   if (range_list && *range_list && range_list2) {
 
1041
      lListElem *range = NULL;
 
1042
      u_long32 id;
 
1043
 
 
1044
      for_each(range, *range_list) {
 
1045
         for (id = lGetUlong(range, RN_min);
 
1046
              id <= lGetUlong(range, RN_max);
 
1047
              id += lGetUlong(range, RN_step)) {
 
1048
            range_list_insert_id(range_list2, answer_list, id);
 
1049
            range_list_compress(*range_list2);
 
1050
            n--;
 
1051
            if (n == 0) {
 
1052
               break;
 
1053
            }
 
1054
         }
 
1055
      }
 
1056
      for_each(range, *range_list2) {
 
1057
         for (id = lGetUlong(range, RN_min);
 
1058
              id <= lGetUlong(range, RN_max);
 
1059
              id += lGetUlong(range, RN_step)) {
 
1060
            range_list_remove_id(range_list, answer_list, id);
 
1061
         }
 
1062
      }
 
1063
   }
 
1064
   DRETURN_VOID;
 
1065
}
 
1066
 
 
1067
/****** sgeobj/range/range_list_insert_id() ***********************************
 
1068
*  NAME
 
1069
*     range_list_insert_id() -- insert an id into a range list 
 
1070
*
 
1071
*  SYNOPSIS
 
1072
*     void range_list_insert_id(lList **range_list, lList **answer_list, 
 
1073
*                               u_long32 id) 
 
1074
*
 
1075
*  FUNCTION
 
1076
*     'id' will be inserted into 'range_list'. 
 
1077
*
 
1078
*  INPUTS
 
1079
*     lList **range_list  - pointer to a RN_Type list 
 
1080
*     lList **answer_list - pointer to a AN_Type list 
 
1081
*     u_long32 id         - new id 
 
1082
*
 
1083
*  NOTES
 
1084
*     It may be possible that 'id' is multiply contained in 'range_list' 
 
1085
*     after using this function. Use range_list_compress() or 
 
1086
*     range_list_sort_uniq_compress() to eliminate them.
 
1087
*
 
1088
*  RESULT
 
1089
*     range_list and answer_list may be modified 
 
1090
*
 
1091
*  SEE ALSO
 
1092
*     sgeobj/range/RN_Type 
 
1093
*     sgeobj/range/range_list_compress()
 
1094
*     sgeobj/range/range_list_sort_uniq_compress()
 
1095
*
 
1096
*  NOTES
 
1097
*     MT-NOTE: range_list_insert_id() is MT safe
 
1098
******************************************************************************/
 
1099
void range_list_insert_id(lList **range_list, lList **answer_list, u_long32 id)
 
1100
{
 
1101
   lListElem *range, *prev_range, *next_range;
 
1102
   int inserted = 0;
 
1103
 
 
1104
   DENTER(RANGE_LAYER, "range_insert_id");
 
1105
 
 
1106
   lPSortList(*range_list, "%I+", RN_min);
 
1107
 
 
1108
   range = NULL;
 
1109
   if (*range_list == NULL) {
 
1110
      *range_list = lCreateList("task_id_range", RN_Type);
 
1111
      if (*range_list == NULL) {
 
1112
         answer_list_add(answer_list, "unable to insert id into range",
 
1113
                         STATUS_ERROR1, ANSWER_QUALITY_ERROR);
 
1114
      }
 
1115
   }
 
1116
   prev_range = lLast(*range_list);
 
1117
   while ((next_range = range, range = prev_range)) {
 
1118
      u_long32 start, end, step;
 
1119
      u_long32 prev_start, prev_end, prev_step;
 
1120
      u_long32 next_start, next_end, next_step;
 
1121
 
 
1122
      prev_range = lPrev(range);
 
1123
      range_get_all_ids(range, &start, &end, &step);
 
1124
 
 
1125
      /* 1 */
 
1126
      if (id < end) {
 
1127
         if (prev_range) {
 
1128
            continue;
 
1129
         } else {
 
1130
            next_range = range;
 
1131
            range = prev_range;
 
1132
            prev_range = NULL;
 
1133
         }
 
1134
      }
 
1135
 
 
1136
      if (next_range) {
 
1137
         range_get_all_ids(next_range, &next_start, &next_end, &next_step);
 
1138
      }
 
1139
      if (prev_range) {
 
1140
         range_get_all_ids(prev_range, &prev_start, &prev_end, &prev_step);
 
1141
      }
 
1142
 
 
1143
      /* 2 */
 
1144
      if (next_range && id > next_start) {
 
1145
         if (((id - next_start) % next_step == 0)) {
 
1146
            /* id is already part of the range */
 
1147
            inserted = 1;
 
1148
         } else {
 
1149
            lListElem *new_range1, *new_range2;
 
1150
            u_long32 factor, prev_id, next_id;
 
1151
 
 
1152
            factor = ((id - next_start) / next_step);
 
1153
            prev_id = next_start + factor * next_step;
 
1154
            next_id = next_start + (factor + 1) * next_step;
 
1155
            range_set_all_ids(next_range, next_start, prev_id, next_step);
 
1156
            new_range1 = lCreateElem(RN_Type);
 
1157
            range_set_all_ids(new_range1, id, id, 1);
 
1158
            lInsertElem(*range_list, next_range, new_range1);
 
1159
            new_range2 = lCreateElem(RN_Type);
 
1160
            range_set_all_ids(new_range2, next_id, next_end, next_step);
 
1161
            lInsertElem(*range_list, new_range1, new_range2);
 
1162
            inserted = 1;
 
1163
         }
 
1164
      } else {
 
1165
         if ((range && (end == id)) || (next_range && (next_start == id))) {
 
1166
            /* id is already part of the range */
 
1167
            inserted = 1;
 
1168
         } else if (range && (end + step == id)) {
 
1169
            /* 3 */
 
1170
            end = id;
 
1171
            range_set_all_ids(range, start, end, step);
 
1172
            inserted = 1;
 
1173
         } else if (next_range && (next_start - next_step == id)) {
 
1174
            /* 4 */
 
1175
            next_start = id;
 
1176
            range_set_all_ids(next_range, next_start, next_end, next_step);
 
1177
            inserted = 1;
 
1178
         } else {
 
1179
            lListElem *new_range;
 
1180
 
 
1181
            /* 5 */
 
1182
            new_range = lCreateElem(RN_Type);
 
1183
            range_set_all_ids(new_range, id, id, 1);
 
1184
            lInsertElem(*range_list, range, new_range);
 
1185
            inserted = 1;
 
1186
         }
 
1187
      }
 
1188
      if (inserted) {
 
1189
         break;
 
1190
      }
 
1191
   }
 
1192
   if (!inserted) {
 
1193
      lListElem *new_range;
 
1194
 
 
1195
      new_range = lCreateElem(RN_Type);
 
1196
      range_set_all_ids(new_range, id, id, 1);
 
1197
      lAppendElem(*range_list, new_range);
 
1198
      inserted = 1;
 
1199
   }
 
1200
   DRETURN_VOID;
 
1201
}
 
1202
 
 
1203
/****** sgeobj/range/range_get_all_ids() **************************************
 
1204
*  NAME
 
1205
*     range_get_all_ids() -- reads 'start', 'end' and 'step' 
 
1206
*
 
1207
*  SYNOPSIS
 
1208
*     void range_get_all_ids(const lListElem *range, u_long32 *min, 
 
1209
*                            u_long32 *max, u_long32 *step) 
 
1210
*
 
1211
*  FUNCTION
 
1212
*     Reads 'min' (start), 'max' (end) and 'step' from a range element.
 
1213
*     If 'range' is NULL then 'min', 'max' and 'step' will be set to 0.
 
1214
*
 
1215
*  INPUTS
 
1216
*     const lListElem *range - range element of type RN_Type 
 
1217
*     u_long32 *min          - start value 
 
1218
*     u_long32 *max          - end value 
 
1219
*     u_long32 *step         - step size 
 
1220
*
 
1221
*  SEE ALSO
 
1222
*     sgeobj/range/RN_Type 
 
1223
*
 
1224
*  NOTES
 
1225
*     MT-NOTE: range_get_all_ids() is MT safe
 
1226
******************************************************************************/
 
1227
void range_get_all_ids(const lListElem *range, u_long32 *min, u_long32 *max,
 
1228
                       u_long32 *step)
 
1229
{
 
1230
   DENTER(RANGE_LAYER, "range_get_all_ids");
 
1231
   if (min != NULL && max != NULL && step != NULL) {
 
1232
      if (range != NULL) {
 
1233
         *min = lGetUlong(range, RN_min);
 
1234
         *max = lGetUlong(range, RN_max);
 
1235
         *step = lGetUlong(range, RN_step);
 
1236
      } else {
 
1237
         *min = *max = *step = 0;
 
1238
      }
 
1239
   }
 
1240
   DRETURN_VOID;
 
1241
}
 
1242
 
 
1243
/****** sgeobj/range/range_set_all_ids() **************************************
 
1244
*  NAME
 
1245
*     range_set_all_ids() -- writes 'start', 'end' and 'step' 
 
1246
*
 
1247
*  SYNOPSIS
 
1248
*     void range_set_all_ids(lListElem *range, u_long32 min, 
 
1249
*                            u_long32 max, u_long32 step) 
 
1250
*
 
1251
*  FUNCTION
 
1252
*     Writes 'min' (start), 'max' (end) and 'step' into a range element 
 
1253
*
 
1254
*  INPUTS
 
1255
*     lListElem *range - range element of type RN_Type 
 
1256
*     u_long32 min     - start value 
 
1257
*     u_long32 max     - end value 
 
1258
*     u_long32 step    - step size 
 
1259
*
 
1260
*  NOTES
 
1261
*     Step values will be nomalized. (e.g. 1-1:3 => 1-1:1)
 
1262
*
 
1263
*  SEE ALSO
 
1264
*     sgeobj/range/RN_Type 
 
1265
*
 
1266
*  NOTES
 
1267
*     MT-NOTE: range_set_all_ids() is MT safe
 
1268
******************************************************************************/
 
1269
void range_set_all_ids(lListElem *range, u_long32 min, u_long32 max,
 
1270
                       u_long32 step)
 
1271
{
 
1272
   DENTER(RANGE_LAYER, "range_set_all_ids");
 
1273
   if (range != NULL) {
 
1274
      lSetUlong(range, RN_min, min);
 
1275
      lSetUlong(range, RN_max, max);
 
1276
      if (min != max) {
 
1277
         lSetUlong(range, RN_step, step);
 
1278
      } else {
 
1279
         lSetUlong(range, RN_step, 1);
 
1280
      }
 
1281
   }
 
1282
   DRETURN_VOID;
 
1283
}
 
1284
 
 
1285
/****** sgeobj/range/range_list_calculate_union_set() *************************
 
1286
*  NAME
 
1287
*     range_list_calculate_union_set() -- Union set of two range lists 
 
1288
*
 
1289
*  SYNOPSIS
 
1290
*     void range_list_calculate_union_set(lList **range_list, 
 
1291
*                                         lList **answer_list, 
 
1292
*                                         const lList *range_list1, 
 
1293
*                                         const lList *range_list2) 
 
1294
*
 
1295
*  FUNCTION
 
1296
*     All ids contained in 'range_list1' and 'range_list2' will be 
 
1297
*     contained in 'range_list' after a call of this function.
 
1298
*      
 
1299
*
 
1300
*  INPUTS
 
1301
*     lList **range_list       - pointer to union set RN_Type list 
 
1302
*     lList **answer_list      - pointer to AN_Type list 
 
1303
*     const lList *range_list1 - first source RN_Type list 
 
1304
*     const lList *range_list2 - second source RN_Type list 
 
1305
*
 
1306
*  RESULT
 
1307
*     range_list and answer_list may be modified 
 
1308
*
 
1309
*  SEE ALSO
 
1310
*     sgeobj/range/RN_Type 
 
1311
******************************************************************************/
 
1312
void range_list_calculate_union_set(lList **range_list,
 
1313
                                    lList **answer_list,
 
1314
                                    const lList *range_list1,
 
1315
                                    const lList *range_list2)
 
1316
{
 
1317
   DENTER(RANGE_LAYER, "range_list_calculate_union_set");
 
1318
   if (range_list != NULL && (range_list1 != NULL || range_list2 != NULL)) {
 
1319
      lFreeList(range_list);
 
1320
 
 
1321
      if (range_list1 != NULL) {
 
1322
         *range_list = lCopyList("", range_list1);
 
1323
      } else {
 
1324
         *range_list = lCopyList("", range_list2);
 
1325
      }
 
1326
      if (*range_list == NULL) {
 
1327
         DTRACE;
 
1328
         goto error;
 
1329
      }
 
1330
 
 
1331
      range_list_sort_uniq_compress(*range_list, answer_list, true);
 
1332
      if (answer_list_has_error(answer_list)) {
 
1333
         DTRACE;
 
1334
         goto error;
 
1335
      }
 
1336
 
 
1337
      if (range_list1 != NULL && range_list2 != NULL) {
 
1338
         lListElem *range2 = NULL;
 
1339
 
 
1340
         for_each(range2, range_list2) {
 
1341
            u_long32 start2, end2, step2;
 
1342
 
 
1343
            range_get_all_ids(range2, &start2, &end2, &step2);
 
1344
            for (; start2 <= end2; start2 += step2) {
 
1345
               range_list_insert_id(range_list, answer_list, start2);
 
1346
            }
 
1347
         }
 
1348
         range_list_compress(*range_list);
 
1349
      }
 
1350
   }
 
1351
   DRETURN_VOID;
 
1352
 
 
1353
 error:
 
1354
   lFreeList(range_list);
 
1355
   answer_list_add(answer_list, "unable to calculate union set",
 
1356
                   STATUS_ERROR1, ANSWER_QUALITY_ERROR);
 
1357
   DRETURN_VOID;
 
1358
}
 
1359
 
 
1360
/****** sgeobj/range/range_list_calculate_difference_set() ********************
 
1361
*  NAME
 
1362
*     range_list_calculate_difference_set() -- Difference set list 
 
1363
*
 
1364
*  SYNOPSIS
 
1365
*     void range_list_calculate_difference_set(lList **range_list, 
 
1366
*                                              lList **answer_list, 
 
1367
*                                              const lList *range_list1, 
 
1368
*                                              const lList *range_list2) 
 
1369
*
 
1370
*  FUNCTION
 
1371
*     'range_list' will contain all ids part of 'range_list1' but not
 
1372
*     contained in 'range_list2' 
 
1373
*
 
1374
*  INPUTS
 
1375
*     lList **range_list       - pointer to result RN_Type list 
 
1376
*     lList **answer_list      - pointer to AN_Type list 
 
1377
*     const lList *range_list1 - first source RN_Type list 
 
1378
*     const lList *range_list2 - second source RN_Type list 
 
1379
*
 
1380
*  SEE ALSO
 
1381
*     sgeobj/range/RN_Type 
 
1382
******************************************************************************/
 
1383
void range_list_calculate_difference_set(lList **range_list,
 
1384
                                         lList **answer_list,
 
1385
                                         const lList *range_list1,
 
1386
                                         const lList *range_list2)
 
1387
{
 
1388
   DENTER(RANGE_LAYER, "range_list_calculate_difference_set");
 
1389
   if (range_list != NULL && range_list1 != NULL) {
 
1390
      lFreeList(range_list);
 
1391
      *range_list = lCopyList("difference_set range list", range_list1);
 
1392
      if (*range_list == NULL) {
 
1393
         goto error;
 
1394
      }
 
1395
 
 
1396
      range_list_sort_uniq_compress(*range_list, answer_list, true);
 
1397
      if (answer_list_has_error(answer_list)) {
 
1398
         goto error;
 
1399
      }
 
1400
 
 
1401
      if (range_list2 != NULL) {
 
1402
         lListElem *range2 = NULL;
 
1403
 
 
1404
         for_each(range2, range_list2) {
 
1405
            u_long32 start2, end2, step2;
 
1406
 
 
1407
            range_get_all_ids(range2, &start2, &end2, &step2);
 
1408
            for (; start2 <= end2; start2 += step2) {
 
1409
               range_list_remove_id(range_list, answer_list, start2);
 
1410
               if (answer_list_has_error(answer_list)) {
 
1411
                  goto error;
 
1412
               }
 
1413
            }
 
1414
         }
 
1415
         range_list_compress(*range_list);
 
1416
      }
 
1417
   }
 
1418
   DRETURN_VOID;
 
1419
 
 
1420
 error:
 
1421
   lFreeList(range_list);
 
1422
   answer_list_add(answer_list, "unable to calculate union set",
 
1423
                   STATUS_ERROR1, ANSWER_QUALITY_ERROR);
 
1424
   DRETURN_VOID;
 
1425
}
 
1426
 
 
1427
/****** sgeobj/range/range_list_calculate_intersection_set() ******************
 
1428
*  NAME
 
1429
*     range_list_calculate_intersection_set() -- Intersection set 
 
1430
*
 
1431
*  SYNOPSIS
 
1432
*     void range_list_calculate_intersection_set(lList **range_list, 
 
1433
*                                          lList **answer_list, 
 
1434
*                                          const lList *range_list1, 
 
1435
*                                          const lList *range_list2) 
 
1436
*
 
1437
*  FUNCTION
 
1438
*     'range_list' will contain all ids which are contained in 
 
1439
*     'range_list1' and also in 'range_list2'.
 
1440
*
 
1441
*  INPUTS
 
1442
*     lList **range_list       - pointer to result RN_Type list 
 
1443
*     lList **answer_list      - pointer to AN_Type list 
 
1444
*     const lList *range_list1 - first source RN_Type list 
 
1445
*     const lList *range_list2 - second source RN_Type list 
 
1446
*
 
1447
*  SEE ALSO
 
1448
*     sgeobj/range/RN_Type 
 
1449
******************************************************************************/
 
1450
void range_list_calculate_intersection_set(lList **range_list,
 
1451
                                           lList **answer_list,
 
1452
                                           const lList *range_list1,
 
1453
                                           const lList *range_list2)
 
1454
{
 
1455
   DENTER(RANGE_LAYER, "range_list_calculate_intersection_set");
 
1456
   lFreeList(range_list);
 
1457
   if (range_list1 && range_list2) {
 
1458
      lListElem *range;
 
1459
 
 
1460
      for_each(range, range_list1) {
 
1461
         u_long32 start, end, step;
 
1462
 
 
1463
         range_get_all_ids(range, &start, &end, &step);
 
1464
         for (; start <= end; start += step) {
 
1465
            if (range_list_is_id_within(range_list2, start)) {
 
1466
               lListElem *new_range;
 
1467
 
 
1468
               if (*range_list == NULL) {
 
1469
                  *range_list = lCreateList("", RN_Type);
 
1470
                  if (*range_list == NULL) {
 
1471
                     goto error;
 
1472
                  }
 
1473
               }
 
1474
               new_range = lCreateElem(RN_Type);
 
1475
               if (new_range == NULL) {
 
1476
                  goto error;
 
1477
               }
 
1478
               range_set_all_ids(new_range, start, start, 1);
 
1479
               lAppendElem(*range_list, new_range);
 
1480
            }
 
1481
         }
 
1482
      }
 
1483
      range_list_compress(*range_list);
 
1484
   }
 
1485
   DRETURN_VOID;
 
1486
 
 
1487
 error:
 
1488
   lFreeList(range_list);
 
1489
   answer_list_add(answer_list, "unable to calculate intersection set",
 
1490
                   STATUS_ERROR1, ANSWER_QUALITY_ERROR);
 
1491
   DRETURN_VOID;
 
1492
}
 
1493
 
 
1494
/****** sgeobj/range/range_to_dstring() **************************************
 
1495
*  NAME
 
1496
*     range_to_dstring() -- Appends a range to a dynamic string 
 
1497
*
 
1498
*  SYNOPSIS
 
1499
*     void range_to_dstring(u_long32 start, 
 
1500
*                                   u_long32 end, 
 
1501
*                                   int step, 
 
1502
*                                   dstring *dyn_taskrange_str) 
 
1503
*
 
1504
*  FUNCTION
 
1505
*     Appends a range to a dynamic string.
 
1506
*
 
1507
*  INPUTS
 
1508
*     u_long32 start              - min id 
 
1509
*     u_long32 end                - max id 
 
1510
*     int step                    - step size 
 
1511
*     dstring *dyn_taskrange_str  - dynamic string 
 
1512
*     int ignore_step             - ignore step for output
 
1513
*     bool use_comma_as_separator - use a comma instead of '-' and ':' for separation
 
1514
*     bool print_always_as_range - even if the range has only one id
 
1515
*
 
1516
*  SEE ALSO
 
1517
*     sgeobj/range/RN_Type 
 
1518
******************************************************************************/
 
1519
void range_to_dstring(u_long32 start, u_long32 end, int step,
 
1520
                      dstring * dyn_taskrange_str, int ignore_step,
 
1521
                      bool use_comma_as_separator, bool print_always_as_range)
 
1522
{
 
1523
   char tail[256] = "";
 
1524
   char to_char = '-'; 
 
1525
   char step_char = ':';
 
1526
 
 
1527
   if (use_comma_as_separator) {
 
1528
      to_char = ',';
 
1529
      step_char = ',';
 
1530
   }
 
1531
   if (dyn_taskrange_str->length > 0) {
 
1532
      sge_dstring_append(dyn_taskrange_str, ",");
 
1533
   }
 
1534
 
 
1535
   if (start == end && !print_always_as_range) {
 
1536
      sprintf(tail, sge_u32, start);
 
1537
   } else if (start == end && print_always_as_range) {
 
1538
      sprintf(tail, sge_u32 "%c" sge_u32, start, to_char, end);
 
1539
   } else if (start + step == end) {
 
1540
      sprintf(tail, sge_u32 "," sge_u32, start, end);
 
1541
   } else {
 
1542
      if (ignore_step) {
 
1543
         sprintf(tail, sge_u32 "%c" sge_u32, start, to_char, end);
 
1544
      } else {
 
1545
         sprintf(tail, sge_u32 "%c" sge_u32 "%c%d", start, to_char, end, step_char, step);
 
1546
      }
 
1547
   }
 
1548
   sge_dstring_append(dyn_taskrange_str, tail);
 
1549
}
 
1550
 
 
1551
/* MT-NOTE: range_parse_from_string() is MT safe */
 
1552
void range_parse_from_string(lListElem **range,
 
1553
                             lList **answer_list,
 
1554
                             const char *rstr,
 
1555
                             int step_allowed, int inf_allowed)
 
1556
{
 
1557
   const char *old_str;
 
1558
   char *dptr;
 
1559
   u_long32 rmin, rmax, ldummy, step = 1;
 
1560
   lListElem *r;
 
1561
   char msg[BUFSIZ];
 
1562
 
 
1563
   DENTER(TOP_LAYER, "range_parse_from_string");
 
1564
 
 
1565
   old_str = rstr;
 
1566
 
 
1567
   if (!strcasecmp(rstr, "UNDEFINED")) {
 
1568
      *range = NULL;
 
1569
      DRETURN_VOID;
 
1570
   }
 
1571
   r = lCreateElem(RN_Type);
 
1572
 
 
1573
   rmin = rmax = 0;
 
1574
   if (rstr[0] == '-') {
 
1575
      /* rstr e.g. is "-<n>" ==> min=1 */
 
1576
      rmin = 1;
 
1577
      rstr++;
 
1578
      if (*rstr == '\0') {
 
1579
         if (inf_allowed) {
 
1580
            /* rstr is just "-" <==> "1-inf" */
 
1581
            lSetUlong(r, RN_min, rmin);
 
1582
            lSetUlong(r, RN_max, RANGE_INFINITY);
 
1583
            *range = r;
 
1584
            DRETURN_VOID;
 
1585
         } else {
 
1586
            *range = NULL;
 
1587
            DRETURN_VOID;
 
1588
         }
 
1589
      }
 
1590
   }
 
1591
 
 
1592
   /* rstr should point to a decimal now */
 
1593
   ldummy = strtol(rstr, &dptr, 10);
 
1594
   if ((ldummy == 0) && (rstr == dptr)) {
 
1595
      sprintf(msg, MSG_GDI_INITIALPORTIONSTRINGNODECIMAL_S, rstr);
 
1596
      answer_list_add(answer_list, msg, STATUS_ESYNTAX, ANSWER_QUALITY_ERROR);
 
1597
      lFreeElem(&r);
 
1598
      *range = NULL;
 
1599
      DRETURN_VOID;
 
1600
   }
 
1601
 
 
1602
   if (rmin != 0) {
 
1603
      /* rstr is "-<n>" and ldummy contains <n>
 
1604
       * dptr poits right after <n>.
 
1605
       */
 
1606
      if (*dptr != '\0' || (step_allowed && *dptr != ':')) {
 
1607
         sprintf(msg, MSG_GDI_RANGESPECIFIERWITHUNKNOWNTRAILER_SS,
 
1608
                 old_str, rstr);
 
1609
         answer_list_add(answer_list, msg, STATUS_ESYNTAX, ANSWER_QUALITY_ERROR);
 
1610
         lFreeElem(&r);
 
1611
         *range = NULL;
 
1612
         DRETURN_VOID;
 
1613
      }
 
1614
      /* <n> is the max-value */
 
1615
      rmax = ldummy;
 
1616
 
 
1617
   } else {     /* rmin==0) */
 
1618
      /*
 
1619
       ** rstr is "<n>" or "<n>-..." and ldummy contains <n>
 
1620
       ** dptr poits right after <n>.
 
1621
       */
 
1622
      if (*dptr == '\0') {
 
1623
         /* rstr is just "<n>" */
 
1624
         rmin = ldummy;
 
1625
         rmax = ldummy;
 
1626
      } else {
 
1627
         /* rstr should be "<n>-..." */
 
1628
         if (!
 
1629
             (*dptr == '-' || isdigit((int) *(dptr + 1)) || *(dptr + 1) == '\0'
 
1630
              || (step_allowed && *dptr == ':'))) {
 
1631
            /* ... but isn't */
 
1632
            sprintf(msg, MSG_GDI_RANGESPECIFIERWITHUNKNOWNTRAILER_SS,
 
1633
                    old_str, dptr);
 
1634
            answer_list_add(answer_list, msg, STATUS_ESYNTAX, ANSWER_QUALITY_ERROR);
 
1635
            lFreeElem(&r);
 
1636
            *range = NULL;
 
1637
            DRETURN_VOID;
 
1638
         } else {
 
1639
            /* it is. set min to ldummy. now, what's after the - */
 
1640
            rmin = ldummy;
 
1641
            rstr = dptr + 1;
 
1642
            if (*rstr == '\0') {
 
1643
               /* the range string was "<n>-" <==> "ldummy-inf" */
 
1644
               if (inf_allowed) {
 
1645
                  rmax = RANGE_INFINITY;
 
1646
               } else {
 
1647
                  *range = NULL;
 
1648
                  DRETURN_VOID;
 
1649
               }
 
1650
            } else {
 
1651
               /* the trailer should contain a decimal - go for it */
 
1652
               ldummy = strtol(rstr, &dptr, 10);
 
1653
               if ((ldummy == 0) && (rstr == dptr)) {
 
1654
                  sprintf(msg, MSG_GDI_INITIALPORTIONSTRINGNODECIMAL_S, rstr);
 
1655
                  answer_list_add(answer_list, msg, STATUS_ESYNTAX,
 
1656
                                  ANSWER_QUALITY_ERROR);
 
1657
                  lFreeElem(&r);
 
1658
                  *range = NULL;
 
1659
                  DRETURN_VOID;
 
1660
               }
 
1661
 
 
1662
               if (!(*dptr == '\0' || (step_allowed && *dptr == ':'))) {
 
1663
                  sprintf(msg, MSG_GDI_RANGESPECIFIERWITHUNKNOWNTRAILER_SS,
 
1664
                          rstr, dptr);
 
1665
                  answer_list_add(answer_list, msg, STATUS_ESYNTAX,
 
1666
                                  ANSWER_QUALITY_ERROR);
 
1667
                  lFreeElem(&r);
 
1668
                  *range = NULL;
 
1669
                  DRETURN_VOID;
 
1670
               }
 
1671
               /* finally, we got the max-value in ldummy */
 
1672
               rmax = ldummy;
 
1673
 
 
1674
               if (step_allowed && *dptr && *dptr == ':') {
 
1675
                  const double epsilon = 1.0E-12;
 
1676
                  double       dbldummy;
 
1677
 
 
1678
                  rstr = dptr + 1;
 
1679
                  dbldummy = strtod(rstr, &dptr);
 
1680
                  ldummy = dbldummy;
 
1681
                  
 
1682
                  if (dbldummy > 0) {
 
1683
                     if (( dbldummy - ldummy > epsilon) ||
 
1684
                        ((ldummy == 0) && (rstr == dptr))) {
 
1685
                        sprintf(msg, MSG_GDI_INITIALPORTIONSTRINGNODECIMAL_S,
 
1686
                                rstr);
 
1687
                        answer_list_add(answer_list, msg, STATUS_ESYNTAX,
 
1688
                                        ANSWER_QUALITY_ERROR);
 
1689
                        lFreeElem(&r);
 
1690
                        *range = NULL;
 
1691
                        DRETURN_VOID;
 
1692
                     }
 
1693
                  }
 
1694
                  else if (dptr == rstr) {
 
1695
                     sprintf(msg, MSG_GDI_INITIALPORTIONSTRINGNODECIMAL_S,
 
1696
                             rstr);
 
1697
                     answer_list_add(answer_list, msg, STATUS_ESYNTAX,
 
1698
                                     ANSWER_QUALITY_ERROR);
 
1699
                     lFreeElem(&r);
 
1700
                     *range = NULL;
 
1701
                     DRETURN_VOID;
 
1702
                  }
 
1703
                  else {
 
1704
                     sprintf( msg, MSG_GDI_NEGATIVSTEP );
 
1705
                     answer_list_add(answer_list, msg, STATUS_ESYNTAX,
 
1706
                                     ANSWER_QUALITY_ERROR);
 
1707
                     lFreeElem(&r);
 
1708
                     *range = NULL;
 
1709
                     DRETURN_VOID;
 
1710
                  }
 
1711
                   
 
1712
                  if (*dptr != '\0') {
 
1713
                     sprintf(msg, MSG_GDI_RANGESPECIFIERWITHUNKNOWNTRAILER_SS,
 
1714
                             rstr, dptr);
 
1715
                     answer_list_add(answer_list, msg, STATUS_ESYNTAX,
 
1716
                                     ANSWER_QUALITY_ERROR);
 
1717
                     lFreeElem(&r);
 
1718
                     *range = NULL;
 
1719
                     DRETURN_VOID;
 
1720
                  }
 
1721
                  /* finally, we got the max-value in ldummy */
 
1722
                  step = ldummy;
 
1723
 
 
1724
               }
 
1725
            }   /* if (*rstr == '\0') -- else clause */
 
1726
         }      /* if (*dptr != '-') -- else clause */
 
1727
      } /* if (*dptr == '\0') -- else clause */
 
1728
   }    /* if (r->min != 0) -- else clause */
 
1729
 
 
1730
   /* We're ready? Not quite! We still have to check whether min<=max */
 
1731
   if (rmin > rmax) {
 
1732
      ldummy = rmax;
 
1733
      rmax = rmin;
 
1734
      rmin = ldummy;
 
1735
   }
 
1736
 
 
1737
   lSetUlong(r, RN_min, rmin);
 
1738
   lSetUlong(r, RN_max, rmax);
 
1739
   lSetUlong(r, RN_step, step);
 
1740
 
 
1741
   /* Ughhhh! Done ... */
 
1742
 
 
1743
   *range = r;
 
1744
   DRETURN_VOID;
 
1745
}
 
1746
 
 
1747
/* 
 
1748
 
 
1749
   converts a range string into a range cull list
 
1750
 
 
1751
   an undefined range return NULL
 
1752
 
 
1753
   if answer_list is delivered no exit occurs instead the function fills the 
 
1754
   answer list and returns NULL, *answer_list must be NULL !
 
1755
 
 
1756
   MT-NOTE: range_list_parse_from_string() is MT safe
 
1757
*/
 
1758
bool 
 
1759
range_list_parse_from_string(lList **this_list, lList **answer_list, 
 
1760
                             const char *string, bool just_parse, 
 
1761
                             bool step_allowed, bool inf_allowed)
 
1762
{
 
1763
   const char *s;
 
1764
   lListElem *range = NULL;
 
1765
   lList *range_list = NULL;
 
1766
   bool undefined = false, first = true;
 
1767
   struct saved_vars_s *context = NULL;
 
1768
 
 
1769
   DENTER(TOP_LAYER, "range_list_parse_from_string");
 
1770
 
 
1771
   if (!this_list) {
 
1772
      this_list = &range_list;
 
1773
   }
 
1774
 
 
1775
   for (s = sge_strtok_r(string, RANGE_SEPARATOR_CHARS, &context);
 
1776
        s; s = sge_strtok_r(NULL, RANGE_SEPARATOR_CHARS, &context)) {
 
1777
      if (!first && undefined) {
 
1778
         /* first was undefined - no more ranges allowed */
 
1779
         ERROR((SGE_EVENT, MSG_GDI_UNEXPECTEDRANGEFOLLOWINGUNDEFINED));
 
1780
         sge_free_saved_vars(context);
 
1781
         answer_list_add(answer_list, SGE_EVENT, STATUS_ESYNTAX,
 
1782
                         ANSWER_QUALITY_ERROR);
 
1783
         *this_list = NULL;
 
1784
         DRETURN(false);
 
1785
      }
 
1786
 
 
1787
      range_parse_from_string(&range, answer_list, s, 
 
1788
                              step_allowed, inf_allowed);
 
1789
 
 
1790
      if (range == NULL) {
 
1791
         if (first) {
 
1792
            undefined = true;
 
1793
         } else {
 
1794
            /* second range may not be undefined ! */
 
1795
            ERROR((SGE_EVENT, MSG_GDI_UNEXPECTEDUNDEFINEDFOLLOWINGRANGE));
 
1796
            sge_free_saved_vars(context);
 
1797
            answer_list_add(answer_list, SGE_EVENT, STATUS_ESYNTAX,
 
1798
                            ANSWER_QUALITY_ERROR);
 
1799
            *this_list = NULL;
 
1800
            DRETURN(false);
 
1801
         }
 
1802
      } else {
 
1803
         if (just_parse) {
 
1804
            lFreeElem(&range);
 
1805
         } else {
 
1806
            expand_range_list(range, this_list);
 
1807
         }
 
1808
      }
 
1809
 
 
1810
      first = false;
 
1811
   }
 
1812
   
 
1813
   sge_free_saved_vars(context);
 
1814
 
 
1815
   DRETURN(true);
 
1816
}