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