Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libvcodex/vcsfxsort.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 2003-2011 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* Phong Vo <[email protected]> *
18
* *
19
***********************************************************************/
20
#include "vchdr.h"
21
#include "vgraph.h"
22
23
/* Algorithm to compute the suffix array of a string.
24
** Sadakane-Larson magic numbering is used to speed up sort.
25
** Optimum branching is used to determine an optimal order
26
** for sorting groups with same first byte.
27
** The multikey-sort function detects periodic sequences and
28
** copy-sort them via a generalized Seward pointer-copy.
29
** Seward pointer-copy is also used to spread sort order.
30
**
31
** Written by Kiem-Phong Vo ([email protected])
32
*/
33
34
#ifdef ITOH_TANAKA
35
#define has_algorithm 1
36
#endif
37
#if !has_algorithm
38
#define OPT_BRANCHING 1
39
#endif
40
41
static unsigned int _rand = 0xdeadbeef; /* gotta be a dirt cheap RNG :-) */
42
#define RAND() (_rand = _rand*16777617 + 3)
43
#define SWAP(x,y,t) ((t) = (x), (x) = (y), (y) = (t)) /* swap two scalars */
44
#define MEDIAN(x,y,z) ((x) <= (y) ? ((y) <= (z) ? (y) : (z) >= (x) ? (z) : (x)) : \
45
((y) >= (z) ? (y) : (z) <= (x) ? (z) : (x)) )
46
47
#define INSERTSORT 64 /* insertion sort any set <= this */
48
#define MAXHEADER 1024 /* max hdr to limit sfxqsort recursion */
49
50
#ifdef DEBUG
51
static Vcsfxint_t Pn, Pz, Pc, Qn, Qz, In, Iz, Cn, Cz;
52
static int Ql, Qm, Qr; /* qsort recursion depths */
53
extern char* getenv(const char*);
54
55
static int chktodo(Vcsfx_t* sfx, Vcsfxint_t lo, Vcsfxint_t hi)
56
{ static int Dblev = -1;
57
if(Dblev < 0)
58
{ char *db = getenv("VCDEBUG");
59
Dblev = !db ? 0 : db[0] - '0';
60
}
61
if(lo > hi)
62
return 0;
63
if(Dblev == 0) /* no checking*/
64
return 0;
65
if(Dblev == 1) /* checking only full range */
66
return (lo == 0 && hi == sfx->nstr-1) ? 1 : 0;
67
return 1; /* always checking */
68
}
69
70
static int intcmp(void* one, void* two, void* disc)
71
{ return (int)(*((Vcsfxint_t*)one) - *((Vcsfxint_t*)two));
72
}
73
74
static int chkdata(Vcsfx_t* sfx, Vcsfxint_t lo, Vcsfxint_t hi)
75
{ Vcsfxint_t i, endi, k;
76
Vcsfxint_t *idx = sfx->idx, *inv = sfx->inv;
77
Vcsfxint_t *ary;
78
79
if(lo > hi || !chktodo(sfx,lo,hi))
80
return 1;
81
82
if(!(ary = (Vcsfxint_t*)malloc((hi-lo+1)*sizeof(Vcsfxint_t))) )
83
return 0;
84
for(k = 0, i = lo; i <= hi; ++i, ++k)
85
ary[k] = idx[i];
86
vcqsort(ary, k, sizeof(Vcsfxint_t), intcmp, (Void_t*)0);
87
for(i = 1; i < k; ++i) /* check distinctness */
88
/**/DEBUG_ASSERT(ary[i] != ary[i-1]);
89
free(ary);
90
91
for(i = lo; i <= hi; i = k) /* check inversion relations */
92
{ endi = inv[idx[i]]; /**/DEBUG_ASSERT(endi >= i);
93
for(k = i; k <= endi; ++k)
94
/**/DEBUG_ASSERT(inv[idx[k]] == endi);
95
}
96
97
return 1;
98
}
99
100
static int cmpsfx(Vcsfx_t* sfx, Vcsfxint_t p, Vcsfxint_t s)
101
{ Vcchar_t *ps = sfx->str+p, *ss = sfx->str+s;
102
Vcsfxint_t v, n, k;
103
p = sfx->nstr-p; s = sfx->nstr-s;
104
for(n = p < s ? p : s, k = 0; k < n; ++k)
105
{ if((v = ps[k] - ss[k]) == 0)
106
continue;
107
return v > 0 ? 1 : -1;
108
}
109
return p < s ? 1 : -1;
110
}
111
112
static int chksorted(Vcsfx_t* sfx, Vcsfxint_t lo, Vcsfxint_t hi)
113
{ Vcsfxint_t *i, *inv = sfx->inv, *idx = sfx->idx;
114
Vcsfxint_t *min = idx+lo, *max = idx+hi;
115
if(!chktodo(sfx,lo,hi))
116
return 1;
117
for(i = min; i <= max; ++i)
118
DEBUG_ASSERT(inv[*i] == i-idx);
119
min = min == sfx->idx ? min+1 : min;
120
max = max < (sfx->idx+sfx->nstr-1) ? max+1 : max;
121
for(; min <= max; ++min)
122
DEBUG_ASSERT(cmpsfx(sfx, min[-1], min[0]) < 0);
123
return 1;
124
}
125
#endif /*DEBUG*/
126
127
/* bucket sort by first two bytes. */
128
#define GMIN(g,x,y) ((g)[((x)<<8)+(y)])
129
#define GMAX(g,x,y,e) (((g)[((x)<<8)+(y)+1]) - (((x) == (e) && (y) == 255) ? 1 : 0) - 1)
130
131
#if __STD_C
132
static void sfxbsort(Vcsfx_t* sfx, Vcsfxint_t* grp)
133
#else
134
static void sfxbsort(sfx, grp)
135
Vcsfx_t* sfx;
136
Vcsfxint_t* grp;
137
#endif
138
{
139
int i, j, v;
140
Vcsfxint_t n, *g;
141
Vcchar_t *s, *ends;
142
Vcsfxint_t *idx = sfx->idx, *inv = sfx->inv;
143
144
memset(grp, 0, 256*256*sizeof(Vcsfxint_t)); /* get frequencies */
145
for(ends = (s = sfx->str)+sfx->nstr-1, i = *s; s < ends; i = j)
146
grp[(i<<8) + (j = *++s)] += 1;
147
148
for(n = 0, g = grp, i = 0; i < 256; ++i)
149
{ for(j = 0; j < 256; ++j, ++g)
150
*g = (n += *g); /* next area to be allocated */
151
if(i == *ends) /* sort the last suffix now */
152
{ inv[sfx->nstr-1] = n;
153
idx[n++] = sfx->nstr-1;
154
}
155
}
156
157
for(n = 0, ends = (s = sfx->str)+sfx->nstr-1, i = *s; s < ends; i = j)
158
{ v = (i << 8) + (j = *++s);
159
inv[n++] = grp[v]-1; /* rank is highest position of group */
160
}
161
for(n = 0, ends = (s = sfx->str)+sfx->nstr-1, i = *s; s < ends; i = j)
162
{ v = (i << 8) + (j = *++s);
163
idx[grp[v] -= 1] = n++; /* put suffix into its bucket */
164
}
165
166
grp[256*256] = sfx->nstr; /* end of 255*255-group */
167
}
168
169
#if __STD_C /* swap two adjacent lists of integers */
170
static void sfxswap(Vcsfxint_t* min, Vcsfxint_t* mid, Vcsfxint_t* max)
171
#else
172
static void sfxswap(min, mid, max)
173
Vcsfxint_t* min;
174
Vcsfxint_t* mid;
175
Vcsfxint_t* max;
176
#endif
177
{
178
Vcsfxint_t m, n;
179
180
if((n = max-mid) > (m = mid-min+1) )
181
n = m;
182
for(; n > 0; --n, ++min, --max)
183
SWAP(*min, *max, m);
184
}
185
186
#if __STD_C /* multikey-quicksort */
187
static void sfxqsort(Vcsfx_t* sfx, Vcsfxint_t* min, Vcsfxint_t* max, Vcsfxint_t hdr, int period)
188
#else
189
static void sfxqsort(sfx, min, max, hdr, period)
190
Vcsfx_t* sfx;
191
Vcsfxint_t* min; /* sorting [min,max] */
192
Vcsfxint_t* max;
193
Vcsfxint_t hdr; /* common header */
194
int period; /* != 0, check periods */
195
#endif
196
{
197
Vcsfxint_t *l, *r, *le, *re, k, ln, mn, rn, pi, sz, c[3];
198
Vcsfxint_t *inv = sfx->inv, *idx = sfx->idx;
199
200
q_sort: if((sz = max-min+1) <= INSERTSORT) /* insertion sort */
201
{ /**/DEBUG_TALLY(period > 1, In, 1); DEBUG_TALLY(period > 1, Iz, sz);
202
for(l = min+1; l <= max; ++l) /* insert *l into [0,l-1] */
203
{ pi = *l;
204
for(r = l-1; r >= min; --r)
205
{ le = inv + (pi+hdr); re = inv + (*r+hdr); /**/DEBUG_ASSERT(le != re);
206
while((k = *le - *re) == 0)
207
{ le += 2; re += 2; }
208
if(k > 0)
209
break;
210
*(r+1) = *r;
211
}
212
*(r+1) = pi;
213
}
214
for(l = min; l <= max; ++l)
215
inv[*l] = l-idx; /* update rank */
216
return;
217
}
218
219
/**/DEBUG_TALLY(period > 1, Qn, 1); DEBUG_TALLY(period > 1, Qz, sz);
220
if((period = (period == 0 || sz <= 1024) ? 0 : 1) != 0)
221
pi = inv[*max]; /* looking for periodic subsequences */
222
else /* approximating a median-of-9 as a pivot */
223
{ for(k = 0; k < 3; ++k)
224
{ ln = inv[min[RAND()%sz]+hdr];
225
mn = inv[min[RAND()%sz]+hdr];
226
rn = inv[min[RAND()%sz]+hdr];
227
c[k] = MEDIAN(ln, mn, rn);
228
}
229
pi = MEDIAN(c[0],c[1],c[2]);
230
}
231
232
for(le = (l = min)-1, re = (r = max)+1; l <= r; )
233
{ for(; l <= r; ++l)
234
{ if((k = inv[*l + hdr] - pi) > 0)
235
break;
236
else if(k == 0 && (le += 1) < l)
237
SWAP(*le, *l, mn);
238
}
239
for(; r >= l; --r)
240
{ if((k = inv[*r + hdr] - pi) < 0)
241
break;
242
else if(k == 0 && (re -= 1) > r)
243
SWAP(*re, *r, mn);
244
}
245
if(l < r)
246
{ SWAP(*l, *r, mn);
247
l += 1; r -= 1;
248
}
249
} /**/DEBUG_ASSERT(r+1 == l);
250
if(le >= min && le < r) /* swap [min,le]=pi && [le+1,r]<pi */
251
sfxswap(min, le, r);
252
if(l < re && re <= max) /* swap [l,re-1]>pi && [re,max]=pi */
253
sfxswap(l, re-1, max);
254
le = min + (r-le); re = max - (re-l);
255
ln = le-min; mn = re-le+1; rn = max-re; /* partition sizes */
256
/**/DEBUG_ASSERT(ln >= 0 && mn >= 0 && rn >= 0 && (ln+rn+mn) == sz );
257
258
if(ln == 1) /* process the segment <pi */
259
inv[*min] = min-idx;
260
else if(ln > 1) /* recurse to sort */
261
{ /**/DEBUG_INCREASE(Ql);
262
sfxqsort(sfx, min, le-1, hdr, 0);
263
/**/DEBUG_DECREASE(Ql);
264
/**/DEBUG_ASSERT(chkdata(sfx,min-idx,(le-1)-idx));
265
}
266
267
if(mn == 1) /* process the segment =pi */
268
inv[*le] = le-idx;
269
else if(mn > 1)
270
{ if(hdr <= MAXHEADER || (period == 0 && rn > 1) )
271
{ /**/DEBUG_INCREASE(Qm);
272
sfxqsort(sfx, le, re, hdr+2, 0);
273
/**/DEBUG_DECREASE(Qm);
274
mn = 0; /* completely sorted */
275
}
276
else if((pi = re-idx) != inv[*le]) /* reset ranks */
277
{ for(l = le; l <= re; ++l)
278
inv[*l] = pi;
279
}
280
}
281
282
if(rn == 1) /* process the segment >pi */
283
inv[*max] = max-idx;
284
else if(rn > 1)
285
{ /**/DEBUG_INCREASE(Qr);
286
sfxqsort(sfx, re+1, max, hdr, 0);
287
/**/DEBUG_DECREASE(Qr);
288
/**/DEBUG_ASSERT(chkdata(sfx,min-idx,(le-1)-idx));
289
}
290
291
if(mn > 1)
292
{ if(period && mn >= sz/16) /* generalized Seward pointer-copy */
293
{ /**/DEBUG_COUNT(Pn); DEBUG_TALLY(1,Pz,mn); DEBUG_TALLY(1,Pc,sz);
294
pi = re-idx; /* current rank of this group */
295
for(l = min; l < le; ++l)
296
if(inv[k = *l-hdr] == pi)
297
{ *le = k; inv[k] = le-idx; le += 1; }
298
for(r = max; r > re; --r)
299
if(inv[k = *r-hdr] == pi)
300
{ *re = k; inv[k] = re-idx; re -= 1; }
301
/**/DEBUG_ASSERT(chkdata(sfx,min-idx,max-idx));
302
}
303
else /* tail recursion to save stack space */
304
{ min = le; max = re; hdr += 2; period = 1;
305
goto q_sort;
306
}
307
}
308
}
309
310
#if __STD_C /* copy-sort yx-groups based on the sort order of x-suffixes */
311
static void sfxcsort(Vcsfx_t* sfx, Vcsfxint_t y, Vcsfxint_t* grp)
312
#else
313
static void sfxcsort(sfx, y, grp)
314
Vcsfx_t* sfx;
315
Vcsfxint_t y; /* common first byte */
316
Vcsfxint_t* grp; /* bounds of xy-groups */
317
#endif
318
{
319
Vcsfxint_t i, k, l, r, x, *xy;
320
Vcsfxint_t omin, omax, pmin[256], pmax[256];
321
Vcchar_t *str = sfx->str;
322
Vcsfxint_t *inv = sfx->inv, *idx = sfx->idx;
323
Vcsfxint_t endc = sfx->str[sfx->nstr-1];
324
325
/* bounds of group headed by the same y */
326
if((omin = grp[y<<8]) > (omax = grp[(y<<8)+256]-1) )
327
return;
328
329
/* set boundary of groups to be copy-sorted */
330
for(k = 0, x = 0; x < 256; ++x)
331
{ l = GMIN(grp,x,y); r = GMAX(grp,x,y,endc);
332
if(l < r && l < (r = inv[idx[l]]) )
333
k += 1; /* nontrivial sortable group */
334
else if(x != y) /* already sorted */
335
l = r = -1;
336
else if(l > r) /* empty yy-group */
337
l = r = omax+1; /* run first loop below only */
338
/*else; non-empty yy-group, run both loops below */
339
340
pmin[x] = l; pmax[x] = r;
341
}
342
if(k == 0) /* nothing to do */
343
return;
344
345
/**/DEBUG_COUNT(Cn); DEBUG_TALLY(1,Cz,omax-omin+1);
346
for(l = omin; l < pmin[y]; ++l)
347
if((k = idx[l]-1) >= 0 && (i = *(xy = pmin+str[k])) >= 0)
348
{ *xy += 1; idx[i] = k; inv[k] = i; }
349
for(r = omax; r > pmax[y]; --r)
350
if((k = idx[r]-1) >= 0 && (i = *(xy = pmax+str[k])) >= 0)
351
{ *xy -= 1; idx[i] = k; inv[k] = i; }
352
/**/DEBUG_ASSERT(chkdata(sfx, omin, omax));
353
}
354
355
#if __STD_C /* sort the unsorted xy-groups for the same x */
356
static int sfxosort(Vcsfx_t* sfx, Vcsfxint_t x, Vcsfxint_t* grp, int dir)
357
#else
358
static int sfxosort(sfx, x, grp, dir)
359
Vcsfx_t* sfx;
360
Vcsfxint_t x; /* common header byte */
361
Vcsfxint_t* grp;
362
int dir; /* itoh-tanaka sort dir */
363
#endif
364
{
365
Vcsfxint_t l, r, k, i, y, z;
366
Graph_t *gr;
367
Grnode_t *hd, *tl, *nd;
368
Gredge_t *e;
369
Vcchar_t *str = sfx->str, endc = sfx->str[sfx->nstr-1];
370
Vcsfxint_t nstr = sfx->nstr, *inv = sfx->inv, *idx = sfx->idx;
371
int rv = -1;
372
373
/* construct graph of relations between xy-groups */
374
if(!(gr = gropen(NIL(Grdisc_t*), GR_DIRECTED)) )
375
goto done;
376
for(y = 0; y < 256; ++y)
377
{ if(y == x || (dir > 0 && y < x) || (dir < 0 && y > x) )
378
continue;
379
if((l = GMIN(grp,x,y)) >= (r = GMAX(grp,x,y,endc)) )
380
continue; /* single or xx-group */
381
if((r = inv[idx[l]]-l+1) <= 1)
382
continue; /* already sorted */
383
384
if(!(hd = grnode(gr, TYPECAST(Void_t*,y), 1)) )
385
goto done;
386
for(k = 0; k < 3; ++k)
387
{ if((i = idx[l + RAND()%r]+2) >= nstr-1 || str[i] != x )
388
continue;
389
if((z = str[i+1]) == x || (dir > 0 && z < x) || (dir < 0 && z > x) )
390
continue;
391
if(!(tl = grnode(gr, TYPECAST(Void_t*,z), 1)) ||
392
!(e = gredge(gr, tl, hd, (Void_t*)0, 1)) )
393
goto done;
394
grbrweight(e, grbrweight(e,-1)+1);
395
}
396
}
397
if((k = grbranching(gr)) < 0)
398
goto done;
399
400
/* now sort xy-groups in their top-sort order */
401
hd = tl = NIL(Grnode_t*); /* first build the list of root nodes */
402
for(nd = (Grnode_t*)dtfirst(gr->nodes); nd; nd = (Grnode_t*)dtnext(gr->nodes,nd))
403
{ if(!nd->iedge) /* no incoming edge, hence a root */
404
{ if(!hd)
405
(hd = tl = nd)->link = NIL(Grnode_t*);
406
else (tl = tl->link = nd)->link = NIL(Grnode_t*);
407
}
408
}
409
for(nd = hd; nd; nd = nd->link) /* top-sort */
410
{ for(e = nd->oedge; e; e = e->onext)
411
(tl = tl->link = e->head)->link = NIL(Grnode_t*);
412
l = grp[(x<<8) + TYPECAST(Vcsfxint_t,nd->label)]; r = inv[idx[l]];
413
sfxqsort(sfx, idx+l, idx+r, 2, 2);
414
/**/DEBUG_ASSERT(chkdata(sfx, l, r));
415
}
416
417
rv = 0; /* successful processing */
418
419
done: if(gr)
420
grclose(gr);
421
return rv;
422
}
423
424
#if __STD_C
425
Vcsfx_t* vcsfxsort(const Void_t* astr, ssize_t nstr)
426
#else
427
Vcsfx_t* vcsfxsort(astr, nstr)
428
Void_t* astr; /* string to be sorted */
429
ssize_t nstr; /* length of string */
430
#endif
431
{
432
Vcsfxint_t l, r, x, y, endc;
433
Vcsfxint_t grp[256*256+1];
434
Vcchar_t *str; /* the addressable astr */
435
Vcsfxint_t *idx, *inv; /* index and rank */
436
Vcsfx_t *sfx; /* suffix array structure */
437
int error = 1;
438
439
if(!(str = (Vcchar_t*)astr) || nstr <= 0)
440
{ str = NIL(Vcchar_t*); nstr = 0; }
441
442
if(!(sfx = (Vcsfx_t*)malloc(sizeof(Vcsfx_t)+2*(nstr+1)*sizeof(Vcsfxint_t))) )
443
return NIL(Vcsfx_t*);
444
sfx->idx = idx = (Vcsfxint_t*)(sfx+1);
445
sfx->inv = inv = idx+nstr+1;
446
sfx->str = str;
447
sfx->nstr = (Vcsfxint_t)nstr;
448
idx[sfx->nstr] = inv[sfx->nstr] = sfx->nstr; /* the infinite eos byte */
449
if(sfx->nstr <= 1) /* the easy sorting case */
450
{ idx[0] = inv[0] = 0;
451
return sfx;
452
}
453
454
sfxbsort(sfx, grp); /* sort suffixes by first 2 bytes */
455
endc = str[nstr-1];
456
457
#ifdef ITOH_TANAKA /* sfxqsort half the data using itoh-tanaka strategy */
458
{ Vcsfxint_t c, d;
459
460
c = d = 0;
461
for(x = 0; x < 256; ++x)
462
for(y = 0; y < 256; ++y)
463
{ if(x == y || (l = GMIN(grp,x,y)) >= (r = GMAX(grp,x,y,endc)) )
464
continue;
465
if(x < y)
466
c += r-l+1;
467
else d += r-l+1;
468
}
469
d = c <= d ? 1 : -1; /* sort direction */
470
471
for(x = d > 0 ? 0 : 255; x >= 0 && x <= 255; x += d)
472
{ if(grp[x<<8] > (grp[(x<<8)+256]-1) )
473
continue;
474
if(sfxosort(sfx, x, grp, d) < 0)
475
goto it_err;
476
sfxcsort(sfx, x, grp);
477
}
478
error = 0; /* have done well */
479
it_err: ;
480
}
481
#endif
482
483
#ifdef OPT_BRANCHING
484
{ /* use an optimum branching to determine sort order of x-groups */
485
Graph_t *gr = NIL(Graph_t*);
486
Grnode_t *tl, *hd, *nd;
487
Gredge_t *e;
488
489
if(!(gr = gropen(NIL(Grdisc_t*), GR_DIRECTED)) )
490
goto ob_err;
491
for(x = 0; x < 256; ++x)
492
{ if(grp[x<<8] > (grp[(x<<8)+256]-1) )
493
continue;
494
if(!(hd = grnode(gr, TYPECAST(Void_t*,x), 1)) )
495
goto ob_err;
496
for(y = 0; y < 256; ++y)
497
{ if(x == y || (l = GMIN(grp,x,y)) >= (r = GMAX(grp,x,y,endc)) )
498
continue;
499
if(!(tl = grnode(gr, TYPECAST(Void_t*,y), 1)) ||
500
!(e = gredge(gr, tl, hd, (Void_t*)0, 1)) )
501
goto ob_err;
502
grbrweight(e, r-l+1);
503
}
504
}
505
if((r = grbranching(gr)) < 0)
506
goto ob_err; /**/DEBUG_PRINT(2,"Branching weight=%d\n", r);
507
508
hd = tl = NIL(Grnode_t*); /* first build the list of root nodes */
509
for(nd = (Grnode_t*)dtfirst(gr->nodes); nd; nd = (Grnode_t*)dtnext(gr->nodes,nd))
510
{ if(!nd->iedge) /* no incoming edge, hence a root */
511
{ if(!hd)
512
(hd = tl = nd)->link = NIL(Grnode_t*);
513
else (tl = tl->link = nd)->link = NIL(Grnode_t*);
514
}
515
} /**/DEBUG_ASSERT(hd && tl);
516
for(nd = hd; nd; nd = nd->link) /* now process in top-sort order */
517
{ for(e = nd->oedge; e; e = e->onext)
518
(tl = tl->link = e->head)->link = NIL(Grnode_t*);
519
x = TYPECAST(Vcsfxint_t,nd->label);
520
if(sfxosort(sfx, x, grp, 0) < 0)
521
goto ob_err;
522
sfxcsort(sfx, x, grp); /* copy-sort */
523
}
524
error = 0; /* have done well */
525
ob_err: if(gr)
526
grclose(gr);
527
}
528
#endif
529
530
/**/DEBUG_PRINT(2,"Cn=%d,",Cn); DEBUG_PRINT(2,"Cz=%d, ",Cz);
531
/**/DEBUG_PRINT(2,"In=%d,",In); DEBUG_PRINT(2,"Iz=%d, ",Iz);
532
/**/DEBUG_PRINT(2,"Qn=%d,",Qn); DEBUG_PRINT(2,"Qz=%d, ",Qz);
533
/**/DEBUG_PRINT(2,"Pn=%d,",Pn); DEBUG_PRINT(2,"Pz=%d,", Pz); DEBUG_PRINT(2,"Pc=%d\n",Pc);
534
/**/DEBUG_ASSERT(chkdata(sfx,0,sfx->nstr-1) && chksorted(sfx,0,sfx->nstr-1) );
535
536
if(error)
537
{ free(sfx);
538
sfx = NIL(Vcsfx_t*);
539
}
540
541
return sfx;
542
}
543
544