xref: /dragonfly/sys/kern/tty_subr.c (revision f746689a)
1 /*
2  * Copyright (c) 1994, David Greenman
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice unmodified, this list of conditions, and the following
10  *    disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  * $FreeBSD: src/sys/kern/tty_subr.c,v 1.32 1999/08/28 00:46:21 peter Exp $
28  * $DragonFly: src/sys/kern/tty_subr.c,v 1.10 2006/12/23 00:35:04 swildner Exp $
29  */
30 
31 /*
32  * clist support routines
33  *
34  * NOTE on cblock->c_cf:	This pointer may point at the base of a cblock,
35  *				which is &cblock->c_info[0], but will never
36  *				point at the end of a cblock (char *)(cblk + 1)
37  *
38  * NOTE on cblock->c_cl:	This pointer will never point at the base of
39  *				a block but may point at the end of one.
40  *
41  * These routines may be used by more then just ttys, so a critical section
42  * must be used to access the free list, and for general safety.
43  */
44 
45 #include <sys/param.h>
46 #include <sys/kernel.h>
47 #include <sys/systm.h>
48 #include <sys/malloc.h>
49 #include <sys/tty.h>
50 #include <sys/clist.h>
51 #include <sys/thread2.h>
52 
53 static void clist_init (void *);
54 SYSINIT(clist, SI_SUB_CLIST, SI_ORDER_FIRST, clist_init, NULL)
55 
56 static struct cblock *cfreelist = 0;
57 int cfreecount = 0;
58 static int cslushcount;
59 static int ctotcount;
60 
61 #ifndef INITIAL_CBLOCKS
62 #define	INITIAL_CBLOCKS 50
63 #endif
64 
65 static struct cblock *cblock_alloc (void);
66 static void cblock_alloc_cblocks (int number);
67 static void cblock_free (struct cblock *cblockp);
68 static void cblock_free_cblocks (int number);
69 
70 #include "opt_ddb.h"
71 #ifdef DDB
72 #include <ddb/ddb.h>
73 
74 DB_SHOW_COMMAND(cbstat, cbstat)
75 {
76 	int cbsize = CBSIZE;
77 
78 	kprintf(
79 	"tot = %d (active = %d, free = %d (reserved = %d, slush = %d))\n",
80 	       ctotcount * cbsize, ctotcount * cbsize - cfreecount, cfreecount,
81 	       cfreecount - cslushcount * cbsize, cslushcount * cbsize);
82 }
83 #endif /* DDB */
84 
85 /*
86  * Called from init_main.c
87  */
88 /* ARGSUSED*/
89 static void
90 clist_init(void *dummy)
91 {
92 	/*
93 	 * Allocate an initial base set of cblocks as a 'slush'.
94 	 * We allocate non-slush cblocks with each initial ttyopen() and
95 	 * deallocate them with each ttyclose().
96 	 * We should adjust the slush allocation.  This can't be done in
97 	 * the i/o routines because they are sometimes called from
98 	 * interrupt handlers when it may be unsafe to call kmalloc().
99 	 */
100 	cblock_alloc_cblocks(cslushcount = INITIAL_CBLOCKS);
101 	KKASSERT(sizeof(struct cblock) == CBLOCK);
102 }
103 
104 /*
105  * Remove a cblock from the cfreelist queue and return a pointer
106  * to it.
107  *
108  * May not block.
109  */
110 static struct cblock *
111 cblock_alloc(void)
112 {
113 	struct cblock *cblockp;
114 
115 	cblockp = cfreelist;
116 	if (cblockp == NULL)
117 		panic("clist reservation botch");
118 	KKASSERT(cblockp->c_head.ch_magic == CLIST_MAGIC_FREE);
119 	cfreelist = cblockp->c_head.ch_next;
120 	cblockp->c_head.ch_next = NULL;
121 	cblockp->c_head.ch_magic = CLIST_MAGIC_USED;
122 	cfreecount -= CBSIZE;
123 	return (cblockp);
124 }
125 
126 /*
127  * Add a cblock to the cfreelist queue.
128  *
129  * May not block, must be called in a critical section
130  */
131 static void
132 cblock_free(struct cblock *cblockp)
133 {
134 	if (isset(cblockp->c_quote, CBQSIZE * NBBY - 1))
135 		bzero(cblockp->c_quote, sizeof cblockp->c_quote);
136 	KKASSERT(cblockp->c_head.ch_magic == CLIST_MAGIC_USED);
137 	cblockp->c_head.ch_next = cfreelist;
138 	cblockp->c_head.ch_magic = CLIST_MAGIC_FREE;
139 	cfreelist = cblockp;
140 	cfreecount += CBSIZE;
141 }
142 
143 /*
144  * Allocate some cblocks for the cfreelist queue.
145  *
146  * This routine may block, but still must be called in a critical section
147  */
148 static void
149 cblock_alloc_cblocks(int number)
150 {
151 	int i;
152 	struct cblock *cbp;
153 
154 	for (i = 0; i < number; ++i) {
155 		cbp = kmalloc(sizeof *cbp, M_TTYS, M_NOWAIT);
156 		if (cbp == NULL) {
157 			kprintf(
158 "clist_alloc_cblocks: M_NOWAIT kmalloc failed, trying M_WAITOK\n");
159 			cbp = kmalloc(sizeof *cbp, M_TTYS, M_WAITOK);
160 		}
161 		KKASSERT(((intptr_t)cbp & CROUND) == 0);
162 		/*
163 		 * Freed cblocks have zero quotes and garbage elsewhere.
164 		 * Set the may-have-quote bit to force zeroing the quotes.
165 		 */
166 		setbit(cbp->c_quote, CBQSIZE * NBBY - 1);
167 		cbp->c_head.ch_magic = CLIST_MAGIC_USED;
168 		cblock_free(cbp);
169 	}
170 	ctotcount += number;
171 }
172 
173 /*
174  * Set the cblock allocation policy for a clist.
175  */
176 void
177 clist_alloc_cblocks(struct clist *clistp, int ccmax, int ccreserved)
178 {
179 	int dcbr;
180 
181 	/*
182 	 * Allow for wasted space at the head.
183 	 */
184 	if (ccmax != 0)
185 		ccmax += CBSIZE - 1;
186 	if (ccreserved != 0)
187 		ccreserved += CBSIZE - 1;
188 
189 	crit_enter();
190 	clistp->c_cbmax = roundup(ccmax, CBSIZE) / CBSIZE;
191 	dcbr = roundup(ccreserved, CBSIZE) / CBSIZE - clistp->c_cbreserved;
192 	if (dcbr >= 0) {
193 		clistp->c_cbreserved += dcbr;	/* atomic w/c_cbmax */
194 		cblock_alloc_cblocks(dcbr);	/* may block */
195 	} else {
196 		KKASSERT(clistp->c_cbcount <= clistp->c_cbreserved);
197 		if (clistp->c_cbreserved + dcbr < clistp->c_cbcount)
198 			dcbr = clistp->c_cbcount - clistp->c_cbreserved;
199 		clistp->c_cbreserved += dcbr;	/* atomic w/c_cbmax */
200 		cblock_free_cblocks(-dcbr);	/* may block */
201 	}
202 	KKASSERT(clistp->c_cbreserved >= 0);
203 	crit_exit();
204 }
205 
206 /*
207  * Free some cblocks from the cfreelist queue back to the
208  * system malloc pool.
209  *
210  * Must be called from within a critical section.  May block.
211  */
212 static void
213 cblock_free_cblocks(int number)
214 {
215 	int i;
216 
217 	for (i = 0; i < number; ++i)
218 		kfree(cblock_alloc(), M_TTYS);
219 	ctotcount -= number;
220 }
221 
222 /*
223  * Free the cblocks reserved for a clist.
224  */
225 void
226 clist_free_cblocks(struct clist *clistp)
227 {
228 	int cbreserved;
229 
230 	crit_enter();
231 	if (clistp->c_cbcount != 0)
232 		panic("freeing active clist cblocks");
233 	cbreserved = clistp->c_cbreserved;
234 	clistp->c_cbmax = 0;
235 	clistp->c_cbreserved = 0;
236 	cblock_free_cblocks(cbreserved); /* may block */
237 	crit_exit();
238 }
239 
240 /*
241  * Get a character from the head of a clist.
242  */
243 int
244 clist_getc(struct clist *clistp)
245 {
246 	int chr = -1;
247 	struct cblock *cblockp;
248 
249 	crit_enter();
250 	if (clistp->c_cc) {
251 		KKASSERT(((intptr_t)clistp->c_cf & CROUND) != 0);
252 		cblockp = (struct cblock *)((intptr_t)clistp->c_cf & ~CROUND);
253 		chr = (u_char)*clistp->c_cf;
254 
255 		/*
256 		 * If this char is quoted, set the flag.
257 		 */
258 		if (isset(cblockp->c_quote, clistp->c_cf - (char *)cblockp->c_info))
259 			chr |= TTY_QUOTE;
260 
261 		/*
262 		 * Advance to next character.
263 		 */
264 		clistp->c_cf++;
265 		clistp->c_cc--;
266 		/*
267 		 * If we have advanced the 'first' character pointer
268 		 * past the end of this cblock, advance to the next one.
269 		 * If there are no more characters, set the first and
270 		 * last pointers to NULL. In either case, free the
271 		 * current cblock.
272 		 */
273 		KKASSERT(clistp->c_cf <= (char *)(cblockp + 1));
274 		if ((clistp->c_cf == (char *)(cblockp + 1)) ||
275 		    (clistp->c_cc == 0)) {
276 			if (clistp->c_cc > 0) {
277 				clistp->c_cf = cblockp->c_head.ch_next->c_info;
278 			} else {
279 				clistp->c_cf = clistp->c_cl = NULL;
280 			}
281 			cblock_free(cblockp);
282 			if (--clistp->c_cbcount >= clistp->c_cbreserved)
283 				++cslushcount;
284 		}
285 	}
286 	crit_exit();
287 	return (chr);
288 }
289 
290 /*
291  * Copy 'amount' of chars, beginning at head of clist 'clistp' to
292  * destination linear buffer 'dest'. Return number of characters
293  * actually copied.
294  */
295 int
296 q_to_b(struct clist *clistp, char *dest, int amount)
297 {
298 	struct cblock *cblockp;
299 	struct cblock *cblockn;
300 	char *dest_orig = dest;
301 	int numc;
302 
303 	crit_enter();
304 	while (clistp && amount && (clistp->c_cc > 0)) {
305 		KKASSERT(((intptr_t)clistp->c_cf & CROUND) != 0);
306 		cblockp = (struct cblock *)((intptr_t)clistp->c_cf & ~CROUND);
307 		cblockn = cblockp + 1; /* pointer arithmetic! */
308 		numc = min(amount, (char *)cblockn - clistp->c_cf);
309 		numc = min(numc, clistp->c_cc);
310 		bcopy(clistp->c_cf, dest, numc);
311 		amount -= numc;
312 		clistp->c_cf += numc;
313 		clistp->c_cc -= numc;
314 		dest += numc;
315 		/*
316 		 * If this cblock has been emptied, advance to the next
317 		 * one. If there are no more characters, set the first
318 		 * and last pointer to NULL. In either case, free the
319 		 * current cblock.
320 		 */
321 		KKASSERT(clistp->c_cf <= (char *)cblockn);
322 		if ((clistp->c_cf == (char *)cblockn) || (clistp->c_cc == 0)) {
323 			if (clistp->c_cc > 0) {
324 				KKASSERT(cblockp->c_head.ch_next != NULL);
325 				clistp->c_cf = cblockp->c_head.ch_next->c_info;
326 			} else {
327 				clistp->c_cf = clistp->c_cl = NULL;
328 			}
329 			cblock_free(cblockp);
330 			if (--clistp->c_cbcount >= clistp->c_cbreserved)
331 				++cslushcount;
332 		}
333 	}
334 	crit_exit();
335 	return (dest - dest_orig);
336 }
337 
338 /*
339  * Flush 'amount' of chars, beginning at head of clist 'clistp'.
340  */
341 void
342 ndflush(struct clist *clistp, int amount)
343 {
344 	struct cblock *cblockp;
345 	struct cblock *cblockn;
346 	int numc;
347 
348 	crit_enter();
349 	while (amount && (clistp->c_cc > 0)) {
350 		KKASSERT(((intptr_t)clistp->c_cf & CROUND) != 0);
351 		cblockp = (struct cblock *)((intptr_t)clistp->c_cf & ~CROUND);
352 		cblockn = cblockp + 1; /* pointer arithmetic! */
353 		numc = min(amount, (char *)cblockn - clistp->c_cf);
354 		numc = min(numc, clistp->c_cc);
355 		amount -= numc;
356 		clistp->c_cf += numc;
357 		clistp->c_cc -= numc;
358 		/*
359 		 * If this cblock has been emptied, advance to the next
360 		 * one. If there are no more characters, set the first
361 		 * and last pointer to NULL. In either case, free the
362 		 * current cblock.
363 		 */
364 		KKASSERT(clistp->c_cf <= (char *)cblockn);
365 		if (clistp->c_cf == (char *)cblockn || clistp->c_cc == 0) {
366 			if (clistp->c_cc > 0) {
367 				KKASSERT(cblockp->c_head.ch_next != NULL);
368 				clistp->c_cf = cblockp->c_head.ch_next->c_info;
369 			} else {
370 				clistp->c_cf = clistp->c_cl = NULL;
371 			}
372 			cblock_free(cblockp);
373 			if (--clistp->c_cbcount >= clistp->c_cbreserved)
374 				++cslushcount;
375 		}
376 	}
377 	crit_exit();
378 }
379 
380 /*
381  * Add a character to the end of a clist. Return -1 is no
382  * more clists, or 0 for success.
383  */
384 int
385 clist_putc(int chr, struct clist *clistp)
386 {
387 	struct cblock *cblockp;
388 
389 	crit_enter();
390 
391 	/*
392 	 * Note: this section may point c_cl at the base of a cblock.  This
393 	 * is a temporary violation of the requirements for c_cl, we
394 	 * increment it before returning.
395 	 */
396 	if (clistp->c_cl == NULL) {
397 		if (clistp->c_cbreserved < 1) {
398 			crit_exit();
399 			kprintf("putc to a clist with no reserved cblocks\n");
400 			return (-1);		/* nothing done */
401 		}
402 		cblockp = cblock_alloc();
403 		clistp->c_cbcount = 1;
404 		clistp->c_cf = clistp->c_cl = cblockp->c_info;
405 		clistp->c_cc = 0;
406 	} else {
407 		cblockp = (struct cblock *)((intptr_t)clistp->c_cl & ~CROUND);
408 		if (((intptr_t)clistp->c_cl & CROUND) == 0) {
409 			struct cblock *prev = (cblockp - 1);
410 
411 			if (clistp->c_cbcount >= clistp->c_cbreserved) {
412 				if (clistp->c_cbcount >= clistp->c_cbmax
413 				    || cslushcount <= 0) {
414 					crit_exit();
415 					return (-1);
416 				}
417 				--cslushcount;
418 			}
419 			cblockp = cblock_alloc();
420 			clistp->c_cbcount++;
421 			prev->c_head.ch_next = cblockp;
422 			clistp->c_cl = cblockp->c_info;
423 		}
424 	}
425 
426 	/*
427 	 * If this character is quoted, set the quote bit, if not, clear it.
428 	 */
429 	if (chr & TTY_QUOTE) {
430 		setbit(cblockp->c_quote, clistp->c_cl - (char *)cblockp->c_info);
431 		/*
432 		 * Use one of the spare quote bits to record that something
433 		 * may be quoted.
434 		 */
435 		setbit(cblockp->c_quote, CBQSIZE * NBBY - 1);
436 	} else {
437 		clrbit(cblockp->c_quote, clistp->c_cl - (char *)cblockp->c_info);
438 	}
439 
440 	*clistp->c_cl++ = chr;
441 	clistp->c_cc++;
442 
443 	crit_exit();
444 	return (0);
445 }
446 
447 /*
448  * Copy data from linear buffer to clist chain. Return the
449  * number of characters not copied.
450  */
451 int
452 b_to_q(char *src, int amount, struct clist *clistp)
453 {
454 	struct cblock *cblockp;
455 	char *firstbyte, *lastbyte;
456 	u_char startmask, endmask;
457 	int startbit, endbit, num_between, numc;
458 
459 	/*
460 	 * Avoid allocating an initial cblock and then not using it.
461 	 * c_cc == 0 must imply c_cbount == 0.
462 	 */
463 	if (amount <= 0)
464 		return (amount);
465 
466 	crit_enter();
467 
468 	/*
469 	 * Note: this section may point c_cl at the base of a cblock.  This
470 	 * is a temporary violation of the requirements for c_cl.  Since
471 	 * amount is non-zero we will not return with it in that state.
472 	 */
473 	if (clistp->c_cl == NULL) {
474 		if (clistp->c_cbreserved < 1) {
475 			crit_exit();
476 			kprintf("b_to_q to a clist with no reserved cblocks.\n");
477 			return (amount);	/* nothing done */
478 		}
479 		cblockp = cblock_alloc();
480 		clistp->c_cbcount = 1;
481 		clistp->c_cf = clistp->c_cl = cblockp->c_info;
482 		clistp->c_cc = 0;
483 	} else {
484 		/*
485 		 * c_cl may legally point past the end of the block, which
486 		 * falls through to the 'get another cblock' code below.
487 		 */
488 		cblockp = (struct cblock *)((intptr_t)clistp->c_cl & ~CROUND);
489 	}
490 
491 	while (amount) {
492 		/*
493 		 * Get another cblock if needed.
494 		 */
495 		if (((intptr_t)clistp->c_cl & CROUND) == 0) {
496 			struct cblock *prev = cblockp - 1;
497 
498 			if (clistp->c_cbcount >= clistp->c_cbreserved) {
499 				if (clistp->c_cbcount >= clistp->c_cbmax
500 				    || cslushcount <= 0) {
501 					crit_exit();
502 					return (amount);
503 				}
504 				--cslushcount;
505 			}
506 			cblockp = cblock_alloc();
507 			clistp->c_cbcount++;
508 			prev->c_head.ch_next = cblockp;
509 			clistp->c_cl = cblockp->c_info;
510 		}
511 
512 		/*
513 		 * Copy a chunk of the linear buffer up to the end
514 		 * of this cblock.
515 		 */
516 		numc = min(amount, (char *)(cblockp + 1) - clistp->c_cl);
517 		bcopy(src, clistp->c_cl, numc);
518 
519 		/*
520 		 * Clear quote bits if they aren't known to be clear.
521 		 * The following could probably be made into a separate
522 		 * "bitzero()" routine, but why bother?
523 		 */
524 		if (isset(cblockp->c_quote, CBQSIZE * NBBY - 1)) {
525 			startbit = clistp->c_cl - (char *)cblockp->c_info;
526 			endbit = startbit + numc - 1;
527 
528 			firstbyte = (u_char *)cblockp->c_quote + (startbit / NBBY);
529 			lastbyte = (u_char *)cblockp->c_quote + (endbit / NBBY);
530 
531 			/*
532 			 * Calculate mask of bits to preserve in first and
533 			 * last bytes.
534 			 */
535 			startmask = NBBY - (startbit % NBBY);
536 			startmask = 0xff >> startmask;
537 			endmask = (endbit % NBBY);
538 			endmask = 0xff << (endmask + 1);
539 
540 			if (firstbyte != lastbyte) {
541 				*firstbyte &= startmask;
542 				*lastbyte &= endmask;
543 
544 				num_between = lastbyte - firstbyte - 1;
545 				if (num_between)
546 					bzero(firstbyte + 1, num_between);
547 			} else {
548 				*firstbyte &= (startmask | endmask);
549 			}
550 		}
551 
552 		/*
553 		 * ...and update pointer for the next chunk.
554 		 */
555 		src += numc;
556 		clistp->c_cl += numc;
557 		clistp->c_cc += numc;
558 		amount -= numc;
559 		/*
560 		 * If we go through the loop again, it's always
561 		 * for data in the next cblock, so by adding one (cblock),
562 		 * (which makes the pointer 1 beyond the end of this
563 		 * cblock) we prepare for the assignment of 'prev'
564 		 * above.
565 		 */
566 		++cblockp;
567 	}
568 	crit_exit();
569 	return (amount);
570 }
571 
572 /*
573  * Get the next character in the clist. Store it at dst. Don't
574  * advance any clist pointers, but return a pointer to the next
575  * character position.
576  *
577  * Must be called at spltty().  This routine may not run in a critical
578  * section and so may not call the cblock allocator/deallocator.
579  */
580 char *
581 nextc(struct clist *clistp, char *cp, int *dst)
582 {
583 	struct cblock *cblockp;
584 
585 	++cp;
586 	/*
587 	 * See if the next character is beyond the end of
588 	 * the clist.
589 	 */
590 	if (clistp->c_cc && (cp != clistp->c_cl)) {
591 		/*
592 		 * If the next character is beyond the end of this
593 		 * cblock, advance to the next cblock.
594 		 */
595 		if (((intptr_t)cp & CROUND) == 0)
596 			cp = ((struct cblock *)cp - 1)->c_head.ch_next->c_info;
597 		cblockp = (struct cblock *)((intptr_t)cp & ~CROUND);
598 
599 		/*
600 		 * Get the character. Set the quote flag if this character
601 		 * is quoted.
602 		 */
603 		*dst = (u_char)*cp | (isset(cblockp->c_quote, cp - (char *)cblockp->c_info) ? TTY_QUOTE : 0);
604 
605 		return (cp);
606 	}
607 
608 	return (NULL);
609 }
610 
611 /*
612  * "Unput" a character from a clist.
613  */
614 int
615 clist_unputc(struct clist *clistp)
616 {
617 	struct cblock *cblockp = 0, *cbp = 0;
618 	int chr = -1;
619 
620 	crit_enter();
621 
622 	if (clistp->c_cc) {
623 		/*
624 		 * note that clistp->c_cl will never point at the base
625 		 * of a cblock (cblock->c_info) (see assert this later on),
626 		 * but it may point past the end of one.  We temporarily
627 		 * violate this in the decrement below but then we fix it up.
628 		 */
629 		--clistp->c_cc;
630 		--clistp->c_cl;
631 
632 		chr = (u_char)*clistp->c_cl;
633 
634 		cblockp = (struct cblock *)((intptr_t)clistp->c_cl & ~CROUND);
635 
636 		/*
637 		 * Set quote flag if this character was quoted.
638 		 */
639 		if (isset(cblockp->c_quote, (u_char *)clistp->c_cl - cblockp->c_info))
640 			chr |= TTY_QUOTE;
641 
642 		/*
643 		 * If all of the characters have been unput in this
644 		 * cblock, then find the previous one and free this
645 		 * one.
646 		 *
647 		 * if c_cc is 0 clistp->c_cl may end up pointing at
648 		 * cblockp->c_info, which is illegal, but the case will be
649 		 * taken care of near the end of the routine.  Otherwise
650 		 * there *MUST* be another cblock, find it.
651 		 */
652 		KKASSERT(clistp->c_cl >= (char *)cblockp->c_info);
653 		if (clistp->c_cc && (clistp->c_cl == (char *)cblockp->c_info)) {
654 			cbp = (struct cblock *)((intptr_t)clistp->c_cf & ~CROUND);
655 
656 			while (cbp->c_head.ch_next != cblockp)
657 				cbp = cbp->c_head.ch_next;
658 			cbp->c_head.ch_next = NULL;
659 
660 			/*
661 			 * When the previous cblock is at the end, the 'last'
662 			 * pointer always points (invalidly) one past.
663 			 */
664 			clistp->c_cl = (char *)(cbp + 1);
665 			cblock_free(cblockp);
666 			if (--clistp->c_cbcount >= clistp->c_cbreserved)
667 				++cslushcount;
668 		}
669 	}
670 
671 	/*
672 	 * If there are no more characters on the list, then
673 	 * free the last cblock.   It should not be possible for c->cl
674 	 * to be pointing past the end of a block due to our decrement
675 	 * of it way above.
676 	 */
677 	if (clistp->c_cc == 0 && clistp->c_cl) {
678 		KKASSERT(((intptr_t)clistp->c_cl & CROUND) != 0);
679 		cblockp = (struct cblock *)((intptr_t)clistp->c_cl & ~CROUND);
680 		cblock_free(cblockp);
681 		if (--clistp->c_cbcount >= clistp->c_cbreserved)
682 			++cslushcount;
683 		clistp->c_cf = clistp->c_cl = NULL;
684 	}
685 
686 	crit_exit();
687 	return (chr);
688 }
689 
690 /*
691  * Move characters in source clist to destination clist,
692  * preserving quote bits.
693  */
694 void
695 catq(struct clist *src_clistp, struct clist *dest_clistp)
696 {
697 	int chr;
698 
699 	crit_enter();
700 	/*
701 	 * If the destination clist is empty (has no cblocks atttached),
702 	 * and there are no possible complications with the resource counters,
703 	 * then we simply assign the current clist to the destination.
704 	 */
705 	if (!dest_clistp->c_cf
706 	    && src_clistp->c_cbcount <= src_clistp->c_cbmax
707 	    && src_clistp->c_cbcount <= dest_clistp->c_cbmax) {
708 		dest_clistp->c_cf = src_clistp->c_cf;
709 		dest_clistp->c_cl = src_clistp->c_cl;
710 		src_clistp->c_cf = src_clistp->c_cl = NULL;
711 
712 		dest_clistp->c_cc = src_clistp->c_cc;
713 		src_clistp->c_cc = 0;
714 		dest_clistp->c_cbcount = src_clistp->c_cbcount;
715 		src_clistp->c_cbcount = 0;
716 
717 		crit_exit();
718 		return;
719 	}
720 	crit_exit();
721 
722 	/*
723 	 * XXX  This should probably be optimized to more than one
724 	 * character at a time.
725 	 */
726 	while ((chr = clist_getc(src_clistp)) != -1)
727 		clist_putc(chr, dest_clistp);
728 }
729