xref: /freebsd/contrib/xz/src/liblzma/lz/lz_encoder_mf.c (revision 5ca8e32633c4ffbbcd6762e5888b6a4ba0708c6c)
1 // SPDX-License-Identifier: 0BSD
2 
3 ///////////////////////////////////////////////////////////////////////////////
4 //
5 /// \file       lz_encoder_mf.c
6 /// \brief      Match finders
7 ///
8 //  Authors:    Igor Pavlov
9 //              Lasse Collin
10 //
11 ///////////////////////////////////////////////////////////////////////////////
12 
13 #include "lz_encoder.h"
14 #include "lz_encoder_hash.h"
15 #include "memcmplen.h"
16 
17 
18 /// \brief      Find matches starting from the current byte
19 ///
20 /// \return     The length of the longest match found
21 extern uint32_t
22 lzma_mf_find(lzma_mf *mf, uint32_t *count_ptr, lzma_match *matches)
23 {
24 	// Call the match finder. It returns the number of length-distance
25 	// pairs found.
26 	// FIXME: Minimum count is zero, what _exactly_ is the maximum?
27 	const uint32_t count = mf->find(mf, matches);
28 
29 	// Length of the longest match; assume that no matches were found
30 	// and thus the maximum length is zero.
31 	uint32_t len_best = 0;
32 
33 	if (count > 0) {
34 #ifndef NDEBUG
35 		// Validate the matches.
36 		for (uint32_t i = 0; i < count; ++i) {
37 			assert(matches[i].len <= mf->nice_len);
38 			assert(matches[i].dist < mf->read_pos);
39 			assert(memcmp(mf_ptr(mf) - 1,
40 				mf_ptr(mf) - matches[i].dist - 2,
41 				matches[i].len) == 0);
42 		}
43 #endif
44 
45 		// The last used element in the array contains
46 		// the longest match.
47 		len_best = matches[count - 1].len;
48 
49 		// If a match of maximum search length was found, try to
50 		// extend the match to maximum possible length.
51 		if (len_best == mf->nice_len) {
52 			// The limit for the match length is either the
53 			// maximum match length supported by the LZ-based
54 			// encoder or the number of bytes left in the
55 			// dictionary, whichever is smaller.
56 			uint32_t limit = mf_avail(mf) + 1;
57 			if (limit > mf->match_len_max)
58 				limit = mf->match_len_max;
59 
60 			// Pointer to the byte we just ran through
61 			// the match finder.
62 			const uint8_t *p1 = mf_ptr(mf) - 1;
63 
64 			// Pointer to the beginning of the match. We need -1
65 			// here because the match distances are zero based.
66 			const uint8_t *p2 = p1 - matches[count - 1].dist - 1;
67 
68 			len_best = lzma_memcmplen(p1, p2, len_best, limit);
69 		}
70 	}
71 
72 	*count_ptr = count;
73 
74 	// Finally update the read position to indicate that match finder was
75 	// run for this dictionary offset.
76 	++mf->read_ahead;
77 
78 	return len_best;
79 }
80 
81 
82 /// Hash value to indicate unused element in the hash. Since we start the
83 /// positions from dict_size + 1, zero is always too far to qualify
84 /// as usable match position.
85 #define EMPTY_HASH_VALUE 0
86 
87 
88 /// Normalization must be done when lzma_mf.offset + lzma_mf.read_pos
89 /// reaches MUST_NORMALIZE_POS.
90 #define MUST_NORMALIZE_POS UINT32_MAX
91 
92 
93 /// \brief      Normalizes hash values
94 ///
95 /// The hash arrays store positions of match candidates. The positions are
96 /// relative to an arbitrary offset that is not the same as the absolute
97 /// offset in the input stream. The relative position of the current byte
98 /// is lzma_mf.offset + lzma_mf.read_pos. The distances of the matches are
99 /// the differences of the current read position and the position found from
100 /// the hash.
101 ///
102 /// To prevent integer overflows of the offsets stored in the hash arrays,
103 /// we need to "normalize" the stored values now and then. During the
104 /// normalization, we drop values that indicate distance greater than the
105 /// dictionary size, thus making space for new values.
106 static void
107 normalize(lzma_mf *mf)
108 {
109 	assert(mf->read_pos + mf->offset == MUST_NORMALIZE_POS);
110 
111 	// In future we may not want to touch the lowest bits, because there
112 	// may be match finders that use larger resolution than one byte.
113 	const uint32_t subvalue
114 			= (MUST_NORMALIZE_POS - mf->cyclic_size);
115 				// & ~((UINT32_C(1) << 10) - 1);
116 
117 	for (uint32_t i = 0; i < mf->hash_count; ++i) {
118 		// If the distance is greater than the dictionary size,
119 		// we can simply mark the hash element as empty.
120 		if (mf->hash[i] <= subvalue)
121 			mf->hash[i] = EMPTY_HASH_VALUE;
122 		else
123 			mf->hash[i] -= subvalue;
124 	}
125 
126 	for (uint32_t i = 0; i < mf->sons_count; ++i) {
127 		// Do the same for mf->son.
128 		//
129 		// NOTE: There may be uninitialized elements in mf->son.
130 		// Valgrind may complain that the "if" below depends on
131 		// an uninitialized value. In this case it is safe to ignore
132 		// the warning. See also the comments in lz_encoder_init()
133 		// in lz_encoder.c.
134 		if (mf->son[i] <= subvalue)
135 			mf->son[i] = EMPTY_HASH_VALUE;
136 		else
137 			mf->son[i] -= subvalue;
138 	}
139 
140 	// Update offset to match the new locations.
141 	mf->offset -= subvalue;
142 
143 	return;
144 }
145 
146 
147 /// Mark the current byte as processed from point of view of the match finder.
148 static void
149 move_pos(lzma_mf *mf)
150 {
151 	if (++mf->cyclic_pos == mf->cyclic_size)
152 		mf->cyclic_pos = 0;
153 
154 	++mf->read_pos;
155 	assert(mf->read_pos <= mf->write_pos);
156 
157 	if (unlikely(mf->read_pos + mf->offset == UINT32_MAX))
158 		normalize(mf);
159 }
160 
161 
162 /// When flushing, we cannot run the match finder unless there is nice_len
163 /// bytes available in the dictionary. Instead, we skip running the match
164 /// finder (indicating that no match was found), and count how many bytes we
165 /// have ignored this way.
166 ///
167 /// When new data is given after the flushing was completed, the match finder
168 /// is restarted by rewinding mf->read_pos backwards by mf->pending. Then
169 /// the missed bytes are added to the hash using the match finder's skip
170 /// function (with small amount of input, it may start using mf->pending
171 /// again if flushing).
172 ///
173 /// Due to this rewinding, we don't touch cyclic_pos or test for
174 /// normalization. It will be done when the match finder's skip function
175 /// catches up after a flush.
176 static void
177 move_pending(lzma_mf *mf)
178 {
179 	++mf->read_pos;
180 	assert(mf->read_pos <= mf->write_pos);
181 	++mf->pending;
182 }
183 
184 
185 /// Calculate len_limit and determine if there is enough input to run
186 /// the actual match finder code. Sets up "cur" and "pos". This macro
187 /// is used by all find functions and binary tree skip functions. Hash
188 /// chain skip function doesn't need len_limit so a simpler code is used
189 /// in them.
190 #define header(is_bt, len_min, ret_op) \
191 	uint32_t len_limit = mf_avail(mf); \
192 	if (mf->nice_len <= len_limit) { \
193 		len_limit = mf->nice_len; \
194 	} else if (len_limit < (len_min) \
195 			|| (is_bt && mf->action == LZMA_SYNC_FLUSH)) { \
196 		assert(mf->action != LZMA_RUN); \
197 		move_pending(mf); \
198 		ret_op; \
199 	} \
200 	const uint8_t *cur = mf_ptr(mf); \
201 	const uint32_t pos = mf->read_pos + mf->offset
202 
203 
204 /// Header for find functions. "return 0" indicates that zero matches
205 /// were found.
206 #define header_find(is_bt, len_min) \
207 	header(is_bt, len_min, return 0); \
208 	uint32_t matches_count = 0
209 
210 
211 /// Header for a loop in a skip function. "continue" tells to skip the rest
212 /// of the code in the loop.
213 #define header_skip(is_bt, len_min) \
214 	header(is_bt, len_min, continue)
215 
216 
217 /// Calls hc_find_func() or bt_find_func() and calculates the total number
218 /// of matches found. Updates the dictionary position and returns the number
219 /// of matches found.
220 #define call_find(func, len_best) \
221 do { \
222 	matches_count = (uint32_t)(func(len_limit, pos, cur, cur_match, \
223 				mf->depth, mf->son, \
224 				mf->cyclic_pos, mf->cyclic_size, \
225 				matches + matches_count, len_best) \
226 			- matches); \
227 	move_pos(mf); \
228 	return matches_count; \
229 } while (0)
230 
231 
232 ////////////////
233 // Hash Chain //
234 ////////////////
235 
236 #if defined(HAVE_MF_HC3) || defined(HAVE_MF_HC4)
237 ///
238 ///
239 /// \param      len_limit       Don't look for matches longer than len_limit.
240 /// \param      pos             lzma_mf.read_pos + lzma_mf.offset
241 /// \param      cur             Pointer to current byte (mf_ptr(mf))
242 /// \param      cur_match       Start position of the current match candidate
243 /// \param      depth           Maximum length of the hash chain
244 /// \param      son             lzma_mf.son (contains the hash chain)
245 /// \param      cyclic_pos      lzma_mf.cyclic_pos
246 /// \param      cyclic_size     lzma_mf_cyclic_size
247 /// \param      matches         Array to hold the matches.
248 /// \param      len_best        The length of the longest match found so far.
249 static lzma_match *
250 hc_find_func(
251 		const uint32_t len_limit,
252 		const uint32_t pos,
253 		const uint8_t *const cur,
254 		uint32_t cur_match,
255 		uint32_t depth,
256 		uint32_t *const son,
257 		const uint32_t cyclic_pos,
258 		const uint32_t cyclic_size,
259 		lzma_match *matches,
260 		uint32_t len_best)
261 {
262 	son[cyclic_pos] = cur_match;
263 
264 	while (true) {
265 		const uint32_t delta = pos - cur_match;
266 		if (depth-- == 0 || delta >= cyclic_size)
267 			return matches;
268 
269 		const uint8_t *const pb = cur - delta;
270 		cur_match = son[cyclic_pos - delta
271 				+ (delta > cyclic_pos ? cyclic_size : 0)];
272 
273 		if (pb[len_best] == cur[len_best] && pb[0] == cur[0]) {
274 			uint32_t len = lzma_memcmplen(pb, cur, 1, len_limit);
275 
276 			if (len_best < len) {
277 				len_best = len;
278 				matches->len = len;
279 				matches->dist = delta - 1;
280 				++matches;
281 
282 				if (len == len_limit)
283 					return matches;
284 			}
285 		}
286 	}
287 }
288 
289 
290 #define hc_find(len_best) \
291 	call_find(hc_find_func, len_best)
292 
293 
294 #define hc_skip() \
295 do { \
296 	mf->son[mf->cyclic_pos] = cur_match; \
297 	move_pos(mf); \
298 } while (0)
299 
300 #endif
301 
302 
303 #ifdef HAVE_MF_HC3
304 extern uint32_t
305 lzma_mf_hc3_find(lzma_mf *mf, lzma_match *matches)
306 {
307 	header_find(false, 3);
308 
309 	hash_3_calc();
310 
311 	const uint32_t delta2 = pos - mf->hash[hash_2_value];
312 	const uint32_t cur_match = mf->hash[FIX_3_HASH_SIZE + hash_value];
313 
314 	mf->hash[hash_2_value] = pos;
315 	mf->hash[FIX_3_HASH_SIZE + hash_value] = pos;
316 
317 	uint32_t len_best = 2;
318 
319 	if (delta2 < mf->cyclic_size && *(cur - delta2) == *cur) {
320 		len_best = lzma_memcmplen(cur - delta2, cur,
321 				len_best, len_limit);
322 
323 		matches[0].len = len_best;
324 		matches[0].dist = delta2 - 1;
325 		matches_count = 1;
326 
327 		if (len_best == len_limit) {
328 			hc_skip();
329 			return 1; // matches_count
330 		}
331 	}
332 
333 	hc_find(len_best);
334 }
335 
336 
337 extern void
338 lzma_mf_hc3_skip(lzma_mf *mf, uint32_t amount)
339 {
340 	do {
341 		if (mf_avail(mf) < 3) {
342 			move_pending(mf);
343 			continue;
344 		}
345 
346 		const uint8_t *cur = mf_ptr(mf);
347 		const uint32_t pos = mf->read_pos + mf->offset;
348 
349 		hash_3_calc();
350 
351 		const uint32_t cur_match
352 				= mf->hash[FIX_3_HASH_SIZE + hash_value];
353 
354 		mf->hash[hash_2_value] = pos;
355 		mf->hash[FIX_3_HASH_SIZE + hash_value] = pos;
356 
357 		hc_skip();
358 
359 	} while (--amount != 0);
360 }
361 #endif
362 
363 
364 #ifdef HAVE_MF_HC4
365 extern uint32_t
366 lzma_mf_hc4_find(lzma_mf *mf, lzma_match *matches)
367 {
368 	header_find(false, 4);
369 
370 	hash_4_calc();
371 
372 	uint32_t delta2 = pos - mf->hash[hash_2_value];
373 	const uint32_t delta3
374 			= pos - mf->hash[FIX_3_HASH_SIZE + hash_3_value];
375 	const uint32_t cur_match = mf->hash[FIX_4_HASH_SIZE + hash_value];
376 
377 	mf->hash[hash_2_value ] = pos;
378 	mf->hash[FIX_3_HASH_SIZE + hash_3_value] = pos;
379 	mf->hash[FIX_4_HASH_SIZE + hash_value] = pos;
380 
381 	uint32_t len_best = 1;
382 
383 	if (delta2 < mf->cyclic_size && *(cur - delta2) == *cur) {
384 		len_best = 2;
385 		matches[0].len = 2;
386 		matches[0].dist = delta2 - 1;
387 		matches_count = 1;
388 	}
389 
390 	if (delta2 != delta3 && delta3 < mf->cyclic_size
391 			&& *(cur - delta3) == *cur) {
392 		len_best = 3;
393 		matches[matches_count++].dist = delta3 - 1;
394 		delta2 = delta3;
395 	}
396 
397 	if (matches_count != 0) {
398 		len_best = lzma_memcmplen(cur - delta2, cur,
399 				len_best, len_limit);
400 
401 		matches[matches_count - 1].len = len_best;
402 
403 		if (len_best == len_limit) {
404 			hc_skip();
405 			return matches_count;
406 		}
407 	}
408 
409 	if (len_best < 3)
410 		len_best = 3;
411 
412 	hc_find(len_best);
413 }
414 
415 
416 extern void
417 lzma_mf_hc4_skip(lzma_mf *mf, uint32_t amount)
418 {
419 	do {
420 		if (mf_avail(mf) < 4) {
421 			move_pending(mf);
422 			continue;
423 		}
424 
425 		const uint8_t *cur = mf_ptr(mf);
426 		const uint32_t pos = mf->read_pos + mf->offset;
427 
428 		hash_4_calc();
429 
430 		const uint32_t cur_match
431 				= mf->hash[FIX_4_HASH_SIZE + hash_value];
432 
433 		mf->hash[hash_2_value] = pos;
434 		mf->hash[FIX_3_HASH_SIZE + hash_3_value] = pos;
435 		mf->hash[FIX_4_HASH_SIZE + hash_value] = pos;
436 
437 		hc_skip();
438 
439 	} while (--amount != 0);
440 }
441 #endif
442 
443 
444 /////////////////
445 // Binary Tree //
446 /////////////////
447 
448 #if defined(HAVE_MF_BT2) || defined(HAVE_MF_BT3) || defined(HAVE_MF_BT4)
449 static lzma_match *
450 bt_find_func(
451 		const uint32_t len_limit,
452 		const uint32_t pos,
453 		const uint8_t *const cur,
454 		uint32_t cur_match,
455 		uint32_t depth,
456 		uint32_t *const son,
457 		const uint32_t cyclic_pos,
458 		const uint32_t cyclic_size,
459 		lzma_match *matches,
460 		uint32_t len_best)
461 {
462 	uint32_t *ptr0 = son + (cyclic_pos << 1) + 1;
463 	uint32_t *ptr1 = son + (cyclic_pos << 1);
464 
465 	uint32_t len0 = 0;
466 	uint32_t len1 = 0;
467 
468 	while (true) {
469 		const uint32_t delta = pos - cur_match;
470 		if (depth-- == 0 || delta >= cyclic_size) {
471 			*ptr0 = EMPTY_HASH_VALUE;
472 			*ptr1 = EMPTY_HASH_VALUE;
473 			return matches;
474 		}
475 
476 		uint32_t *const pair = son + ((cyclic_pos - delta
477 				+ (delta > cyclic_pos ? cyclic_size : 0))
478 				<< 1);
479 
480 		const uint8_t *const pb = cur - delta;
481 		uint32_t len = my_min(len0, len1);
482 
483 		if (pb[len] == cur[len]) {
484 			len = lzma_memcmplen(pb, cur, len + 1, len_limit);
485 
486 			if (len_best < len) {
487 				len_best = len;
488 				matches->len = len;
489 				matches->dist = delta - 1;
490 				++matches;
491 
492 				if (len == len_limit) {
493 					*ptr1 = pair[0];
494 					*ptr0 = pair[1];
495 					return matches;
496 				}
497 			}
498 		}
499 
500 		if (pb[len] < cur[len]) {
501 			*ptr1 = cur_match;
502 			ptr1 = pair + 1;
503 			cur_match = *ptr1;
504 			len1 = len;
505 		} else {
506 			*ptr0 = cur_match;
507 			ptr0 = pair;
508 			cur_match = *ptr0;
509 			len0 = len;
510 		}
511 	}
512 }
513 
514 
515 static void
516 bt_skip_func(
517 		const uint32_t len_limit,
518 		const uint32_t pos,
519 		const uint8_t *const cur,
520 		uint32_t cur_match,
521 		uint32_t depth,
522 		uint32_t *const son,
523 		const uint32_t cyclic_pos,
524 		const uint32_t cyclic_size)
525 {
526 	uint32_t *ptr0 = son + (cyclic_pos << 1) + 1;
527 	uint32_t *ptr1 = son + (cyclic_pos << 1);
528 
529 	uint32_t len0 = 0;
530 	uint32_t len1 = 0;
531 
532 	while (true) {
533 		const uint32_t delta = pos - cur_match;
534 		if (depth-- == 0 || delta >= cyclic_size) {
535 			*ptr0 = EMPTY_HASH_VALUE;
536 			*ptr1 = EMPTY_HASH_VALUE;
537 			return;
538 		}
539 
540 		uint32_t *pair = son + ((cyclic_pos - delta
541 				+ (delta > cyclic_pos ? cyclic_size : 0))
542 				<< 1);
543 		const uint8_t *pb = cur - delta;
544 		uint32_t len = my_min(len0, len1);
545 
546 		if (pb[len] == cur[len]) {
547 			len = lzma_memcmplen(pb, cur, len + 1, len_limit);
548 
549 			if (len == len_limit) {
550 				*ptr1 = pair[0];
551 				*ptr0 = pair[1];
552 				return;
553 			}
554 		}
555 
556 		if (pb[len] < cur[len]) {
557 			*ptr1 = cur_match;
558 			ptr1 = pair + 1;
559 			cur_match = *ptr1;
560 			len1 = len;
561 		} else {
562 			*ptr0 = cur_match;
563 			ptr0 = pair;
564 			cur_match = *ptr0;
565 			len0 = len;
566 		}
567 	}
568 }
569 
570 
571 #define bt_find(len_best) \
572 	call_find(bt_find_func, len_best)
573 
574 #define bt_skip() \
575 do { \
576 	bt_skip_func(len_limit, pos, cur, cur_match, mf->depth, \
577 			mf->son, mf->cyclic_pos, \
578 			mf->cyclic_size); \
579 	move_pos(mf); \
580 } while (0)
581 
582 #endif
583 
584 
585 #ifdef HAVE_MF_BT2
586 extern uint32_t
587 lzma_mf_bt2_find(lzma_mf *mf, lzma_match *matches)
588 {
589 	header_find(true, 2);
590 
591 	hash_2_calc();
592 
593 	const uint32_t cur_match = mf->hash[hash_value];
594 	mf->hash[hash_value] = pos;
595 
596 	bt_find(1);
597 }
598 
599 
600 extern void
601 lzma_mf_bt2_skip(lzma_mf *mf, uint32_t amount)
602 {
603 	do {
604 		header_skip(true, 2);
605 
606 		hash_2_calc();
607 
608 		const uint32_t cur_match = mf->hash[hash_value];
609 		mf->hash[hash_value] = pos;
610 
611 		bt_skip();
612 
613 	} while (--amount != 0);
614 }
615 #endif
616 
617 
618 #ifdef HAVE_MF_BT3
619 extern uint32_t
620 lzma_mf_bt3_find(lzma_mf *mf, lzma_match *matches)
621 {
622 	header_find(true, 3);
623 
624 	hash_3_calc();
625 
626 	const uint32_t delta2 = pos - mf->hash[hash_2_value];
627 	const uint32_t cur_match = mf->hash[FIX_3_HASH_SIZE + hash_value];
628 
629 	mf->hash[hash_2_value] = pos;
630 	mf->hash[FIX_3_HASH_SIZE + hash_value] = pos;
631 
632 	uint32_t len_best = 2;
633 
634 	if (delta2 < mf->cyclic_size && *(cur - delta2) == *cur) {
635 		len_best = lzma_memcmplen(
636 				cur, cur - delta2, len_best, len_limit);
637 
638 		matches[0].len = len_best;
639 		matches[0].dist = delta2 - 1;
640 		matches_count = 1;
641 
642 		if (len_best == len_limit) {
643 			bt_skip();
644 			return 1; // matches_count
645 		}
646 	}
647 
648 	bt_find(len_best);
649 }
650 
651 
652 extern void
653 lzma_mf_bt3_skip(lzma_mf *mf, uint32_t amount)
654 {
655 	do {
656 		header_skip(true, 3);
657 
658 		hash_3_calc();
659 
660 		const uint32_t cur_match
661 				= mf->hash[FIX_3_HASH_SIZE + hash_value];
662 
663 		mf->hash[hash_2_value] = pos;
664 		mf->hash[FIX_3_HASH_SIZE + hash_value] = pos;
665 
666 		bt_skip();
667 
668 	} while (--amount != 0);
669 }
670 #endif
671 
672 
673 #ifdef HAVE_MF_BT4
674 extern uint32_t
675 lzma_mf_bt4_find(lzma_mf *mf, lzma_match *matches)
676 {
677 	header_find(true, 4);
678 
679 	hash_4_calc();
680 
681 	uint32_t delta2 = pos - mf->hash[hash_2_value];
682 	const uint32_t delta3
683 			= pos - mf->hash[FIX_3_HASH_SIZE + hash_3_value];
684 	const uint32_t cur_match = mf->hash[FIX_4_HASH_SIZE + hash_value];
685 
686 	mf->hash[hash_2_value] = pos;
687 	mf->hash[FIX_3_HASH_SIZE + hash_3_value] = pos;
688 	mf->hash[FIX_4_HASH_SIZE + hash_value] = pos;
689 
690 	uint32_t len_best = 1;
691 
692 	if (delta2 < mf->cyclic_size && *(cur - delta2) == *cur) {
693 		len_best = 2;
694 		matches[0].len = 2;
695 		matches[0].dist = delta2 - 1;
696 		matches_count = 1;
697 	}
698 
699 	if (delta2 != delta3 && delta3 < mf->cyclic_size
700 			&& *(cur - delta3) == *cur) {
701 		len_best = 3;
702 		matches[matches_count++].dist = delta3 - 1;
703 		delta2 = delta3;
704 	}
705 
706 	if (matches_count != 0) {
707 		len_best = lzma_memcmplen(
708 				cur, cur - delta2, len_best, len_limit);
709 
710 		matches[matches_count - 1].len = len_best;
711 
712 		if (len_best == len_limit) {
713 			bt_skip();
714 			return matches_count;
715 		}
716 	}
717 
718 	if (len_best < 3)
719 		len_best = 3;
720 
721 	bt_find(len_best);
722 }
723 
724 
725 extern void
726 lzma_mf_bt4_skip(lzma_mf *mf, uint32_t amount)
727 {
728 	do {
729 		header_skip(true, 4);
730 
731 		hash_4_calc();
732 
733 		const uint32_t cur_match
734 				= mf->hash[FIX_4_HASH_SIZE + hash_value];
735 
736 		mf->hash[hash_2_value] = pos;
737 		mf->hash[FIX_3_HASH_SIZE + hash_3_value] = pos;
738 		mf->hash[FIX_4_HASH_SIZE + hash_value] = pos;
739 
740 		bt_skip();
741 
742 	} while (--amount != 0);
743 }
744 #endif
745