/usr/src/lib/libadm/common/ckitem.c
C | 600 lines | 494 code | 65 blank | 41 comment | 154 complexity | 191a50d29c5dda5b1a57cfd725c5210b MD5 | raw file
- /*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
- /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
- /* All Rights Reserved */
- /*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
- /*
- * Copyright 2010 Nexenta Systems, Inc. All rights reserved.
- */
- /*LINTLIBRARY*/
- #include <stdio.h>
- #include <ctype.h>
- #include <limits.h>
- #include "valtools.h"
- #include <sys/types.h>
- #include <stdlib.h>
- #include <strings.h>
- #include "libadm.h"
- static int insert(struct _choice_ *, CKMENU *);
- static char *strtoki(char *, char *);
- static char **match(CKMENU *, char *, int);
- static int getstr(char *, char *, char *, char *, char *);
- static int getnum(char *, int, int *, int *);
- static struct _choice_ *next(struct _choice_ *);
- static char *deferr;
- static char *errmsg;
- static char *defhlp;
- #define PROMPT "Enter selection"
- #define MESG0 "Entry does not match available menu selection. "
- #define MESG1 "the number of the menu item you wish to select, or "
- #define MESG2 "the token which is associated with the menu item,\
- or a partial string which uniquely identifies the \
- token for the menu item. Enter ?? to reprint the menu."
- #define TOOMANY "Too many items selected from menu"
- #define NOTUNIQ "The entered text does not uniquely identify a menu choice."
- #define BADNUM "Bad numeric choice specification"
- static char *
- setmsg(CKMENU *menup, short flag)
- {
- int n;
- char *msg;
- n = (int)(6 + sizeof (MESG2));
- if (flag)
- n += (int)(sizeof (MESG0));
- if (menup->attr & CKUNNUM) {
- msg = calloc((size_t)n, sizeof (char));
- if (flag)
- (void) strcpy(msg, MESG0);
- else
- msg[0] = '\0';
- (void) strcat(msg, "Enter ");
- (void) strcat(msg, MESG2);
- } else {
- msg = calloc(n+sizeof (MESG1), sizeof (char));
- if (flag)
- (void) strcpy(msg, MESG0);
- else
- msg[0] = '\0';
- (void) strcat(msg, "Enter ");
- (void) strcat(msg, MESG1);
- (void) strcat(msg, MESG2);
- }
- return (msg);
- }
- CKMENU *
- allocmenu(char *label, int attr)
- {
- CKMENU *pt;
- if (pt = calloc(1, sizeof (CKMENU))) {
- pt->attr = attr;
- pt->label = label;
- }
- return (pt);
- }
- void
- ckitem_err(CKMENU *menup, char *error)
- {
- deferr = setmsg(menup, 1);
- puterror(stdout, deferr, error);
- free(deferr);
- }
- void
- ckitem_hlp(CKMENU *menup, char *help)
- {
- defhlp = setmsg(menup, 0);
- puthelp(stdout, defhlp, help);
- free(defhlp);
- }
- int
- ckitem(CKMENU *menup, char *item[], short max, char *defstr, char *error,
- char *help, char *prompt)
- {
- int n, i;
- char strval[MAX_INPUT];
- char **list;
- if ((menup->nchoices <= 0) && !menup->invis)
- return (4); /* nothing to choose from */
- if (menup->attr & CKONEFLAG) {
- if (((n = menup->nchoices) <= 1) && menup->invis) {
- for (i = 0; menup->invis[i]; ++i)
- n++;
- }
- if (n <= 1) {
- if (menup->choice)
- item[0] = menup->choice->token;
- else if (menup->invis)
- item[0] = menup->invis[0];
- item[1] = NULL;
- return (0);
- }
- }
- if (max < 1)
- max = menup->nchoices;
- if (!prompt)
- prompt = PROMPT;
- defhlp = setmsg(menup, 0);
- deferr = setmsg(menup, 1);
- reprint:
- printmenu(menup);
- start:
- if (n = getstr(strval, defstr, error, help, prompt)) {
- free(defhlp);
- free(deferr);
- return (n);
- }
- if (strcmp(strval, "??") == 0) {
- goto reprint;
- }
- if ((defstr) && (strcmp(strval, defstr) == 0)) {
- item[0] = defstr;
- item[1] = NULL;
- } else {
- list = match(menup, strval, (int)max);
- if (!list) {
- puterror(stderr, deferr, (errmsg ? errmsg : error));
- goto start;
- }
- for (i = 0; (i < max); i++)
- item[i] = list[i];
- free(list);
- }
- free(defhlp);
- free(deferr);
- return (0);
- }
- static int
- getnum(char *strval, int max, int *begin, int *end)
- {
- int n;
- char *pt;
- *begin = *end = 0;
- pt = strval;
- for (;;) {
- if (*pt == '$') {
- n = max;
- pt++;
- } else {
- n = (int)strtol(pt, &pt, 10);
- if ((n <= 0) || (n > max))
- return (1);
- }
- while (isspace((unsigned char)*pt))
- pt++;
- if (!*begin && (*pt == '-')) {
- *begin = n;
- pt++;
- while (isspace((unsigned char)*pt))
- pt++;
- continue;
- } else if (*pt) {
- return (1); /* wasn't a number, or an invalid one */
- } else if (*begin) {
- *end = n;
- break;
- } else {
- *begin = n;
- break;
- }
- }
- if (!*end)
- *end = *begin;
- return ((*begin <= *end) ? 0 : 1);
- }
- static char **
- match(CKMENU *menup, char *strval, int max)
- {
- struct _choice_ *chp;
- char **choice;
- int begin, end;
- char *pt, *found;
- int i, len, nchoice;
- nchoice = 0;
- choice = calloc((size_t)max, sizeof (char *));
- do {
- if (pt = strpbrk(strval, " \t,")) {
- do {
- *pt++ = '\0';
- } while (strchr(" \t,", *pt));
- }
- if (nchoice >= max) {
- errmsg = TOOMANY;
- return (NULL);
- }
- if (!(menup->attr & CKUNNUM) &&
- isdigit((unsigned char)*strval)) {
- if (getnum(strval, (int)menup->nchoices, &begin,
- &end)) {
- errmsg = BADNUM;
- return (NULL);
- }
- chp = menup->choice;
- for (i = 1; chp; i++) {
- if ((i >= begin) && (i <= end)) {
- if (nchoice >= max) {
- errmsg = TOOMANY;
- return (NULL);
- }
- choice[nchoice++] = chp->token;
- }
- chp = chp->next;
- }
- continue;
- }
- found = NULL;
- chp = menup->choice;
- for (i = 0; chp; i++) {
- len = (int)strlen(strval);
- if (strncmp(chp->token, strval, (size_t)len) == 0) {
- if (chp->token[len] == '\0') {
- found = chp->token;
- break;
- } else if (found) {
- errmsg = NOTUNIQ;
- return (NULL); /* not unique */
- }
- found = chp->token;
- }
- chp = chp->next;
- }
- if (menup->invis) {
- for (i = 0; menup->invis[i]; ++i) {
- len = (int)strlen(strval);
- if (strncmp(menup->invis[i], strval,
- (size_t)len) == 0) {
- #if _3b2
- if (chp->token[len] == '\0') {
- #else
- if (menup->invis[i][len] == '\0') {
- #endif
- found = menup->invis[i];
- break;
- } else if (found) {
- errmsg = NOTUNIQ;
- return (NULL);
- }
- found = menup->invis[i];
- }
- }
- }
- if (found) {
- choice[nchoice++] = found;
- continue;
- }
- errmsg = NULL;
- return (NULL);
- } while (((strval = pt) != NULL) && *pt);
- return (choice);
- }
- int
- setitem(CKMENU *menup, char *choice)
- {
- struct _choice_ *chp;
- int n;
- char *pt;
- if (choice == NULL) {
- /* request to clear memory usage */
- chp = menup->choice;
- while (chp) {
- struct _choice_ *_chp = chp;
- chp = chp->next;
- menup->longest = menup->nchoices = 0;
- (void) free(_chp->token); /* free token and text */
- (void) free(_chp);
- }
- return (1);
- }
- if ((chp = calloc(1, sizeof (struct _choice_))) == NULL)
- return (1);
- if ((pt = strdup(choice)) == NULL) {
- free(chp);
- return (1);
- }
- if (!*pt || isspace((unsigned char)*pt)) {
- free(chp);
- return (2);
- }
- chp->token = strtoki(pt, " \t\n");
- chp->text = strtoki(NULL, "");
- if (chp->text) {
- while (isspace((unsigned char)*chp->text))
- chp->text++;
- }
- n = (int)strlen(chp->token);
- if (n > menup->longest)
- menup->longest = (short)n;
- if (insert(chp, menup))
- menup->nchoices++;
- else
- free(chp); /* duplicate entry */
- return (0);
- }
- int
- setinvis(CKMENU *menup, char *choice)
- {
- int index;
- index = 0;
- if (choice == NULL) {
- if (menup->invis == NULL)
- return (0);
- while (menup->invis[index])
- free(menup->invis[index]);
- free(menup->invis);
- return (0);
- }
- if (menup->invis == NULL)
- menup->invis = calloc(2, sizeof (char *));
- else {
- while (menup->invis[index])
- index++; /* count invisible choices */
- menup->invis = realloc(menup->invis,
- (index+2)* sizeof (char *));
- menup->invis[index+1] = NULL;
- }
- if (!menup->invis)
- return (-1);
- menup->invis[index] = strdup(choice);
- return (0);
- }
- static int
- insert(struct _choice_ *chp, CKMENU *menup)
- {
- struct _choice_ *last, *base;
- int n;
- base = menup->choice;
- last = NULL;
- if (!(menup->attr & CKALPHA)) {
- while (base) {
- if (strcmp(base->token, chp->token) == 0)
- return (0);
- last = base;
- base = base->next;
- }
- if (last)
- last->next = chp;
- else
- menup->choice = chp;
- return (1);
- }
- while (base) {
- if ((n = strcmp(base->token, chp->token)) == 0)
- return (0);
- if (n > 0) {
- /* should come before this one */
- break;
- }
- last = base;
- base = base->next;
- }
- if (last) {
- chp->next = last->next;
- last->next = chp;
- } else {
- chp->next = menup->choice;
- menup->choice = chp;
- }
- return (1);
- }
- void
- printmenu(CKMENU *menup)
- {
- int i;
- struct _choice_ *chp;
- char *pt;
- char format[16];
- int c;
- (void) fputc('\n', stderr);
- if (menup->label) {
- (void) puttext(stderr, menup->label, 0, 0);
- (void) fputc('\n', stderr);
- }
- (void) sprintf(format, "%%-%ds", menup->longest+5);
- (void) next(NULL);
- chp = ((menup->attr & CKALPHA) ? next(menup->choice) : menup->choice);
- for (i = 1; chp; ++i) {
- if (!(menup->attr & CKUNNUM))
- (void) fprintf(stderr, "%3d ", i);
- /* LINTED E_SEC_PRINTF_VAR_FMT */
- (void) fprintf(stderr, format, chp->token);
- if (chp->text) {
- /* there is text associated with the token */
- pt = chp->text;
- while (*pt) {
- (void) fputc(*pt, stderr);
- if (*pt++ == '\n') {
- if (!(menup->attr & CKUNNUM))
- (void) fprintf(stderr,
- "%5s", "");
- /* LINTED E_SEC_PRINTF_VAR_FMT */
- (void) fprintf(stderr, format, "");
- while (isspace((unsigned char)*pt))
- ++pt;
- }
- }
- }
- (void) fputc('\n', stderr);
- chp = ((menup->attr & CKALPHA) ?
- next(menup->choice) : chp->next);
- if (chp && ((i % 10) == 0)) {
- /* page the choices */
- (void) fprintf(stderr,
- "\n... %d more menu choices to follow;",
- menup->nchoices - i);
- (void) fprintf(stderr,
- /* CSTYLED */
- "\n<RETURN> for more choices, <CTRL-D> to stop \
- display:");
- /* ignore other chars */
- while (((c = getc(stdin)) != EOF) && (c != '\n'))
- ;
- (void) fputc('\n', stderr);
- if (c == EOF)
- break; /* stop printing menu */
- }
- }
- }
- static int
- getstr(char *strval, char *defstr, char *error, char *help, char *prompt)
- {
- char input[MAX_INPUT];
- char end[MAX_INPUT];
- *end = '\0';
- if (defstr) {
- (void) snprintf(end, MAX_INPUT, "(default: %s) ", defstr);
- }
- if (ckquit) {
- (void) strlcat(end, "[?,??,q]", MAX_INPUT);
- } else {
- (void) strlcat(end, "[?,??]", MAX_INPUT);
- }
- start:
- (void) fputc('\n', stderr);
- (void) puttext(stderr, prompt, 0, 0);
- (void) fprintf(stderr, " %s: ", end);
- if (getinput(input))
- return (1);
- if (strlen(input) == 0) {
- if (defstr) {
- (void) strcpy(strval, defstr);
- return (0);
- }
- puterror(stderr, deferr, (errmsg ? errmsg : error));
- goto start;
- } else if (strcmp(input, "?") == 0) {
- puthelp(stderr, defhlp, help);
- goto start;
- } else if (ckquit && (strcmp(input, "q") == 0)) {
- /* (void) strcpy(strval, input); */
- return (3);
- }
- (void) strcpy(strval, input);
- return (0);
- }
- static struct _choice_ *
- next(struct _choice_ *chp)
- {
- static char *last;
- static char *first;
- struct _choice_ *found;
- if (!chp) {
- last = NULL;
- return (NULL);
- }
- found = NULL;
- for (first = NULL; chp; chp = chp->next) {
- if (last && strcmp(last, chp->token) >= 0)
- continue; /* lower than the last one we found */
- if (!first || strcmp(first, chp->token) > 0) {
- first = chp->token;
- found = chp;
- }
- }
- last = first;
- return (found);
- }
- static char *
- strtoki(char *string, char *sepset)
- {
- char *p, *q, *r;
- static char *savept;
- /* first or subsequent call */
- p = (string == NULL)? savept: string;
- if (p == NULL) /* return if no tokens remaining */
- return (NULL);
- q = p + strspn(p, sepset); /* skip leading separators */
- if (*q == '\0') /* return if no tokens remaining */
- return (NULL);
- if ((r = strpbrk(q, sepset)) == NULL) /* move past token */
- savept = 0; /* indicate this is last token */
- else {
- *r = '\0';
- savept = ++r;
- }
- return (q);
- }