xref: /original-bsd/usr.bin/window/compress.c (revision 860e07fc)
1 /*
2  * Copyright (c) 1989 Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Edward Wang at The University of California, Berkeley.
7  *
8  * %sccs.include.redist.c%
9  */
10 
11 #ifndef lint
12 static char sccsid[] = "@(#)compress.c	3.7 (Berkeley) 08/24/92";
13 #endif /* not lint */
14 
15 #include "ww.h"
16 #include "tt.h"
17 
18 	/* special */
19 #include <stdio.h>
20 #include <fcntl.h>
21 int cc_trace = 0;
22 FILE *cc_trace_fp;
23 
24 	/* tunable parameters */
25 
26 int cc_reverse = 1;
27 int cc_sort = 0;
28 int cc_chop = 0;
29 
30 int cc_token_max = 8;		/* <= TOKEN_MAX */
31 int cc_token_min = 2;		/* > tt.tt_put_token_cost */
32 int cc_npass0 = 1;
33 int cc_npass1 = 1;
34 
35 int cc_bufsize = 1024 * 3;	/* XXX, or 80 * 24 * 2 */
36 
37 int cc_ntoken = 8192;
38 
39 #define cc_weight XXX
40 #ifndef cc_weight
41 int cc_weight = 0;
42 #endif
43 
44 #define TOKEN_MAX 16
45 
46 struct cc {
47 	char string[TOKEN_MAX];
48 	char length;
49 	char flag;
50 #ifndef cc_weight
51 	short weight;
52 #endif
53 	long time;		/* time last seen */
54 	short bcount;		/* count in this buffer */
55 	short ccount;		/* count in compression */
56 	short places;		/* places in the buffer */
57 	short code;		/* token code */
58 	struct cc *qforw, *qback;
59 	struct cc *hforw, **hback;
60 };
61 
62 short cc_thresholds[TOKEN_MAX + 1];
63 #define thresh(length) (cc_thresholds[length])
64 #define threshp(code, count, length) \
65 	((code) >= 0 || (short) (count) >= cc_thresholds[length])
66 
67 #ifndef cc_weight
68 short cc_wthresholds[TOKEN_MAX + 1];
69 #define wthresh(length) (cc_wthresholds[length])
70 #define wthreshp(weight, length) ((short) (weight) >= cc_wthresholds[length])
71 #else
72 #define wthreshp(weight, length) (0)
73 #endif
74 
75 #ifndef cc_weight
76 short cc_wlimits[TOKEN_MAX + 1];
77 #define wlimit(length) (cc_wlimits[length])
78 #endif
79 
80 #define put_token_score(length) ((length) - tt.tt_put_token_cost)
81 
82 int cc_score_adjustments[TOKEN_MAX + 1][8]; /* XXX, 8 > max of cc_thresholds */
83 #define score_adjust(score, p) \
84 	do { \
85 		int length = (p)->length; \
86 		int ccount = (p)->ccount; \
87 		if (threshp((p)->code, ccount, length) || \
88 		    wthreshp((p)->weight, length)) /* XXX */ \
89 			(score) -= length - tt.tt_put_token_cost; \
90 		else \
91 			(score) += cc_score_adjustments[length][ccount]; \
92 	} while (0)
93 
94 int cc_initial_scores[TOKEN_MAX + 1][8]; /* XXX, 8 > max of cc_thresholds */
95 
96 struct cc cc_q0a, cc_q0b, cc_q1a, cc_q1b;
97 
98 #define qinsert(p1, p2) \
99 	do { \
100 		register struct cc *forw = (p1)->qforw; \
101 		register struct cc *back = (p1)->qback; \
102 		back->qforw = forw; \
103 		forw->qback = back; \
104 		forw = (p2)->qforw; \
105 		(p1)->qforw = forw; \
106 		forw->qback = (p1); \
107 		(p2)->qforw = (p1); \
108 		(p1)->qback = (p2); \
109 	} while (0)
110 
111 #define qinsertq(q, p) \
112 	((q)->qforw == (q) ? 0 : \
113 	 ((q)->qback->qforw = (p)->qforw, \
114 	  (p)->qforw->qback = (q)->qback, \
115 	  (q)->qforw->qback = (p), \
116 	  (p)->qforw = (q)->qforw, \
117 	  (q)->qforw = (q), \
118 	  (q)->qback = (q)))
119 
120 #define H		(14)
121 #define HSIZE		(1 << H)
122 #define hash(h, c)	((((h) >> H - 8 | (h) << 8) ^ (c)) & HSIZE - 1)
123 
124 char *cc_buffer;
125 struct cc **cc_output;			/* the output array */
126 short *cc_places[TOKEN_MAX + 1];
127 short *cc_hashcodes;			/* for computing hashcodes */
128 struct cc **cc_htab;			/* the hash table */
129 struct cc **cc_tokens;			/* holds all the active tokens */
130 struct cc_undo {
131 	struct cc **pos;
132 	struct cc *val;
133 } *cc_undo;
134 
135 long cc_time, cc_time0;
136 
137 char *cc_tt_ob, *cc_tt_obe;
138 
139 ccinit()
140 {
141 	register i, j;
142 	register struct cc *p;
143 
144 	if (tt.tt_token_max > cc_token_max)
145 		tt.tt_token_max = cc_token_max;
146 	if (tt.tt_token_min < cc_token_min)
147 		tt.tt_token_min = cc_token_min;
148 	if (tt.tt_token_min > tt.tt_token_max) {
149 		tt.tt_ntoken = 0;
150 		return 0;
151 	}
152 	if (tt.tt_ntoken > cc_ntoken / 2)	/* not likely */
153 		tt.tt_ntoken = cc_ntoken / 2;
154 #define C(x) (sizeof (x) / sizeof *(x))
155 	for (i = 0; i < C(cc_thresholds); i++) {
156 		int h = i - tt.tt_put_token_cost;
157 		if (h > 0)
158 			cc_thresholds[i] =
159 				(tt.tt_set_token_cost + 1 + h - 1) / h + 1;
160 		else
161 			cc_thresholds[i] = 0;
162 	}
163 	for (i = 0; i < C(cc_score_adjustments); i++) {
164 		int t = cc_thresholds[i];
165 		for (j = 0; j < C(*cc_score_adjustments); j++) {
166 			if (j >= t)
167 				cc_score_adjustments[i][j] =
168 					- (i - tt.tt_put_token_cost);
169 			else if (j < t - 1)
170 				cc_score_adjustments[i][j] = 0;
171 			else
172 				/*
173 				 * cost now is
174 				 *	length * (ccount + 1)		a
175 				 * cost before was
176 				 *	set-token-cost + length +
177 				 *		ccount * put-token-cost	b
178 				 * the score adjustment is (b - a)
179 				 */
180 				cc_score_adjustments[i][j] =
181 					tt.tt_set_token_cost + i +
182 						j * tt.tt_put_token_cost -
183 							i * (j + 1);
184 			if (j >= t)
185 				cc_initial_scores[i][j] = 0;
186 			else
187 				/*
188 				 * - (set-token-cost +
189 				 *	(length - put-token-cost) -
190 				 *	(length - put-token-cost) * ccount)
191 				 */
192 				cc_initial_scores[i][j] =
193 					- (tt.tt_set_token_cost +
194 					   (i - tt.tt_put_token_cost) -
195 					   (i - tt.tt_put_token_cost) * j);
196 		}
197 	}
198 #ifndef cc_weight
199 	for (i = 1; i < C(cc_wthresholds); i++) {
200 		cc_wthresholds[i] =
201 			((tt.tt_set_token_cost + tt.tt_put_token_cost) / i +
202 				i / 5 + 1) *
203 				cc_weight + 1;
204 		cc_wlimits[i] = cc_wthresholds[i] + cc_weight;
205 	}
206 #endif
207 #undef C
208 	if ((cc_output = (struct cc **)
209 	     malloc((unsigned) cc_bufsize * sizeof *cc_output)) == 0)
210 		goto nomem;
211 	if ((cc_hashcodes = (short *)
212 	     malloc((unsigned) cc_bufsize * sizeof *cc_hashcodes)) == 0)
213 		goto nomem;
214 	if ((cc_htab = (struct cc **) malloc(HSIZE * sizeof *cc_htab)) == 0)
215 		goto nomem;
216 	if ((cc_tokens = (struct cc **)
217 	     malloc((unsigned)
218 	            (cc_ntoken + tt.tt_token_max - tt.tt_token_min + 1) *
219 		    sizeof *cc_tokens)) == 0)
220 		goto nomem;
221 	if ((cc_undo = (struct cc_undo *)
222 	     malloc((unsigned) cc_bufsize * sizeof *cc_undo)) == 0)
223 		goto nomem;
224 	for (i = tt.tt_token_min; i <= tt.tt_token_max; i++)
225 		if ((cc_places[i] = (short *)
226 		     malloc((unsigned) cc_bufsize * sizeof **cc_places)) == 0)
227 			goto nomem;
228 	cc_q0a.qforw = cc_q0a.qback = &cc_q0a;
229 	cc_q0b.qforw = cc_q0b.qback = &cc_q0b;
230 	cc_q1a.qforw = cc_q1a.qback = &cc_q1a;
231 	cc_q1b.qforw = cc_q1b.qback = &cc_q1b;
232 	if ((p = (struct cc *) malloc((unsigned) cc_ntoken * sizeof *p)) == 0)
233 		goto nomem;
234 	for (i = 0; i < tt.tt_ntoken; i++) {
235 		p->code = i;
236 		p->time = -1;
237 		p->qback = cc_q0a.qback;
238 		p->qforw = &cc_q0a;
239 		p->qback->qforw = p;
240 		cc_q0a.qback = p;
241 		p++;
242 	}
243 	for (; i < cc_ntoken; i++) {
244 		p->code = -1;
245 		p->time = -1;
246 		p->qback = cc_q1a.qback;
247 		p->qforw = &cc_q1a;
248 		p->qback->qforw = p;
249 		cc_q1a.qback = p;
250 		p++;
251 	}
252 	cc_tt_ob = tt_ob;
253 	cc_tt_obe = tt_obe;
254 	if ((cc_buffer = malloc((unsigned) cc_bufsize)) == 0)
255 		goto nomem;
256 	return 0;
257 nomem:
258 	wwerrno = WWE_NOMEM;
259 	return -1;
260 }
261 
262 ccstart()
263 {
264 	register struct cc *p;
265 	int ccflush();
266 
267 	(*tt.tt_flush)();
268 	tt_obp = tt_ob = cc_buffer;
269 	tt_obe = tt_ob + cc_bufsize;
270 	tt.tt_flush = ccflush;
271 	bzero((char *) cc_htab, HSIZE * sizeof *cc_htab);
272 	for (p = cc_q0a.qforw; p != &cc_q0a; p = p->qforw)
273 		p->hback = 0;
274 	for (p = cc_q1a.qforw; p != &cc_q1a; p = p->qforw)
275 		p->hback = 0;
276 	if (cc_trace) {
277 		cc_trace_fp = fopen("window-trace", "a");
278 		(void) fcntl(fileno(cc_trace_fp), F_SETFD, 1);
279 	}
280 }
281 
282 ccend()
283 {
284 	int ttflush();
285 
286 	(*tt.tt_flush)();
287 	tt_obp = tt_ob = cc_tt_ob;
288 	tt_obe = cc_tt_obe;
289 	tt.tt_flush = ttflush;
290 	if (cc_trace_fp != NULL) {
291 		(void) fclose(cc_trace_fp);
292 		cc_trace_fp = NULL;
293 	}
294 }
295 
296 ccflush()
297 {
298 	int bufsize = tt_obp - tt_ob;
299 	int n;
300 	int ttflush();
301 
302 	if (tt_ob != cc_buffer)
303 		abort();
304 	if (cc_trace_fp != NULL) {
305 		(void) fwrite(tt_ob, 1, bufsize, cc_trace_fp);
306 		putc(-1, cc_trace_fp);
307 	}
308 	if (bufsize < tt.tt_token_min) {
309 		ttflush();
310 		return;
311 	}
312 	tt_obp = tt_ob = cc_tt_ob;
313 	tt_obe = cc_tt_obe;
314 	tt.tt_flush = ttflush;
315 	cc_time0 = cc_time;
316 	cc_time += bufsize;
317 	n = cc_sweep_phase(cc_buffer, bufsize, cc_tokens);
318 	cc_compress_phase(cc_output, bufsize, cc_tokens, n);
319 	cc_output_phase(cc_buffer, cc_output, bufsize);
320 	ttflush();
321 	tt_obp = tt_ob = cc_buffer;
322 	tt_obe = cc_buffer + cc_bufsize;
323 	tt.tt_flush = ccflush;
324 }
325 
326 cc_sweep_phase(buffer, bufsize, tokens)
327 	char *buffer;
328 	struct cc **tokens;
329 {
330 	register struct cc **pp = tokens;
331 	register i, n;
332 #ifdef STATS
333 	int nn, ii;
334 #endif
335 
336 #ifdef STATS
337 	if (verbose >= 0)
338 		time_begin();
339 	if (verbose > 0)
340 		printf("Sweep:");
341 #endif
342 	cc_sweep0(buffer, bufsize, tt.tt_token_min - 1);
343 #ifdef STATS
344 	ntoken_stat = 0;
345 	nn = 0;
346 	ii = 0;
347 #endif
348 	for (i = tt.tt_token_min; i <= tt.tt_token_max; i++) {
349 #ifdef STATS
350 		if (verbose > 0) {
351 			if (ii > 7) {
352 				printf("\n      ");
353 				ii = 0;
354 			}
355 			ii++;
356 			printf(" (%d", i);
357 			(void) fflush(stdout);
358 		}
359 #endif
360 		n = cc_sweep(buffer, bufsize, pp, i);
361 		pp += n;
362 #ifdef STATS
363 		if (verbose > 0) {
364 			if (--n > 0) {
365 				printf(" %d", n);
366 				nn += n;
367 			}
368 			putchar(')');
369 		}
370 #endif
371 	}
372 	qinsertq(&cc_q1b, &cc_q1a);
373 #ifdef STATS
374 	if (verbose > 0)
375 		printf("\n       %d tokens, %d candidates\n",
376 			ntoken_stat, nn);
377 	if (verbose >= 0)
378 		time_end();
379 #endif
380 	return pp - tokens;
381 }
382 
383 cc_sweep0(buffer, n, length)
384 	char *buffer;
385 {
386 	register char *p;
387 	register short *hc;
388 	register i;
389 	register short c;
390 	register short pc = tt.tt_padc;
391 
392 	/* n and length are at least 1 */
393 	p = buffer++;
394 	hc = cc_hashcodes;
395 	i = n;
396 	do {
397 		if ((*hc++ = *p++) == pc)
398 			hc[-1] = -1;
399 	} while (--i);
400 	while (--length) {
401 		p = buffer++;
402 		hc = cc_hashcodes;
403 		for (i = n--; --i;) {
404 			if ((c = *p++) == pc || *hc < 0)
405 				c = -1;
406 			else
407 				c = hash(*hc, c);
408 			*hc++ = c;
409 		}
410 	}
411 }
412 
413 cc_sweep(buffer, bufsize, tokens, length)
414 	char *buffer;
415 	struct cc **tokens;
416 	register length;
417 {
418 	register struct cc *p;
419 	register char *cp;
420 	register i;
421 	short *hc;
422 	short *places = cc_places[length];
423 	struct cc **pp = tokens;
424 	short threshold = thresh(length);
425 #ifndef cc_weight
426 	short wthreshold = wthresh(length);
427 	short limit = wlimit(length);
428 #endif
429 	int time;
430 	short pc = tt.tt_padc;
431 
432 	i = length - 1;
433 	bufsize -= i;
434 	cp = buffer + i;
435 	hc = cc_hashcodes;
436 	time = cc_time0;
437 	for (i = 0; i < bufsize; i++, time++) {
438 		struct cc **h;
439 
440 		{
441 			register short *hc1 = hc;
442 			register short c = *cp++;
443 			register short hh;
444 			if ((hh = *hc1) < 0 || c == pc) {
445 				*hc1++ = -1;
446 				hc = hc1;
447 				continue;
448 			}
449 			h = cc_htab + (*hc1++ = hash(hh, c));
450 			hc = hc1;
451 		}
452 		for (p = *h; p != 0; p = p->hforw)
453 			if (p->length == (char) length) {
454 				register char *p1 = p->string;
455 				register char *p2 = cp - length;
456 				register n = length;
457 				do
458 					if (*p1++ != *p2++)
459 						goto fail;
460 				while (--n);
461 				break;
462 			fail:;
463 			}
464 		if (p == 0) {
465 			p = cc_q1a.qback;
466 			if (p == &cc_q1a ||
467 			    p->time >= cc_time0 && p->length == (char) length)
468 				continue;
469 			if (p->hback != 0)
470 				if ((*p->hback = p->hforw) != 0)
471 					p->hforw->hback = p->hback;
472 			{
473 				register char *p1 = p->string;
474 				register char *p2 = cp - length;
475 				register n = length;
476 				do
477 					*p1++ = *p2++;
478 				while (--n);
479 			}
480 			p->length = length;
481 #ifndef cc_weight
482 			p->weight = cc_weight;
483 #endif
484 			p->time = time;
485 			p->bcount = 1;
486 			p->ccount = 0;
487 			p->flag = 0;
488 			if ((p->hforw = *h) != 0)
489 				p->hforw->hback = &p->hforw;
490 			*h = p;
491 			p->hback = h;
492 			qinsert(p, &cc_q1a);
493 			places[i] = -1;
494 			p->places = i;
495 #ifdef STATS
496 			ntoken_stat++;
497 #endif
498 		} else if (p->time < cc_time0) {
499 #ifndef cc_weight
500 			if ((p->weight += p->time - time) < 0)
501 				p->weight = cc_weight;
502 			else if ((p->weight += cc_weight) > limit)
503 				p->weight = limit;
504 #endif
505 			p->time = time;
506 			p->bcount = 1;
507 			p->ccount = 0;
508 			if (p->code >= 0) {
509 				p->flag = 1;
510 				*pp++ = p;
511 			} else
512 #ifndef cc_weight
513 			if (p->weight >= wthreshold) {
514 				p->flag = 1;
515 				*pp++ = p;
516 				qinsert(p, &cc_q1b);
517 			} else
518 #endif
519 			{
520 				p->flag = 0;
521 				qinsert(p, &cc_q1a);
522 			}
523 			places[i] = -1;
524 			p->places = i;
525 #ifdef STATS
526 			ntoken_stat++;
527 #endif
528 		} else if (p->time + length > time) {
529 			/*
530 			 * overlapping token, don't count as two and
531 			 * don't update time, but do adjust weight to offset
532 			 * the difference
533 			 */
534 #ifndef cc_weight
535 			if (cc_weight != 0) {	/* XXX */
536 				p->weight += time - p->time;
537 				if (!p->flag && p->weight >= wthreshold) {
538 					p->flag = 1;
539 					*pp++ = p;
540 					qinsert(p, &cc_q1b);
541 				}
542 			}
543 #endif
544 			places[i] = p->places;
545 			p->places = i;
546 		} else {
547 #ifndef cc_weight
548 			if ((p->weight += p->time - time) < 0)
549 				p->weight = cc_weight;
550 			else if ((p->weight += cc_weight) > limit)
551 				p->weight = limit;
552 #endif
553 			p->time = time;
554 			p->bcount++;
555 			if (!p->flag &&
556 			    /* code must be < 0 if flag false here */
557 			    (p->bcount >= threshold
558 #ifndef cc_weight
559 			     || p->weight >= wthreshold
560 #endif
561 			     )) {
562 				p->flag = 1;
563 				*pp++ = p;
564 				qinsert(p, &cc_q1b);
565 			}
566 			places[i] = p->places;
567 			p->places = i;
568 		}
569 	}
570 	if ((i = pp - tokens) > 0) {
571 		*pp = 0;
572 		if (cc_reverse)
573 			cc_sweep_reverse(tokens, places);
574 		if (cc_sort && i > 1) {
575 			int cc_token_compare();
576 			qsort((char *) tokens, i, sizeof *tokens,
577 			      cc_token_compare);
578 		}
579 		if (cc_chop) {
580 			if ((i = i * cc_chop / 100) == 0)
581 				i = 1;
582 			tokens[i] = 0;
583 		}
584 		i++;
585 	}
586 	return i;
587 }
588 
589 cc_sweep_reverse(pp, places)
590 	register struct cc **pp;
591 	register short *places;
592 {
593 	register struct cc *p;
594 	register short front, back, t;
595 
596 	while ((p = *pp++) != 0) {
597 		back = -1;
598 		t = p->places;
599 		/* the list is never empty */
600 		do {
601 			front = places[t];
602 			places[t] = back;
603 			back = t;
604 		} while ((t = front) >= 0);
605 		p->places = back;
606 	}
607 }
608 
609 cc_compress_phase(output, bufsize, tokens, ntoken)
610 	struct cc **output;
611 	struct cc **tokens;
612 {
613 	register i;
614 
615 	bzero((char *) output, bufsize * sizeof *output);
616 	for (i = 0; i < cc_npass0; i++)
617 		cc_compress_phase1(output, tokens, ntoken, 0);
618 	for (i = 0; i < cc_npass1; i++)
619 		cc_compress_phase1(output, tokens, ntoken, 1);
620 	cc_compress_cleanup(output, bufsize);
621 }
622 
623 cc_compress_phase1(output, tokens, ntoken, flag)
624 	register struct cc **output;
625 	struct cc **tokens;
626 {
627 	register struct cc **pp;
628 #ifdef STATS
629 	register int i = 0;
630 	int nt = 0, cc = 0, nc = 0;
631 #endif
632 
633 #ifdef STATS
634 	if (verbose >= 0)
635 		time_begin();
636 	if (verbose > 0)
637 		printf("Compress:");
638 #endif
639 	pp = tokens;
640 	while (pp < tokens + ntoken) {
641 #ifdef STATS
642 		if (verbose > 0) {
643 			ntoken_stat = 0;
644 			ccount_stat = 0;
645 			ncover_stat = 0;
646 			if (i > 2) {
647 				printf("\n         ");
648 				i = 0;
649 			}
650 			i++;
651 			printf(" (%d", (*pp)->length);
652 			(void) fflush(stdout);
653 		}
654 #endif
655 		pp += cc_compress(output, pp, flag);
656 #ifdef STATS
657 		if (verbose > 0) {
658 			printf(" %dt %du %dc)", ntoken_stat, ccount_stat,
659 			       ncover_stat);
660 			nt += ntoken_stat;
661 			cc += ccount_stat;
662 			nc += ncover_stat;
663 		}
664 #endif
665 	}
666 #ifdef STATS
667 	if (verbose > 0)
668 		printf("\n   total: (%dt %du %dc)\n", nt, cc, nc);
669 	if (verbose >= 0)
670 		time_end();
671 #endif
672 }
673 
674 cc_compress_cleanup(output, bufsize)
675 	register struct cc **output;
676 {
677 	register struct cc **end;
678 
679 	/* the previous output phase may have been interrupted */
680 	qinsertq(&cc_q0b, &cc_q0a);
681 	for (end = output + bufsize; output < end;) {
682 		register struct cc *p;
683 		register length;
684 		if ((p = *output) == 0) {
685 			output++;
686 			continue;
687 		}
688 		length = p->length;
689 		if (!p->flag) {
690 		} else if (p->code >= 0) {
691 			qinsert(p, &cc_q0b);
692 			p->flag = 0;
693 		} else if (p->ccount == 0) {
694 			*output = 0;
695 		} else if (p->ccount >= thresh(length)
696 #ifndef cc_weight
697 			   || wthreshp(p->weight, length)
698 #endif
699 			   ) {
700 			p->flag = 0;
701 		} else {
702 			p->ccount = 0;
703 			*output = 0;
704 		}
705 		output += length;
706 	}
707 }
708 
709 cc_compress(output, tokens, flag)
710 	struct cc **output;
711 	struct cc **tokens;
712 	char flag;
713 {
714 	struct cc **pp = tokens;
715 	register struct cc *p = *pp++;
716 	int length = p->length;
717 	int threshold = thresh(length);
718 #ifndef cc_weight
719 	short wthreshold = wthresh(length);
720 #endif
721 	short *places = cc_places[length];
722 	int *initial_scores = cc_initial_scores[length];
723 	int initial_score0 = put_token_score(length);
724 
725 	do {
726 		int score;
727 		register struct cc_undo *undop;
728 		int ccount;
729 #ifdef STATS
730 		int ncover;
731 #endif
732 		int i;
733 
734 		ccount = p->ccount;
735 		if ((short) ccount >= p->bcount)
736 			continue;
737 		if (p->code >= 0 || ccount >= threshold)
738 			score = 0;
739 #ifndef cc_weight
740 		else if (p->weight >= wthreshold)
741 			/* allow one fewer match than normal */
742 			/* XXX, should adjust for ccount */
743 			score = - tt.tt_set_token_cost;
744 #endif
745 		else
746 			score = initial_scores[ccount];
747 		undop = cc_undo;
748 #ifdef STATS
749 		ncover = 0;
750 #endif
751 		for (i = p->places; i >= 0; i = places[i]) {
752 			register struct cc **jp;
753 			register struct cc *x;
754 			register struct cc **ip = output + i;
755 			register score0 = initial_score0;
756 			struct cc **iip = ip + length;
757 			struct cc_undo *undop1 = undop;
758 
759 			if ((x = *(jp = ip)) != 0)
760 				goto z;
761 			while (--jp >= output)
762 				if ((x = *jp) != 0) {
763 					if (jp + x->length > ip)
764 						goto z;
765 					break;
766 				}
767 			jp = ip + 1;
768 			while (jp < iip) {
769 				if ((x = *jp) == 0) {
770 					jp++;
771 					continue;
772 				}
773 			z:
774 				if (x == p)
775 					goto undo;
776 #ifdef STATS
777 				ncover++;
778 #endif
779 				undop->pos = jp;
780 				undop->val = x;
781 				undop++;
782 				*jp = 0;
783 				x->ccount--;
784 				score_adjust(score0, x);
785 				if (score0 < 0 && flag)
786 					goto undo;
787 				jp += x->length;
788 			}
789 			undop->pos = ip;
790 			undop->val = 0;
791 			undop++;
792 			*ip = p;
793 			ccount++;
794 			score += score0;
795 			continue;
796 		undo:
797 			while (--undop >= undop1)
798 				if (*undop->pos = x = undop->val)
799 					x->ccount++;
800 			undop++;
801 		}
802 		if (score > 0) {
803 #ifdef STATS
804 			ccount_stat += ccount - p->ccount;
805 			ntoken_stat++;
806 			ncover_stat += ncover;
807 #endif
808 			p->ccount = ccount;
809 		} else {
810 			register struct cc_undo *u = cc_undo;
811 			while (--undop >= u) {
812 				register struct cc *x;
813 				if (*undop->pos = x = undop->val)
814 					x->ccount++;
815 			}
816 		}
817 	} while ((p = *pp++) != 0);
818 	return pp - tokens;
819 }
820 
821 cc_output_phase(buffer, output, bufsize)
822 	register char *buffer;
823 	register struct cc **output;
824 	register bufsize;
825 {
826 	register i;
827 	register struct cc *p, *p1;
828 
829 	for (i = 0; i < bufsize;) {
830 		if ((p = output[i]) == 0) {
831 			ttputc(buffer[i]);
832 			i++;
833 		} else if (p->code >= 0) {
834 			if (--p->ccount == 0)
835 				qinsert(p, &cc_q0a);
836 			(*tt.tt_put_token)(p->code, p->string, p->length);
837 			wwntokuse++;
838 			wwntoksave += put_token_score(p->length);
839 			i += p->length;
840 		} else if ((p1 = cc_q0a.qback) != &cc_q0a) {
841 			p->code = p1->code;
842 			p1->code = -1;
843 			qinsert(p1, &cc_q1a);
844 			if (--p->ccount == 0)
845 				qinsert(p, &cc_q0a);
846 			else
847 				qinsert(p, &cc_q0b);
848 			(*tt.tt_set_token)(p->code, p->string, p->length);
849 			wwntokdef++;
850 			wwntoksave -= tt.tt_set_token_cost;
851 			i += p->length;
852 		} else {
853 			p->ccount--;
854 			ttwrite(p->string, p->length);
855 			wwntokbad++;
856 			i += p->length;
857 		}
858 	}
859 	wwntokc += bufsize;
860 }
861 
862 cc_token_compare(p1, p2)
863 	struct cc **p1, **p2;
864 {
865 	return (*p2)->bcount - (*p1)->bcount;
866 }
867