Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/elmergrid/src/egutils.c
3196 views
1
/*
2
ElmerGrid - A simple mesh generation and manipulation utility
3
Copyright (C) 1995- , CSC - IT Center for Science Ltd.
4
5
Author: Peter Raback
6
Email: [email protected]
7
Address: CSC - IT Center for Science Ltd.
8
Keilaranta 14
9
02101 Espoo, Finland
10
11
This program is free software; you can redistribute it and/or
12
modify it under the terms of the GNU General Public License
13
as published by the Free Software Foundation; either version 2
14
of the License, or (at your option) any later version.
15
16
This program is distributed in the hope that it will be useful,
17
but WITHOUT ANY WARRANTY; without even the implied warranty of
18
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
GNU General Public License for more details.
20
21
You should have received a copy of the GNU General Public License
22
along with this program; if not, write to the Free Software
23
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24
*/
25
26
#include <stdio.h>
27
#include <stddef.h>
28
#include <stdlib.h>
29
#include <string.h>
30
#include <math.h>
31
#include <sys/types.h>
32
#include <time.h>
33
34
/* Possible monitoring of memory usage, if supported */
35
#define MEM_USAGE 0
36
#if MEM_USAGE
37
#include <sys/resource.h>
38
#endif
39
40
#include "egutils.h"
41
42
#define FREE_ARG char*
43
#define SHOWMEM 0
44
45
#if SHOWMEM
46
static int nfloat=0, nint=0, cumnfloat=0, cumnint=0, locnint, locnfloat;
47
48
int MemoryUsage()
49
{
50
if(locnint > 1000 || locnfloat > 1000)
51
printf("Memory used real %d %d %d int %d %d %d\n",
52
nfloat,cumnfloat,locnfloat,nint,cumnint,locnint);
53
locnfloat = locnint = 0;
54
}
55
#endif
56
57
58
/* The following routines are copied from the book
59
"Numerical Recipes in C, The art of scientific computing"
60
by Cambridge University Press and include the following
61
62
Non-Copyright Notice: This appendix and its utility routines are
63
herewith placed into the public domain. Anyone may copy them freely
64
for any purpose. We of course accept no liability whatsoever for
65
any such use. */
66
67
68
69
void nrerror(const char error_text[])
70
/* standard error handler */
71
{
72
fprintf(stderr,"run-time error...\n");
73
fprintf(stderr,"%s\n",error_text);
74
fprintf(stderr,"...now exiting to system...\n");
75
exit(1);
76
}
77
78
79
/* Vector initialization */
80
81
float *vector(int nl,int nh)
82
/* allocate a float vector with subscript range v[nl..nh] */
83
{
84
float *v;
85
86
v = (float*)malloc((size_t) (nh-nl+1+1)*sizeof(float));
87
if (!v) nrerror("allocation failure in vector()");
88
return(v-nl+1);
89
}
90
91
92
93
int *ivector(int nl,int nh)
94
/* Allocate an int vector with subscript range v[nl..nh] */
95
{
96
int *v;
97
98
if( nh < nl ) {
99
printf("Allocation impossible in ivector: %d %d\n",nl,nh);
100
exit(1);
101
}
102
103
v=(int*) malloc((size_t) (nh-nl+1+1)*sizeof(int));
104
if (!v) nrerror("allocation failure in ivector()");
105
106
#if SHOWMEM
107
locnint = (nh-nl+1+1);
108
nint += locnint;
109
cumnint += locnint;
110
MemoryUsage();
111
#endif
112
113
return(v-nl+1);
114
}
115
116
117
char *cvector(int nl,int nh)
118
/* allocate an char vector with subscript range v[nl..nh] */
119
{
120
char *v;
121
122
v=(char *)malloc((size_t) (nh-nl+1+1)*sizeof(char));
123
if (!v) nrerror("allocation failure in cvector()");
124
return(v-nl+1);
125
}
126
127
128
unsigned long *lvector(int nl,int nh)
129
/* allocate an unsigned long vector with subscript range v[nl..nh] */
130
{
131
unsigned long *v;
132
133
v=(unsigned long *)malloc((size_t) (nh-nl+1+1)*sizeof(unsigned long));
134
if (!v) nrerror("allocation failure in lvector()");
135
return(v-nl+1);
136
}
137
138
139
140
double *dvector(int nl,int nh)
141
/* allocate a double vector with subscript range v[nl..nh] */
142
{
143
double *v;
144
145
if( nh < nl ) {
146
printf("Allocation impossible in dvector: %d %d\n",nl,nh);
147
exit(1);
148
}
149
150
v=(double *)malloc((size_t) (nh-nl+1+1)*sizeof(double));
151
if (!v) nrerror("allocation failure in dvector()");
152
153
#if SHOWMEM
154
locnfloat = nh-nl+1+1;
155
nfloat += locnfloat;
156
cumnfloat += locnfloat;
157
MemoryUsage();
158
#endif
159
160
return(v-nl+1);
161
}
162
163
164
/* Matrix initialization */
165
166
float **matrix(int nrl,int nrh,int ncl,int nch)
167
/* allocate a float matrix with subscript range m[nrl..nrh][ncl..nch] */
168
{
169
int i, nrow=nrh-nrl+1, ncol=nch-ncl+1;
170
float **m;
171
172
/* allocate pointers to rows */
173
m=(float **) malloc((size_t) (nrow+1)*sizeof(float*));
174
if (!m) nrerror("allocation failure 1 in matrix()");
175
m += 1;
176
m -= nrl;
177
178
/* allocate rows and set pointers to them */
179
m[nrl]=(float *) malloc((size_t)((nrow*ncol+1)*sizeof(float)));
180
if (!m[nrl]) nrerror("allocation failure 2 in matrix()");
181
m[nrl] += 1;
182
m[nrl] -= ncl;
183
184
for(i=nrl+1;i<=nrh;i++)
185
m[i]=m[i-1]+ncol;
186
187
return(m);
188
}
189
190
191
double **dmatrix(int nrl,int nrh,int ncl,int nch)
192
/* allocate a double matrix with subscript range m[nrl..nrh][ncl..nch] */
193
{
194
int i, nrow=nrh-nrl+1, ncol=nch-ncl+1;
195
double **m;
196
197
if( nrh < nrl || nch < ncl ) {
198
printf("Allocation impossible in dmatrix: %d %d %d %d\n",nrl,nrh,ncl,nch);
199
exit(1);
200
}
201
202
203
204
/* allocate pointers to rows */
205
m=(double **) malloc((size_t) (nrow+1)*sizeof(double*));
206
if (!m) nrerror("allocation failure 1 in dmatrix()");
207
m += 1;
208
m -= nrl;
209
210
211
/* allocate rows and set pointers to them */
212
m[nrl]=(double *) malloc((size_t)((nrow*ncol+1)*sizeof(double)));
213
if (!m[nrl]) nrerror("allocation failure 2 in dmatrix()");
214
m[nrl] += 1;
215
m[nrl] -= ncl;
216
217
for(i=nrl+1;i<=nrh;i++)
218
m[i]=m[i-1]+ncol;
219
220
#if SHOWMEM
221
locnfloat = (nrow+1 + (nrow*ncol+1));
222
nfloat += locnfloat;
223
cumnfloat += locnfloat;
224
MemoryUsage();
225
#endif
226
227
return(m);
228
}
229
230
231
int **imatrix(int nrl,int nrh,int ncl,int nch)
232
/* allocate an int matrix with subscript range m[nrl..nrh][ncl..nch] */
233
{
234
int i, nrow=nrh-nrl+1, ncol=nch-ncl+1;
235
int **m;
236
237
if( nrh < nrl || nch < ncl ) {
238
printf("Allocation impossible in imatrix: %d %d %d %d\n",nrl,nrh,ncl,nch);
239
exit(1);
240
}
241
242
/* allocate pointers to rows */
243
m=(int **) malloc((size_t) (nrow+1)*sizeof(int*));
244
if (!m) nrerror("allocation failure 1 in imatrix()");
245
m += 1;
246
m -= nrl;
247
248
/* allocate rows and set pointers to them */
249
m[nrl]=(int *) malloc((size_t)((nrow*ncol+1)*sizeof(int)));
250
if (!m[nrl]) nrerror("allocation failure 2 in imatrix()");
251
m[nrl] += 1;
252
m[nrl] -= ncl;
253
254
for(i=nrl+1;i<=nrh;i++)
255
m[i]=m[i-1]+ncol;
256
257
#if SHOWMEM
258
locnint = (nrow+1 + (nrow*ncol+1));
259
nint += locnint;
260
cumnint += locnint;
261
MemoryUsage();
262
#endif
263
264
return(m);
265
}
266
267
268
269
float **submatrix(float **a,int oldrl,int oldrh,int oldcl,int oldch,int newrl,int newcl)
270
/* point a submatrix [newrl..][newcl..] to a[oldrl..oldrh][oldcl..oldch] */
271
{
272
int i,j, nrow=oldrh-oldrl+1, ncol=oldcl-newcl;
273
float **m;
274
275
/* allocate array of pointers to rows */
276
m=(float **) malloc((size_t) ((nrow+1)*sizeof(float*)));
277
if (!m) nrerror("allocation failure in submatrix()");
278
m += 1;
279
m -= newrl;
280
281
/* set pointers to rows */
282
for(i=oldrl,j=newrl;i<=oldrh;i++,j++)
283
m[j]=a[i]+ncol;
284
285
return(m);
286
}
287
288
/* Tensor initialization */
289
290
double ***f3tensor(int nrl,int nrh,int ncl,int nch,int ndl,int ndh)
291
/* allocate a double 3tensor with range t[nrl..nrh][ncl..nch][ndl..ndh] */
292
{
293
int i,j,nrow=nrh-nrl+1,ncol=nch-ncl+1,ndep=ndh-ndl+1;
294
double ***t;
295
296
t=(double***) malloc((size_t)((nrow+1)*sizeof(double***)));
297
if (!t) nrerror("allocation failure 1 in f3tensor()");
298
t += 1;
299
t -= nrl;
300
301
t[nrl]=(double**) malloc((size_t)((nrow*ncol+1)*sizeof(double*)));
302
if(!t[nrl]) nrerror("allocation failure 2 in f3tensor()");
303
t[nrl] += 1;
304
t[nrl] -= ncl;
305
306
t[nrl][ncl]=(double*) malloc((size_t)((nrow*ncol*ndep+1)*sizeof(double)));
307
if(!t[nrl][ncl]) nrerror("allocation failure 3 in f3tensor()");
308
t[nrl][ncl] += 1;
309
t[nrl][ncl] -= ndl;
310
311
for(j=ncl+1;j<=nch;j++) t[nrl][j] = t[nrl][j-1]+ndep;
312
for(i=nrl+1;i<=nrh;i++) {
313
t[i] = t[i-1]+ncol;
314
t[i][ncl] = t[i-1][ncl]+ncol*ndep;
315
for(j=ncl+1;j<=nch;j++) t[i][j] = t[i][j-1]+ndep;
316
}
317
return(t);
318
}
319
320
321
/* Deallocation routines */
322
323
void free_vector(float *v,int nl,int nh)
324
{
325
free((FREE_ARG) (v+nl-1));
326
}
327
328
void free_ivector(int *v,int nl,int nh)
329
{
330
#if SHOWMEM
331
cumnint -= (nh-nl+1+1);
332
#endif
333
334
free((FREE_ARG) (v+nl-1));
335
}
336
337
void free_cvector(char *v,int nl,int nh)
338
{
339
free((FREE_ARG) (v+nl-1));
340
}
341
342
void free_lvector(unsigned long *v,int nl,int nh)
343
{
344
free((FREE_ARG) (v+nl-1));
345
}
346
347
348
void free_dvector(double *v,int nl,int nh)
349
{
350
#if SHOWMEM
351
cumnfloat -= (nh-nl+1+1);
352
#endif
353
354
free((FREE_ARG) (v+nl-1));
355
}
356
357
void free_matrix(float **m,int nrl,int nrh,int ncl,int nch)
358
{
359
free((FREE_ARG) (m[nrl]+ncl-1));
360
free((FREE_ARG) (m+nrl-1));
361
}
362
363
void free_dmatrix(double **m,int nrl,int nrh,int ncl,int nch)
364
{
365
#if SHOWMEM
366
int nrow=nrh-nrl+1;
367
int ncol=nch-ncl+1;
368
cumnfloat -= (nrow+1 + (nrow*ncol+1));
369
#endif
370
371
free((FREE_ARG) (m[nrl]+ncl-1));
372
free((FREE_ARG) (m+nrl-1));
373
}
374
375
void free_imatrix(int **m,int nrl,int nrh,int ncl,int nch)
376
{
377
#if SHOWMEM
378
int nrow=nrh-nrl+1;
379
int ncol=nch-ncl+1;
380
cumnint -= (nrow+1 + (nrow*ncol+1));
381
#endif
382
383
free((FREE_ARG) (m[nrl]+ncl-1));
384
free((FREE_ARG) (m+nrl-1));
385
}
386
387
void free_submatrix(float **b,int nrl,int nrh,int ncl,int nch)
388
{
389
free((FREE_ARG) (b+nrl-1));
390
}
391
392
void free_f3tensor(double ***t,int nrl,int nrh,int ncl,int nch,int ndl,int ndh)
393
{
394
free((FREE_ARG) (t[nrl][ncl]+ndl-1));
395
free((FREE_ARG) (t[nrl]+ncl-1));
396
free((FREE_ARG) (t+nrl-1));
397
}
398
399
400
/* -------------------------------: common.c :----------------------------
401
Includes common operations for operating vectors and such. */
402
403
404
static Real timer_t0, timer_dt;
405
static int timer_active = FALSE;
406
static char timer_filename[600];
407
408
void timer_init()
409
{
410
timer_active = FALSE;
411
}
412
413
414
void timer_activate(const char *prefix)
415
{
416
Real time;
417
timer_active = TRUE;
418
419
time = clock() / (double)CLOCKS_PER_SEC;
420
421
AddExtension(prefix,timer_filename,"time");
422
423
printf("Activating timer (s): %.2f\n",time);
424
printf("Saving timer info to file %s\n",timer_filename);
425
426
timer_dt = time;
427
timer_t0 = time;
428
}
429
430
431
void timer_show()
432
{
433
static int visited = 0;
434
Real time;
435
FILE *out;
436
#if MEM_USAGE
437
int who,ret;
438
Real memusage;
439
static struct rusage usage;
440
#endif
441
442
if(!timer_active) return;
443
444
time = clock() / (double)CLOCKS_PER_SEC;
445
printf("Elapsed time (s): %.2f %.2f\n",time-timer_t0,time-timer_dt);
446
447
#if MEM_USAGE
448
who = RUSAGE_SELF;
449
ret = getrusage( who, &usage );
450
if( !ret ) {
451
printf("maxrss %ld\n",usage.ru_maxrss);
452
printf("ixrss %ld\n",usage.ru_ixrss);
453
printf("idrss %ld\n",usage.ru_idrss);
454
printf("isrss %ld\n",usage.ru_isrss);
455
456
memusage = (double) 1.0 * usage.ru_maxrss;
457
}
458
else {
459
printf("Failed to obtain resource usage!\n");
460
memusage = 0.0;
461
}
462
#endif
463
464
visited = visited + 1;
465
if( visited == 1 ) {
466
out = fopen(timer_filename,"w");
467
}
468
else {
469
out = fopen(timer_filename,"a");
470
}
471
472
#if MEM_USAGE
473
fprintf(out,"%3d %12.4le %12.4le %12.4le\n",visited,time-timer_t0,time-timer_dt,memusage);
474
#else
475
fprintf(out,"%3d %12.4le %12.4le\n",visited,time-timer_t0,time-timer_dt);
476
#endif
477
478
fclose(out);
479
480
timer_dt = time;
481
}
482
483
484
485
486
void bigerror(const char error_text[])
487
{
488
fprintf(stderr,"***** ERROR: We cannot continue with this! *****\n");
489
fprintf(stderr,"***** %s\n",error_text);
490
fprintf(stderr,"***** ...now exiting to system!\n");
491
exit(1);
492
}
493
494
495
void smallerror(const char error_text[])
496
{
497
fprintf(stderr,"***** WARNING: This should not happen but we try to continue! *****\n");
498
fprintf(stderr,"***** %s\n",error_text);
499
}
500
501
502
503
int FileExists(char *filename)
504
{
505
FILE *in;
506
507
if((in = fopen(filename,"r")) == NULL)
508
return(FALSE);
509
else {
510
fclose(in);
511
return(TRUE);
512
}
513
}
514
515
516
Real Minimum(Real *vector,int first,int last)
517
/* Returns the smallest value of vector in range [first,last]. */
518
{
519
Real min;
520
int i;
521
522
min=vector[first];
523
for(i=first+1;i<=last;i++)
524
if(min>vector[i]) min=vector[i];
525
526
return(min);
527
}
528
529
530
int Minimi(Real *vector,int first,int last)
531
/* Returns the position of the smallest value of vector in range [first,last]. */
532
{
533
Real min;
534
int i,mini;
535
536
mini=first;
537
min=vector[first];
538
for(i=first+1;i<=last;i++)
539
if(min>vector[i])
540
min=vector[(mini=i)];
541
542
return(mini);
543
}
544
545
546
Real Maximum(Real *vector,int first,int last)
547
/* Returns the largest value of vector in range [first,last]. */
548
{
549
Real max;
550
int i;
551
552
max=vector[first];
553
for(i=first+1;i<=last;i++)
554
if(max<vector[i]) max=vector[i];
555
556
return(max);
557
}
558
559
560
int Maximi(Real *vector,int first,int last)
561
/* Returns the position of the largest value of vector in range [first,last]. */
562
{
563
Real max;
564
int i,maxi;
565
566
maxi=-1;
567
max=vector[first];
568
for(i=first+1;i<=last;i++)
569
if(max<vector[i])
570
max=vector[(maxi=i)];
571
572
return(maxi);
573
}
574
575
576
577
void AddExtension(const char *fname1,char *fname2,const char *newext)
578
/* Changes the extension of a filename.
579
'fname1' - the original filename
580
'fname2' - the new filename
581
'newext' - the new extension
582
If there is originally no extension it's appended. In this case
583
there has to be room for the extension.
584
*/
585
{
586
char *ptr1,*ptr2;
587
588
strcpy(fname2,fname1);
589
ptr1 = strrchr(fname2, '.');
590
591
if (ptr1) {
592
int badpoint=FALSE;
593
ptr2 = strrchr(fname2, '/');
594
if(ptr2 && ptr2 > ptr1) badpoint = TRUE;
595
if(!badpoint) *ptr1 = '\0';
596
}
597
strcat(fname2, ".");
598
strcat(fname2,newext);
599
}
600
601
602
int StringToStrings(const char *buf,char args[10][15],int maxcnt,char separator)
603
/* Finds real numbers separated by a certain separator from a string.
604
'buf' - input string ending to a EOF
605
'dest' - a vector of real numbers
606
'maxcnt' - maximum number of real numbers to be read
607
'separator' - the separator of real numbers
608
The number of numbers found is returned in the function value.
609
*/
610
{
611
int i,cnt,totlen,finish;
612
char *ptr1 = (char *)buf, *ptr2;
613
614
615
totlen = strlen(buf);
616
finish = 0;
617
cnt = 0;
618
619
if (!buf[0]) return 0;
620
621
do {
622
ptr2 = strchr(ptr1,separator);
623
if(ptr2) {
624
for(i=0;i<15;i++) {
625
args[cnt][i] = ptr1[i];
626
if(ptr1 + i >= ptr2) break;
627
}
628
args[cnt][i] = '\0';
629
ptr1 = ptr2+1;
630
}
631
else {
632
for(i=0;i<15;i++) {
633
if(ptr1 + i >= buf+totlen) break;
634
args[cnt][i] = ptr1[i];
635
}
636
args[cnt][i] = '\0';
637
finish = 1;
638
}
639
640
cnt++;
641
} while (cnt < maxcnt && !finish);
642
643
return cnt;
644
}
645
646
647
int StringToReal(const char *buf,Real *dest,int maxcnt,char separator)
648
/* Finds real numbers separated by a certain separator from a string.
649
'buf' - input string ending to a EOF
650
'dest' - a vector of real numbers
651
'maxcnt' - maximum number of real numbers to be read
652
'separator' - the separator of real numbers
653
The number of numbers found is returned in the function value.
654
*/
655
{
656
int cnt = 0;
657
char *ptr1 = (char *)buf, *ptr2;
658
659
if (!buf[0]) return 0;
660
do {
661
ptr2 = strchr(ptr1,separator);
662
if (ptr2) ptr2[0] = '\0';
663
dest[cnt++] = atof(ptr1);
664
if (ptr2) ptr1 = ptr2+1;
665
} while (cnt < maxcnt && ptr2 != NULL);
666
667
return cnt;
668
}
669
670
671
int StringToInteger(const char *buf,int *dest,int maxcnt,char separator)
672
{
673
int cnt = 0;
674
char *ptr1 = (char *)buf, *ptr2;
675
int ival;
676
677
if (!buf[0]) return 0;
678
do {
679
680
ptr2 = strchr(ptr1,separator);
681
if (ptr2) ptr2[0] = '\0';
682
ival = atoi(ptr1);
683
684
dest[cnt++] = ival;
685
686
if (ptr2) ptr1 = ptr2+1;
687
} while (cnt < maxcnt && ptr2 != NULL);
688
689
return cnt;
690
}
691
692
int StringToIntegerNoZero(const char *buf,int *dest,int maxcnt,char separator)
693
{
694
int cnt = 0;
695
char *ptr1 = (char *)buf, *ptr2;
696
int ival;
697
698
if (!buf[0]) return 0;
699
do {
700
701
ptr2 = strchr(ptr1,separator);
702
if (ptr2) ptr2[0] = '\0';
703
ival = atoi(ptr1);
704
705
if(ival == 0) break;
706
707
dest[cnt++] = ival;
708
709
if (ptr2) ptr1 = ptr2+1;
710
} while (cnt < maxcnt && ptr2 != NULL);
711
712
return cnt;
713
}
714
715
716
int next_int(char **start)
717
{
718
int i;
719
char *end;
720
721
i = strtol(*start,&end,10);
722
*start = end;
723
return(i);
724
}
725
726
int next_int_n(char **start, int n)
727
{
728
int i;
729
char *end = *start+n;
730
char saved = *end;
731
732
*end = '\0';
733
i = strtol(*start,NULL,10);
734
*end = saved;
735
*start = end;
736
return(i);
737
}
738
739
Real next_real(char **start)
740
{
741
Real r;
742
char *end;
743
744
r = strtod(*start,&end);
745
746
*start = end;
747
return(r);
748
}
749
750
751
/*
752
* sort: sort an (double) array to ascending order, and move the elements of
753
* another (integer) array accordingly. the latter can be used as track
754
* keeper of where an element in the sorted order at position (k) was in
755
* in the original order (Ord[k]), if it is initialized to contain
756
* numbers (0..N-1) before calling sort.
757
*
758
* Parameters:
759
*
760
* N: int / number of entries in the arrays.
761
* Key: double[N] / array to be sorted.
762
* Ord: int[N] / change this accordingly.
763
*/
764
void SortIndex( int N, double *Key, int *Ord )
765
{
766
double CurrentKey;
767
768
int CurrentOrd;
769
770
int CurLastPos;
771
int CurHalfPos;
772
773
int i;
774
int j;
775
776
/* Initialize order */
777
for(i=1;i<=N;i++)
778
Ord[i] = i;
779
780
CurHalfPos = N / 2 + 1;
781
CurLastPos = N;
782
while( 1 ) {
783
if ( CurHalfPos > 1 ) {
784
CurHalfPos--;
785
CurrentKey = Key[CurHalfPos];
786
CurrentOrd = Ord[CurHalfPos];
787
} else {
788
CurrentKey = Key[CurLastPos];
789
CurrentOrd = Ord[CurLastPos];
790
Key[CurLastPos] = Key[1];
791
Ord[CurLastPos] = Ord[1];
792
CurLastPos--;
793
if ( CurLastPos == 1 ) {
794
Key[1] = CurrentKey;
795
Ord[1] = CurrentOrd;
796
return;
797
}
798
}
799
i = CurHalfPos;
800
j = 2 * CurHalfPos;
801
while( j <= CurLastPos ) {
802
if ( j < CurLastPos && Key[j] < Key[j + 1] ) {
803
j++;
804
}
805
if ( CurrentKey < Key[j] ) {
806
Key[i] = Key[j];
807
Ord[i] = Ord[j];
808
i = j;
809
j += i;
810
} else {
811
j = CurLastPos + 1;
812
}
813
}
814
Key[i] = CurrentKey;
815
Ord[i] = CurrentOrd;
816
}
817
818
}
819
820
821
822
823