Major namecache work primarily to support NULLFS.
[dragonfly.git] / sys / kern / tty_subr.c
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.9 2006/10/19 18:44:00 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         printf(
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                         printf(
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                         printf("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                         printf("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 }