2 * Copyright (c) 1993, 1994
3 * The Regents of the University of California. All rights reserved.
4 * Copyright (c) 1993, 1994, 1995, 1996
5 * Keith Bostic. All rights reserved.
7 * See the LICENSE file for redistribution information.
13 static const char sccsid
[] = "$Id: vs_split.c,v 10.43 2015/04/05 15:21:55 zy Exp $";
16 #include <sys/types.h>
17 #include <sys/queue.h>
20 #include <bitstring.h>
27 #include "../common/common.h"
30 typedef enum { HORIZ_FOLLOW
, HORIZ_PRECEDE
, VERT_FOLLOW
, VERT_PRECEDE
} jdir_t
;
32 static SCR
*vs_getbg(SCR
*, char *);
33 static void vs_insert(SCR
*sp
, GS
*gp
);
34 static int vs_join(SCR
*, SCR
**, jdir_t
*);
38 * Create a new screen, horizontally.
40 * PUBLIC: int vs_split(SCR *, SCR *, int);
46 int ccl
) /* Colon-command line split. */
51 int issmallscreen
, splitup
;
55 /* Check to see if it's possible. */
56 /* XXX: The IS_ONELINE fix will change this, too. */
59 "222|Screen must be larger than %d lines to split", 4 - 1);
63 /* Wait for any messages in the screen. */
64 vs_resolve(sp
, NULL
, 1);
66 /* Get a new screen map. */
67 CALLOC(sp
, _HMAP(new), SMAP
*, SIZE_HMAP(sp
), sizeof(SMAP
));
68 if (_HMAP(new) == NULL
)
70 _HMAP(new)->lno
= sp
->lno
;
74 /* Split the screen in half. */
80 * Small screens: see vs_refresh.c section 6a. Set a flag so
81 * we know to fix the screen up later.
83 issmallscreen
= IS_SMALL(sp
);
85 /* The columns in the screen don't change. */
90 * Split the screen, and link the screens together. If creating a
91 * screen to edit the colon command line or the cursor is in the top
92 * half of the current screen, the new screen goes under the current
93 * screen. Else, it goes above the current screen.
95 * Recalculate current cursor position based on sp->lno, we're called
96 * with the cursor on the colon command line. Then split the screen
97 * in half and update the shared information.
100 !ccl
&& (vs_sm_cursor(sp
, &smp
) ? 0 : (smp
- HMAP
) + 1) >= half
;
101 if (splitup
) { /* Old is bottom half. */
102 new->rows
= sp
->rows
- half
; /* New. */
103 new->roff
= sp
->roff
;
104 sp
->rows
= half
; /* Old. */
105 sp
->roff
+= new->rows
;
108 * If the parent is the bottom half of the screen, shift
109 * the map down to match on-screen text.
111 memcpy(_HMAP(sp
), _HMAP(sp
) + new->rows
,
112 (sp
->t_maxrows
- new->rows
) * sizeof(SMAP
));
113 } else { /* Old is top half. */
114 new->rows
= half
; /* New. */
115 sp
->rows
-= half
; /* Old. */
116 new->roff
= sp
->roff
+ sp
->rows
;
119 /* Adjust maximum text count. */
120 sp
->t_maxrows
= IS_ONELINE(sp
) ? 1 : sp
->rows
- 1;
121 new->t_maxrows
= IS_ONELINE(new) ? 1 : new->rows
- 1;
124 * Small screens: see vs_refresh.c, section 6a.
126 * The child may have different screen options sizes than the parent,
127 * so use them. Guarantee that text counts aren't larger than the
131 /* Fix the text line count for the parent. */
133 sp
->t_rows
-= new->rows
;
135 /* Fix the parent screen. */
136 if (sp
->t_rows
> sp
->t_maxrows
)
137 sp
->t_rows
= sp
->t_maxrows
;
138 if (sp
->t_minrows
> sp
->t_maxrows
)
139 sp
->t_minrows
= sp
->t_maxrows
;
141 /* Fix the child screen. */
142 new->t_minrows
= new->t_rows
= O_VAL(sp
, O_WINDOW
);
143 if (new->t_rows
> new->t_maxrows
)
144 new->t_rows
= new->t_maxrows
;
145 if (new->t_minrows
> new->t_maxrows
)
146 new->t_minrows
= new->t_maxrows
;
148 sp
->t_minrows
= sp
->t_rows
= IS_ONELINE(sp
) ? 1 : sp
->rows
- 1;
151 * The new screen may be a small screen, even if the parent
152 * was not. Don't complain if O_WINDOW is too large, we're
153 * splitting the screen so the screen is much smaller than
156 new->t_minrows
= new->t_rows
= O_VAL(sp
, O_WINDOW
);
157 if (new->t_rows
> new->rows
- 1)
158 new->t_minrows
= new->t_rows
=
159 IS_ONELINE(new) ? 1 : new->rows
- 1;
162 /* Adjust the ends of the new and old maps. */
163 _TMAP(sp
) = IS_ONELINE(sp
) ?
164 _HMAP(sp
) : _HMAP(sp
) + (sp
->t_rows
- 1);
165 _TMAP(new) = IS_ONELINE(new) ?
166 _HMAP(new) : _HMAP(new) + (new->t_rows
- 1);
168 /* Reset the length of the default scroll. */
169 if ((sp
->defscroll
= sp
->t_maxrows
/ 2) == 0)
171 if ((new->defscroll
= new->t_maxrows
/ 2) == 0)
174 /* Fit the screen into the logical chain. */
175 vs_insert(new, sp
->gp
);
177 /* Tell the display that we're splitting. */
178 (void)gp
->scr_split(sp
, new);
181 * Initialize the screen flags:
183 * If we're in vi mode in one screen, we don't have to reinitialize.
184 * This isn't just a cosmetic fix. The path goes like this:
186 * return into vi(), SC_SSWITCH set
187 * call vs_refresh() with SC_STATUS set
188 * call vs_resolve to display the status message
189 * call vs_refresh() because the SC_SCR_VI bit isn't set
191 * Things go downhill at this point.
193 * Draw the new screen from scratch, and add a status line.
196 SC_SCR_REFORMAT
| SC_STATUS
|
197 F_ISSET(sp
, SC_EX
| SC_VI
| SC_SCR_VI
| SC_SCR_EX
| SC_READONLY
));
203 * Create a new screen, vertically.
205 * PUBLIC: int vs_vsplit(SCR *, SCR *);
208 vs_vsplit(SCR
*sp
, SCR
*new)
215 /* Check to see if it's possible. */
216 if (sp
->cols
/ 2 <= MINIMUM_SCREEN_COLS
) {
218 "288|Screen must be larger than %d columns to split",
219 MINIMUM_SCREEN_COLS
* 2);
223 /* Wait for any messages in the screen. */
224 vs_resolve(sp
, NULL
, 1);
226 /* Get a new screen map. */
227 CALLOC(sp
, _HMAP(new), SMAP
*, SIZE_HMAP(sp
), sizeof(SMAP
));
228 if (_HMAP(new) == NULL
)
230 _HMAP(new)->lno
= sp
->lno
;
231 _HMAP(new)->coff
= 0;
232 _HMAP(new)->soff
= 1;
235 * Split the screen in half; we have to sacrifice a column to delimit
239 * We always split to the right... that makes more sense to me, and
240 * I don't want to play the stupid games that I play when splitting
244 * We reserve a column for the screen, "knowing" that curses needs
245 * one. This should be worked out with the display interface.
248 new->cols
= sp
->cols
- cols
- 1;
250 new->coff
= sp
->coff
+ cols
+ 1;
253 /* Nothing else changes. */
254 new->rows
= sp
->rows
;
255 new->t_rows
= sp
->t_rows
;
256 new->t_maxrows
= sp
->t_maxrows
;
257 new->t_minrows
= sp
->t_minrows
;
258 new->roff
= sp
->roff
;
259 new->defscroll
= sp
->defscroll
;
260 _TMAP(new) = _HMAP(new) + (new->t_rows
- 1);
262 /* Fit the screen into the logical chain. */
263 vs_insert(new, sp
->gp
);
265 /* Tell the display that we're splitting. */
266 (void)gp
->scr_split(sp
, new);
268 /* Redraw the old screen from scratch. */
269 F_SET(sp
, SC_SCR_REFORMAT
| SC_STATUS
);
272 * Initialize the screen flags:
274 * If we're in vi mode in one screen, we don't have to reinitialize.
275 * This isn't just a cosmetic fix. The path goes like this:
277 * return into vi(), SC_SSWITCH set
278 * call vs_refresh() with SC_STATUS set
279 * call vs_resolve to display the status message
280 * call vs_refresh() because the SC_SCR_VI bit isn't set
282 * Things go downhill at this point.
284 * Draw the new screen from scratch, and add a status line.
287 SC_SCR_REFORMAT
| SC_STATUS
|
288 F_ISSET(sp
, SC_EX
| SC_VI
| SC_SCR_VI
| SC_SCR_EX
| SC_READONLY
));
294 * Insert the new screen into the correct place in the logical
298 vs_insert(SCR
*sp
, GS
*gp
)
304 /* Move past all screens with lower row numbers. */
305 TAILQ_FOREACH(tsp
, gp
->dq
, q
)
306 if (tsp
->roff
>= sp
->roff
)
309 * Move past all screens with the same row number and lower
312 for (; tsp
!= NULL
; tsp
= TAILQ_NEXT(tsp
, q
))
313 if (tsp
->roff
!= sp
->roff
|| tsp
->coff
> sp
->coff
)
317 * If we reached the end, this screen goes there. Otherwise,
318 * put it before or after the screen where we stopped.
321 TAILQ_INSERT_TAIL(gp
->dq
, sp
, q
);
322 } else if (tsp
->roff
< sp
->roff
||
323 (tsp
->roff
== sp
->roff
&& tsp
->coff
< sp
->coff
)) {
324 TAILQ_INSERT_AFTER(gp
->dq
, tsp
, sp
, q
);
326 TAILQ_INSERT_BEFORE(tsp
, sp
, q
);
331 * Discard the screen, folding the real-estate into a related screen,
332 * if one exists, and return that screen.
334 * PUBLIC: int vs_discard(SCR *, SCR **);
337 vs_discard(SCR
*sp
, SCR
**spp
)
340 SCR
*tsp
, **lp
, *list
[100];
346 * Save the old screen's cursor information.
349 * If called after file_end(), and the underlying file was a tmp
350 * file, it may have gone away.
352 if (sp
->frp
!= NULL
) {
353 sp
->frp
->lno
= sp
->lno
;
354 sp
->frp
->cno
= sp
->cno
;
355 F_SET(sp
->frp
, FR_CURSORSET
);
358 /* If no other screens to join, we're done. */
360 (void)gp
->scr_discard(sp
, NULL
);
368 * Find a set of screens that cover one of the screen's borders.
369 * Check the vertical axis first, for no particular reason.
372 * It's possible (I think?), to create a screen that shares no full
373 * border with any other set of screens, so we can't discard it. We
374 * just complain at the user until they clean it up.
376 if (vs_join(sp
, list
, &jdir
))
380 * Modify the affected screens. Redraw the modified screen(s) from
381 * scratch, setting a status line. If this is ever a performance
382 * problem we could play games with the map, but I wrote that code
383 * before and it was never clean or easy.
385 * Don't clean up the discarded screen's information. If the screen
386 * isn't exiting, we'll do the work when the user redisplays it.
391 for (lp
= &list
[0]; (tsp
= *lp
) != NULL
; ++lp
) {
393 * Small screens: see vs_refresh.c section 6a. Adjust
394 * text line info, unless it's a small screen.
396 * Reset the length of the default scroll.
398 * Reset the map references.
400 tsp
->rows
+= sp
->rows
;
402 tsp
->t_rows
= tsp
->t_minrows
= tsp
->rows
- 1;
403 tsp
->t_maxrows
= tsp
->rows
- 1;
405 tsp
->defscroll
= tsp
->t_maxrows
/ 2;
407 *(_HMAP(tsp
) + (tsp
->t_rows
- 1)) = *_TMAP(tsp
);
408 _TMAP(tsp
) = _HMAP(tsp
) + (tsp
->t_rows
- 1);
412 tsp
->roff
= sp
->roff
;
413 vs_sm_fill(tsp
, OOBLNO
, P_TOP
);
416 vs_sm_fill(tsp
, OOBLNO
, P_BOTTOM
);
421 F_SET(tsp
, SC_STATUS
);
426 for (lp
= &list
[0]; (tsp
= *lp
) != NULL
; ++lp
) {
427 if (jdir
== VERT_FOLLOW
)
428 tsp
->coff
= sp
->coff
;
429 tsp
->cols
+= sp
->cols
+ 1; /* XXX: DIVIDER */
430 vs_sm_fill(tsp
, OOBLNO
, P_TOP
);
431 F_SET(tsp
, SC_STATUS
);
438 /* Find the closest screen that changed and move to it. */
443 /* Tell the display that we're discarding a screen. */
444 (void)gp
->scr_discard(sp
, list
);
451 * Find a set of screens that covers a screen's border.
454 vs_join(SCR
*sp
, SCR
**listp
, jdir_t
*jdirp
)
463 /* Check preceding vertical. */
464 for (lp
= listp
, tlen
= sp
->rows
,
465 tsp
= TAILQ_FIRST(gp
->dq
);
466 tsp
!= NULL
; tsp
= TAILQ_NEXT(tsp
, q
)) {
469 /* Test if precedes the screen vertically. */
470 if (tsp
->coff
+ tsp
->cols
+ 1 != sp
->coff
)
473 * Test if a subset on the vertical axis. If overlaps the
474 * beginning or end, we can't join on this axis at all.
476 if (tsp
->roff
> sp
->roff
+ sp
->rows
)
478 if (tsp
->roff
< sp
->roff
) {
479 if (tsp
->roff
+ tsp
->rows
>= sp
->roff
)
483 if (tsp
->roff
+ tsp
->rows
> sp
->roff
+ sp
->rows
)
486 if (tlen
< tsp
->rows
)
494 *jdirp
= VERT_PRECEDE
;
498 /* Check following vertical. */
499 for (lp
= listp
, tlen
= sp
->rows
,
500 tsp
= TAILQ_FIRST(gp
->dq
);
501 tsp
!= NULL
; tsp
= TAILQ_NEXT(tsp
, q
)) {
504 /* Test if follows the screen vertically. */
505 if (tsp
->coff
!= sp
->coff
+ sp
->cols
+ 1)
508 * Test if a subset on the vertical axis. If overlaps the
509 * beginning or end, we can't join on this axis at all.
511 if (tsp
->roff
> sp
->roff
+ sp
->rows
)
513 if (tsp
->roff
< sp
->roff
) {
514 if (tsp
->roff
+ tsp
->rows
>= sp
->roff
)
518 if (tsp
->roff
+ tsp
->rows
> sp
->roff
+ sp
->rows
)
521 if (tlen
< tsp
->rows
)
529 *jdirp
= VERT_FOLLOW
;
533 /* Check preceding horizontal. */
534 for (first
= 0, lp
= listp
, tlen
= sp
->cols
,
535 tsp
= TAILQ_FIRST(gp
->dq
);
536 tsp
!= NULL
; tsp
= TAILQ_NEXT(tsp
, q
)) {
539 /* Test if precedes the screen horizontally. */
540 if (tsp
->roff
+ tsp
->rows
!= sp
->roff
)
543 * Test if a subset on the horizontal axis. If overlaps the
544 * beginning or end, we can't join on this axis at all.
546 if (tsp
->coff
> sp
->coff
+ sp
->cols
)
548 if (tsp
->coff
< sp
->coff
) {
549 if (tsp
->coff
+ tsp
->cols
>= sp
->coff
)
553 if (tsp
->coff
+ tsp
->cols
> sp
->coff
+ sp
->cols
)
556 if (tlen
< tsp
->cols
)
559 tlen
-= tsp
->cols
+ first
;
565 *jdirp
= HORIZ_PRECEDE
;
569 /* Check following horizontal. */
570 for (first
= 0, lp
= listp
, tlen
= sp
->cols
,
571 tsp
= TAILQ_FIRST(gp
->dq
);
572 tsp
!= NULL
; tsp
= TAILQ_NEXT(tsp
, q
)) {
575 /* Test if precedes the screen horizontally. */
576 if (tsp
->roff
!= sp
->roff
+ sp
->rows
)
579 * Test if a subset on the horizontal axis. If overlaps the
580 * beginning or end, we can't join on this axis at all.
582 if (tsp
->coff
> sp
->coff
+ sp
->cols
)
584 if (tsp
->coff
< sp
->coff
) {
585 if (tsp
->coff
+ tsp
->cols
>= sp
->coff
)
589 if (tsp
->coff
+ tsp
->cols
> sp
->coff
+ sp
->cols
)
592 if (tlen
< tsp
->cols
)
595 tlen
-= tsp
->cols
+ first
;
601 *jdirp
= HORIZ_FOLLOW
;
609 * Background the current screen, and foreground a new one.
611 * PUBLIC: int vs_fg(SCR *, SCR **, CHAR_T *, int);
614 vs_fg(SCR
*sp
, SCR
**nspp
, CHAR_T
*name
, int newscreen
)
624 INT2CHAR(sp
, name
, STRLEN(name
) + 1, np
, nlen
);
628 /* Get the specified background screen. */
629 nsp
= vs_getbg(sp
, np
);
632 if (vs_swap(sp
, &nsp
, np
))
635 if ((*nspp
= nsp
) == NULL
) {
636 msgq_wstr(sp
, M_ERR
, name
,
638 "223|There are no background screens" :
639 "224|There's no background screen editing a file named %s");
644 /* Remove the new screen from the background queue. */
645 TAILQ_REMOVE(gp
->hq
, nsp
, q
);
647 /* Split the screen; if we fail, hook the screen back in. */
648 if (vs_split(sp
, nsp
, 0)) {
649 TAILQ_INSERT_TAIL(gp
->hq
, nsp
, q
);
653 /* Move the old screen to the background queue. */
654 TAILQ_REMOVE(gp
->dq
, sp
, q
);
655 TAILQ_INSERT_TAIL(gp
->hq
, sp
, q
);
662 * Background the screen, and switch to the next one.
664 * PUBLIC: int vs_bg(SCR *);
674 /* Try and join with another screen. */
675 if (vs_discard(sp
, &nsp
))
679 "225|You may not background your only displayed screen");
683 /* Move the old screen to the background queue. */
684 TAILQ_REMOVE(gp
->dq
, sp
, q
);
685 TAILQ_INSERT_TAIL(gp
->hq
, sp
, q
);
687 /* Toss the screen map. */
691 /* Switch screens. */
693 F_SET(sp
, SC_SSWITCH
);
700 * Swap the current screen with a backgrounded one.
702 * PUBLIC: int vs_swap(SCR *, SCR **, char *);
705 vs_swap(SCR
*sp
, SCR
**nspp
, char *name
)
712 /* Get the specified background screen. */
713 if ((*nspp
= nsp
= vs_getbg(sp
, name
)) == NULL
)
717 * Save the old screen's cursor information.
720 * If called after file_end(), and the underlying file was a tmp
721 * file, it may have gone away.
723 if (sp
->frp
!= NULL
) {
724 sp
->frp
->lno
= sp
->lno
;
725 sp
->frp
->cno
= sp
->cno
;
726 F_SET(sp
->frp
, FR_CURSORSET
);
729 /* Switch screens. */
731 F_SET(sp
, SC_SSWITCH
);
733 /* Initialize terminal information. */
734 VIP(nsp
)->srows
= VIP(sp
)->srows
;
736 /* Initialize screen information. */
737 nsp
->cols
= sp
->cols
;
738 nsp
->rows
= sp
->rows
; /* XXX: Only place in vi that sets rows. */
739 nsp
->roff
= sp
->roff
;
742 * Small screens: see vs_refresh.c, section 6a.
744 * The new screens may have different screen options sizes than the
745 * old one, so use them. Make sure that text counts aren't larger
746 * than the new screen sizes.
749 nsp
->t_minrows
= nsp
->t_rows
= O_VAL(nsp
, O_WINDOW
);
750 if (nsp
->t_rows
> sp
->t_maxrows
)
751 nsp
->t_rows
= nsp
->t_maxrows
;
752 if (nsp
->t_minrows
> sp
->t_maxrows
)
753 nsp
->t_minrows
= nsp
->t_maxrows
;
755 nsp
->t_rows
= nsp
->t_maxrows
= nsp
->t_minrows
= nsp
->rows
- 1;
757 /* Reset the length of the default scroll. */
758 nsp
->defscroll
= nsp
->t_maxrows
/ 2;
760 /* Allocate a new screen map. */
761 CALLOC_RET(nsp
, _HMAP(nsp
), SMAP
*, SIZE_HMAP(nsp
), sizeof(SMAP
));
762 _TMAP(nsp
) = _HMAP(nsp
) + (nsp
->t_rows
- 1);
766 if (vs_sm_fill(nsp
, nsp
->lno
, P_FILL
))
770 * The new screen replaces the old screen in the parent/child list.
771 * We insert the new screen after the old one. If we're exiting,
772 * the exit will delete the old one, if we're foregrounding, the fg
773 * code will move the old one to the background queue.
775 TAILQ_REMOVE(gp
->hq
, nsp
, q
);
776 TAILQ_INSERT_AFTER(gp
->dq
, sp
, nsp
, q
);
779 * Don't change the screen's cursor information other than to
780 * note that the cursor is wrong.
782 F_SET(VIP(nsp
), VIP_CUR_INVALID
);
784 /* Draw the new screen from scratch, and add a status line. */
785 F_SET(nsp
, SC_SCR_REDRAW
| SC_STATUS
);
787 list
[0] = nsp
; list
[1] = NULL
;
788 (void)gp
->scr_discard(sp
, list
);
795 * Change the absolute size of the current screen.
797 * PUBLIC: int vs_resize(SCR *, long, adj_t);
800 vs_resize(SCR
*sp
, long int count
, adj_t adj
)
803 SCR
*g
, *s
, *prev
, *next
, *list
[3] = {NULL
, NULL
, NULL
};
809 * Figure out which screens will grow, which will shrink, and
810 * make sure it's possible.
815 if (sp
->t_maxrows
== count
)
817 if (sp
->t_maxrows
> count
) {
819 count
= sp
->t_maxrows
- count
;
822 count
= count
- sp
->t_maxrows
;
826 /* Find first overlapping screen */
827 for (next
= TAILQ_NEXT(sp
, q
); next
!= NULL
&&
828 (next
->coff
>= sp
->coff
+ sp
->cols
||
829 next
->coff
+ next
->cols
<= sp
->coff
);
830 next
= TAILQ_NEXT(next
, q
));
831 /* See if we can use it */
833 (sp
->coff
!= next
->coff
|| sp
->cols
!= next
->cols
))
835 for (prev
= TAILQ_PREV(sp
, _dqh
, q
); prev
!= NULL
&&
836 (prev
->coff
>= sp
->coff
+ sp
->cols
||
837 prev
->coff
+ prev
->cols
<= sp
->coff
);
838 prev
= TAILQ_PREV(prev
, _dqh
, q
));
840 (sp
->coff
!= prev
->coff
|| sp
->cols
!= prev
->cols
))
844 if (adj
== A_DECREASE
) {
848 if (s
->t_maxrows
< MINIMUM_SCREEN_ROWS
+ count
)
850 if ((g
= prev
) == NULL
) {
851 if ((g
= next
) == NULL
)
858 if ((s
= next
) != NULL
&&
859 s
->t_maxrows
>= MINIMUM_SCREEN_ROWS
+ count
)
864 if ((s
= prev
) == NULL
) {
865 toobig
: msgq(sp
, M_BERR
, adj
== A_DECREASE
?
866 "227|The screen cannot shrink" :
867 "228|The screen cannot grow");
870 if (s
->t_maxrows
< MINIMUM_SCREEN_ROWS
+ count
) {
871 toosmall
: msgq(sp
, M_BERR
,
872 "226|The screen can only shrink to %d rows",
873 MINIMUM_SCREEN_ROWS
);
881 * Fix up the screens; we could optimize the reformatting of the
882 * screen, but this isn't likely to be a common enough operation
883 * to make it worthwhile.
891 if (g
->t_minrows
== g
->t_maxrows
)
892 g
->t_minrows
+= count
;
893 g
->t_maxrows
+= count
;
895 F_SET(g
, SC_SCR_REFORMAT
| SC_STATUS
);
898 s
->t_maxrows
-= count
;
899 if (s
->t_minrows
> s
->t_maxrows
)
900 s
->t_minrows
= s
->t_maxrows
;
902 F_SET(s
, SC_SCR_REFORMAT
| SC_STATUS
);
905 list
[0] = g
; list
[1] = s
;
906 gp
->scr_discard(0, list
);
913 * Get the specified background screen, or, if name is NULL, the first
917 vs_getbg(SCR
*sp
, char *name
)
925 /* If name is NULL, return the first background screen on the list. */
927 return (TAILQ_FIRST(gp
->hq
));
929 /* Search for a full match. */
930 TAILQ_FOREACH(nsp
, gp
->hq
, q
)
931 if (!strcmp(nsp
->frp
->name
, name
))
936 /* Search for a last-component match. */
937 TAILQ_FOREACH(nsp
, gp
->hq
, q
) {
938 if ((p
= strrchr(nsp
->frp
->name
, '/')) == NULL
)
942 if (!strcmp(p
, name
))