4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
22 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
23 /* All Rights Reserved */
27 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
28 * Use is subject to license terms.
31 * Copyright 2010 Nexenta Systems, Inc. All rights reserved.
40 #include <sys/types.h>
45 static int insert(struct _choice_
*, CKMENU
*);
46 static char *strtoki(char *, char *);
47 static char **match(CKMENU
*, char *, int);
48 static int getstr(char *, char *, char *, char *, char *);
49 static int getnum(char *, int, int *, int *);
50 static struct _choice_
*next(struct _choice_
*);
56 #define PROMPT "Enter selection"
57 #define MESG0 "Entry does not match available menu selection. "
58 #define MESG1 "the number of the menu item you wish to select, or "
59 #define MESG2 "the token which is associated with the menu item,\
60 or a partial string which uniquely identifies the \
61 token for the menu item. Enter ?? to reprint the menu."
63 #define TOOMANY "Too many items selected from menu"
64 #define NOTUNIQ "The entered text does not uniquely identify a menu choice."
65 #define BADNUM "Bad numeric choice specification"
68 setmsg(CKMENU
*menup
, short flag
)
73 n
= (int)(6 + sizeof (MESG2
));
75 n
+= (int)(sizeof (MESG0
));
77 if (menup
->attr
& CKUNNUM
) {
78 msg
= calloc((size_t)n
, sizeof (char));
80 (void) strcpy(msg
, MESG0
);
83 (void) strcat(msg
, "Enter ");
84 (void) strcat(msg
, MESG2
);
86 msg
= calloc(n
+sizeof (MESG1
), sizeof (char));
88 (void) strcpy(msg
, MESG0
);
91 (void) strcat(msg
, "Enter ");
92 (void) strcat(msg
, MESG1
);
93 (void) strcat(msg
, MESG2
);
99 allocmenu(char *label
, int attr
)
103 if (pt
= calloc(1, sizeof (CKMENU
))) {
111 ckitem_err(CKMENU
*menup
, char *error
)
113 deferr
= setmsg(menup
, 1);
114 puterror(stdout
, deferr
, error
);
119 ckitem_hlp(CKMENU
*menup
, char *help
)
121 defhlp
= setmsg(menup
, 0);
122 puthelp(stdout
, defhlp
, help
);
127 ckitem(CKMENU
*menup
, char *item
[], short max
, char *defstr
, char *error
,
128 char *help
, char *prompt
)
131 char strval
[MAX_INPUT
];
134 if ((menup
->nchoices
<= 0) && !menup
->invis
)
135 return (4); /* nothing to choose from */
137 if (menup
->attr
& CKONEFLAG
) {
138 if (((n
= menup
->nchoices
) <= 1) && menup
->invis
) {
139 for (i
= 0; menup
->invis
[i
]; ++i
)
144 item
[0] = menup
->choice
->token
;
145 else if (menup
->invis
)
146 item
[0] = menup
->invis
[0];
153 max
= menup
->nchoices
;
157 defhlp
= setmsg(menup
, 0);
158 deferr
= setmsg(menup
, 1);
164 if (n
= getstr(strval
, defstr
, error
, help
, prompt
)) {
169 if (strcmp(strval
, "??") == 0) {
172 if ((defstr
) && (strcmp(strval
, defstr
) == 0)) {
176 list
= match(menup
, strval
, (int)max
);
178 puterror(stderr
, deferr
, (errmsg
? errmsg
: error
));
181 for (i
= 0; (i
< max
); i
++)
191 getnum(char *strval
, int max
, int *begin
, int *end
)
203 n
= (int)strtol(pt
, &pt
, 10);
204 if ((n
<= 0) || (n
> max
))
207 while (isspace((unsigned char)*pt
))
210 if (!*begin
&& (*pt
== '-')) {
213 while (isspace((unsigned char)*pt
))
217 return (1); /* wasn't a number, or an invalid one */
228 return ((*begin
<= *end
) ? 0 : 1);
232 match(CKMENU
*menup
, char *strval
, int max
)
234 struct _choice_
*chp
;
241 choice
= calloc((size_t)max
, sizeof (char *));
244 if (pt
= strpbrk(strval
, " \t,")) {
247 } while (strchr(" \t,", *pt
));
250 if (nchoice
>= max
) {
254 if (!(menup
->attr
& CKUNNUM
) &&
255 isdigit((unsigned char)*strval
)) {
256 if (getnum(strval
, (int)menup
->nchoices
, &begin
,
262 for (i
= 1; chp
; i
++) {
263 if ((i
>= begin
) && (i
<= end
)) {
264 if (nchoice
>= max
) {
268 choice
[nchoice
++] = chp
->token
;
277 for (i
= 0; chp
; i
++) {
278 len
= (int)strlen(strval
);
279 if (strncmp(chp
->token
, strval
, (size_t)len
) == 0) {
280 if (chp
->token
[len
] == '\0') {
285 return (NULL
); /* not unique */
293 for (i
= 0; menup
->invis
[i
]; ++i
) {
294 len
= (int)strlen(strval
);
295 if (strncmp(menup
->invis
[i
], strval
,
298 if (chp
->token
[len
] == '\0') {
300 if (menup
->invis
[i
][len
] == '\0') {
302 found
= menup
->invis
[i
];
308 found
= menup
->invis
[i
];
313 choice
[nchoice
++] = found
;
318 } while (((strval
= pt
) != NULL
) && *pt
);
323 setitem(CKMENU
*menup
, char *choice
)
325 struct _choice_
*chp
;
329 if (choice
== NULL
) {
330 /* request to clear memory usage */
333 struct _choice_
*_chp
= chp
;
336 menup
->longest
= menup
->nchoices
= 0;
338 (void) free(_chp
->token
); /* free token and text */
344 if ((chp
= calloc(1, sizeof (struct _choice_
))) == NULL
)
347 if ((pt
= strdup(choice
)) == NULL
) {
351 if (!*pt
|| isspace((unsigned char)*pt
)) {
356 chp
->token
= strtoki(pt
, " \t\n");
357 chp
->text
= strtoki(NULL
, "");
360 while (isspace((unsigned char)*chp
->text
))
363 n
= (int)strlen(chp
->token
);
364 if (n
> menup
->longest
)
365 menup
->longest
= (short)n
;
367 if (insert(chp
, menup
))
370 free(chp
); /* duplicate entry */
375 setinvis(CKMENU
*menup
, char *choice
)
380 if (choice
== NULL
) {
381 if (menup
->invis
== NULL
)
383 while (menup
->invis
[index
])
384 free(menup
->invis
[index
]);
389 if (menup
->invis
== NULL
)
390 menup
->invis
= calloc(2, sizeof (char *));
392 while (menup
->invis
[index
])
393 index
++; /* count invisible choices */
394 menup
->invis
= reallocarray(menup
->invis
, index
+ 2,
396 menup
->invis
[index
+1] = NULL
;
400 menup
->invis
[index
] = strdup(choice
);
405 insert(struct _choice_
*chp
, CKMENU
*menup
)
407 struct _choice_
*last
, *base
;
410 base
= menup
->choice
;
413 if (!(menup
->attr
& CKALPHA
)) {
415 if (strcmp(base
->token
, chp
->token
) == 0)
428 if ((n
= strcmp(base
->token
, chp
->token
)) == 0)
431 /* should come before this one */
438 chp
->next
= last
->next
;
441 chp
->next
= menup
->choice
;
448 printmenu(CKMENU
*menup
)
451 struct _choice_
*chp
;
456 (void) fputc('\n', stderr
);
458 (void) puttext(stderr
, menup
->label
, 0, 0);
459 (void) fputc('\n', stderr
);
461 (void) sprintf(format
, "%%-%ds", menup
->longest
+5);
464 chp
= ((menup
->attr
& CKALPHA
) ? next(menup
->choice
) : menup
->choice
);
465 for (i
= 1; chp
; ++i
) {
466 if (!(menup
->attr
& CKUNNUM
))
467 (void) fprintf(stderr
, "%3d ", i
);
468 /* LINTED E_SEC_PRINTF_VAR_FMT */
469 (void) fprintf(stderr
, format
, chp
->token
);
471 /* there is text associated with the token */
474 (void) fputc(*pt
, stderr
);
476 if (!(menup
->attr
& CKUNNUM
))
477 (void) fprintf(stderr
,
479 /* LINTED E_SEC_PRINTF_VAR_FMT */
480 (void) fprintf(stderr
, format
, "");
481 while (isspace((unsigned char)*pt
))
486 (void) fputc('\n', stderr
);
487 chp
= ((menup
->attr
& CKALPHA
) ?
488 next(menup
->choice
) : chp
->next
);
489 if (chp
&& ((i
% 10) == 0)) {
490 /* page the choices */
491 (void) fprintf(stderr
,
492 "\n... %d more menu choices to follow;",
493 menup
->nchoices
- i
);
494 (void) fprintf(stderr
,
496 "\n<RETURN> for more choices, <CTRL-D> to stop \
498 /* ignore other chars */
499 while (((c
= getc(stdin
)) != EOF
) && (c
!= '\n'))
501 (void) fputc('\n', stderr
);
503 break; /* stop printing menu */
509 getstr(char *strval
, char *defstr
, char *error
, char *help
, char *prompt
)
511 char input
[MAX_INPUT
];
516 (void) snprintf(end
, MAX_INPUT
, "(default: %s) ", defstr
);
519 (void) strlcat(end
, "[?,??,q]", MAX_INPUT
);
521 (void) strlcat(end
, "[?,??]", MAX_INPUT
);
525 (void) fputc('\n', stderr
);
526 (void) puttext(stderr
, prompt
, 0, 0);
527 (void) fprintf(stderr
, " %s: ", end
);
532 if (strlen(input
) == 0) {
534 (void) strcpy(strval
, defstr
);
537 puterror(stderr
, deferr
, (errmsg
? errmsg
: error
));
539 } else if (strcmp(input
, "?") == 0) {
540 puthelp(stderr
, defhlp
, help
);
542 } else if (ckquit
&& (strcmp(input
, "q") == 0)) {
543 /* (void) strcpy(strval, input); */
546 (void) strcpy(strval
, input
);
550 static struct _choice_
*
551 next(struct _choice_
*chp
)
555 struct _choice_
*found
;
563 for (first
= NULL
; chp
; chp
= chp
->next
) {
564 if (last
&& strcmp(last
, chp
->token
) >= 0)
565 continue; /* lower than the last one we found */
567 if (!first
|| strcmp(first
, chp
->token
) > 0) {
577 strtoki(char *string
, char *sepset
)
582 /* first or subsequent call */
583 p
= (string
== NULL
)? savept
: string
;
585 if (p
== NULL
) /* return if no tokens remaining */
588 q
= p
+ strspn(p
, sepset
); /* skip leading separators */
590 if (*q
== '\0') /* return if no tokens remaining */
593 if ((r
= strpbrk(q
, sepset
)) == NULL
) /* move past token */
594 savept
= 0; /* indicate this is last token */