PageRenderTime 44ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/usr/src/lib/libadm/common/ckitem.c

https://github.com/richlowe/illumos-gate
C | 600 lines | 494 code | 65 blank | 41 comment | 154 complexity | 191a50d29c5dda5b1a57cfd725c5210b MD5 | raw file
  1. /*
  2. * CDDL HEADER START
  3. *
  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
  7. * with the License.
  8. *
  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.
  13. *
  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]
  19. *
  20. * CDDL HEADER END
  21. */
  22. /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
  23. /* All Rights Reserved */
  24. /*
  25. * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
  26. * Use is subject to license terms.
  27. */
  28. /*
  29. * Copyright 2010 Nexenta Systems, Inc. All rights reserved.
  30. */
  31. /*LINTLIBRARY*/
  32. #include <stdio.h>
  33. #include <ctype.h>
  34. #include <limits.h>
  35. #include "valtools.h"
  36. #include <sys/types.h>
  37. #include <stdlib.h>
  38. #include <strings.h>
  39. #include "libadm.h"
  40. static int insert(struct _choice_ *, CKMENU *);
  41. static char *strtoki(char *, char *);
  42. static char **match(CKMENU *, char *, int);
  43. static int getstr(char *, char *, char *, char *, char *);
  44. static int getnum(char *, int, int *, int *);
  45. static struct _choice_ *next(struct _choice_ *);
  46. static char *deferr;
  47. static char *errmsg;
  48. static char *defhlp;
  49. #define PROMPT "Enter selection"
  50. #define MESG0 "Entry does not match available menu selection. "
  51. #define MESG1 "the number of the menu item you wish to select, or "
  52. #define MESG2 "the token which is associated with the menu item,\
  53. or a partial string which uniquely identifies the \
  54. token for the menu item. Enter ?? to reprint the menu."
  55. #define TOOMANY "Too many items selected from menu"
  56. #define NOTUNIQ "The entered text does not uniquely identify a menu choice."
  57. #define BADNUM "Bad numeric choice specification"
  58. static char *
  59. setmsg(CKMENU *menup, short flag)
  60. {
  61. int n;
  62. char *msg;
  63. n = (int)(6 + sizeof (MESG2));
  64. if (flag)
  65. n += (int)(sizeof (MESG0));
  66. if (menup->attr & CKUNNUM) {
  67. msg = calloc((size_t)n, sizeof (char));
  68. if (flag)
  69. (void) strcpy(msg, MESG0);
  70. else
  71. msg[0] = '\0';
  72. (void) strcat(msg, "Enter ");
  73. (void) strcat(msg, MESG2);
  74. } else {
  75. msg = calloc(n+sizeof (MESG1), sizeof (char));
  76. if (flag)
  77. (void) strcpy(msg, MESG0);
  78. else
  79. msg[0] = '\0';
  80. (void) strcat(msg, "Enter ");
  81. (void) strcat(msg, MESG1);
  82. (void) strcat(msg, MESG2);
  83. }
  84. return (msg);
  85. }
  86. CKMENU *
  87. allocmenu(char *label, int attr)
  88. {
  89. CKMENU *pt;
  90. if (pt = calloc(1, sizeof (CKMENU))) {
  91. pt->attr = attr;
  92. pt->label = label;
  93. }
  94. return (pt);
  95. }
  96. void
  97. ckitem_err(CKMENU *menup, char *error)
  98. {
  99. deferr = setmsg(menup, 1);
  100. puterror(stdout, deferr, error);
  101. free(deferr);
  102. }
  103. void
  104. ckitem_hlp(CKMENU *menup, char *help)
  105. {
  106. defhlp = setmsg(menup, 0);
  107. puthelp(stdout, defhlp, help);
  108. free(defhlp);
  109. }
  110. int
  111. ckitem(CKMENU *menup, char *item[], short max, char *defstr, char *error,
  112. char *help, char *prompt)
  113. {
  114. int n, i;
  115. char strval[MAX_INPUT];
  116. char **list;
  117. if ((menup->nchoices <= 0) && !menup->invis)
  118. return (4); /* nothing to choose from */
  119. if (menup->attr & CKONEFLAG) {
  120. if (((n = menup->nchoices) <= 1) && menup->invis) {
  121. for (i = 0; menup->invis[i]; ++i)
  122. n++;
  123. }
  124. if (n <= 1) {
  125. if (menup->choice)
  126. item[0] = menup->choice->token;
  127. else if (menup->invis)
  128. item[0] = menup->invis[0];
  129. item[1] = NULL;
  130. return (0);
  131. }
  132. }
  133. if (max < 1)
  134. max = menup->nchoices;
  135. if (!prompt)
  136. prompt = PROMPT;
  137. defhlp = setmsg(menup, 0);
  138. deferr = setmsg(menup, 1);
  139. reprint:
  140. printmenu(menup);
  141. start:
  142. if (n = getstr(strval, defstr, error, help, prompt)) {
  143. free(defhlp);
  144. free(deferr);
  145. return (n);
  146. }
  147. if (strcmp(strval, "??") == 0) {
  148. goto reprint;
  149. }
  150. if ((defstr) && (strcmp(strval, defstr) == 0)) {
  151. item[0] = defstr;
  152. item[1] = NULL;
  153. } else {
  154. list = match(menup, strval, (int)max);
  155. if (!list) {
  156. puterror(stderr, deferr, (errmsg ? errmsg : error));
  157. goto start;
  158. }
  159. for (i = 0; (i < max); i++)
  160. item[i] = list[i];
  161. free(list);
  162. }
  163. free(defhlp);
  164. free(deferr);
  165. return (0);
  166. }
  167. static int
  168. getnum(char *strval, int max, int *begin, int *end)
  169. {
  170. int n;
  171. char *pt;
  172. *begin = *end = 0;
  173. pt = strval;
  174. for (;;) {
  175. if (*pt == '$') {
  176. n = max;
  177. pt++;
  178. } else {
  179. n = (int)strtol(pt, &pt, 10);
  180. if ((n <= 0) || (n > max))
  181. return (1);
  182. }
  183. while (isspace((unsigned char)*pt))
  184. pt++;
  185. if (!*begin && (*pt == '-')) {
  186. *begin = n;
  187. pt++;
  188. while (isspace((unsigned char)*pt))
  189. pt++;
  190. continue;
  191. } else if (*pt) {
  192. return (1); /* wasn't a number, or an invalid one */
  193. } else if (*begin) {
  194. *end = n;
  195. break;
  196. } else {
  197. *begin = n;
  198. break;
  199. }
  200. }
  201. if (!*end)
  202. *end = *begin;
  203. return ((*begin <= *end) ? 0 : 1);
  204. }
  205. static char **
  206. match(CKMENU *menup, char *strval, int max)
  207. {
  208. struct _choice_ *chp;
  209. char **choice;
  210. int begin, end;
  211. char *pt, *found;
  212. int i, len, nchoice;
  213. nchoice = 0;
  214. choice = calloc((size_t)max, sizeof (char *));
  215. do {
  216. if (pt = strpbrk(strval, " \t,")) {
  217. do {
  218. *pt++ = '\0';
  219. } while (strchr(" \t,", *pt));
  220. }
  221. if (nchoice >= max) {
  222. errmsg = TOOMANY;
  223. return (NULL);
  224. }
  225. if (!(menup->attr & CKUNNUM) &&
  226. isdigit((unsigned char)*strval)) {
  227. if (getnum(strval, (int)menup->nchoices, &begin,
  228. &end)) {
  229. errmsg = BADNUM;
  230. return (NULL);
  231. }
  232. chp = menup->choice;
  233. for (i = 1; chp; i++) {
  234. if ((i >= begin) && (i <= end)) {
  235. if (nchoice >= max) {
  236. errmsg = TOOMANY;
  237. return (NULL);
  238. }
  239. choice[nchoice++] = chp->token;
  240. }
  241. chp = chp->next;
  242. }
  243. continue;
  244. }
  245. found = NULL;
  246. chp = menup->choice;
  247. for (i = 0; chp; i++) {
  248. len = (int)strlen(strval);
  249. if (strncmp(chp->token, strval, (size_t)len) == 0) {
  250. if (chp->token[len] == '\0') {
  251. found = chp->token;
  252. break;
  253. } else if (found) {
  254. errmsg = NOTUNIQ;
  255. return (NULL); /* not unique */
  256. }
  257. found = chp->token;
  258. }
  259. chp = chp->next;
  260. }
  261. if (menup->invis) {
  262. for (i = 0; menup->invis[i]; ++i) {
  263. len = (int)strlen(strval);
  264. if (strncmp(menup->invis[i], strval,
  265. (size_t)len) == 0) {
  266. #if _3b2
  267. if (chp->token[len] == '\0') {
  268. #else
  269. if (menup->invis[i][len] == '\0') {
  270. #endif
  271. found = menup->invis[i];
  272. break;
  273. } else if (found) {
  274. errmsg = NOTUNIQ;
  275. return (NULL);
  276. }
  277. found = menup->invis[i];
  278. }
  279. }
  280. }
  281. if (found) {
  282. choice[nchoice++] = found;
  283. continue;
  284. }
  285. errmsg = NULL;
  286. return (NULL);
  287. } while (((strval = pt) != NULL) && *pt);
  288. return (choice);
  289. }
  290. int
  291. setitem(CKMENU *menup, char *choice)
  292. {
  293. struct _choice_ *chp;
  294. int n;
  295. char *pt;
  296. if (choice == NULL) {
  297. /* request to clear memory usage */
  298. chp = menup->choice;
  299. while (chp) {
  300. struct _choice_ *_chp = chp;
  301. chp = chp->next;
  302. menup->longest = menup->nchoices = 0;
  303. (void) free(_chp->token); /* free token and text */
  304. (void) free(_chp);
  305. }
  306. return (1);
  307. }
  308. if ((chp = calloc(1, sizeof (struct _choice_))) == NULL)
  309. return (1);
  310. if ((pt = strdup(choice)) == NULL) {
  311. free(chp);
  312. return (1);
  313. }
  314. if (!*pt || isspace((unsigned char)*pt)) {
  315. free(chp);
  316. return (2);
  317. }
  318. chp->token = strtoki(pt, " \t\n");
  319. chp->text = strtoki(NULL, "");
  320. if (chp->text) {
  321. while (isspace((unsigned char)*chp->text))
  322. chp->text++;
  323. }
  324. n = (int)strlen(chp->token);
  325. if (n > menup->longest)
  326. menup->longest = (short)n;
  327. if (insert(chp, menup))
  328. menup->nchoices++;
  329. else
  330. free(chp); /* duplicate entry */
  331. return (0);
  332. }
  333. int
  334. setinvis(CKMENU *menup, char *choice)
  335. {
  336. int index;
  337. index = 0;
  338. if (choice == NULL) {
  339. if (menup->invis == NULL)
  340. return (0);
  341. while (menup->invis[index])
  342. free(menup->invis[index]);
  343. free(menup->invis);
  344. return (0);
  345. }
  346. if (menup->invis == NULL)
  347. menup->invis = calloc(2, sizeof (char *));
  348. else {
  349. while (menup->invis[index])
  350. index++; /* count invisible choices */
  351. menup->invis = realloc(menup->invis,
  352. (index+2)* sizeof (char *));
  353. menup->invis[index+1] = NULL;
  354. }
  355. if (!menup->invis)
  356. return (-1);
  357. menup->invis[index] = strdup(choice);
  358. return (0);
  359. }
  360. static int
  361. insert(struct _choice_ *chp, CKMENU *menup)
  362. {
  363. struct _choice_ *last, *base;
  364. int n;
  365. base = menup->choice;
  366. last = NULL;
  367. if (!(menup->attr & CKALPHA)) {
  368. while (base) {
  369. if (strcmp(base->token, chp->token) == 0)
  370. return (0);
  371. last = base;
  372. base = base->next;
  373. }
  374. if (last)
  375. last->next = chp;
  376. else
  377. menup->choice = chp;
  378. return (1);
  379. }
  380. while (base) {
  381. if ((n = strcmp(base->token, chp->token)) == 0)
  382. return (0);
  383. if (n > 0) {
  384. /* should come before this one */
  385. break;
  386. }
  387. last = base;
  388. base = base->next;
  389. }
  390. if (last) {
  391. chp->next = last->next;
  392. last->next = chp;
  393. } else {
  394. chp->next = menup->choice;
  395. menup->choice = chp;
  396. }
  397. return (1);
  398. }
  399. void
  400. printmenu(CKMENU *menup)
  401. {
  402. int i;
  403. struct _choice_ *chp;
  404. char *pt;
  405. char format[16];
  406. int c;
  407. (void) fputc('\n', stderr);
  408. if (menup->label) {
  409. (void) puttext(stderr, menup->label, 0, 0);
  410. (void) fputc('\n', stderr);
  411. }
  412. (void) sprintf(format, "%%-%ds", menup->longest+5);
  413. (void) next(NULL);
  414. chp = ((menup->attr & CKALPHA) ? next(menup->choice) : menup->choice);
  415. for (i = 1; chp; ++i) {
  416. if (!(menup->attr & CKUNNUM))
  417. (void) fprintf(stderr, "%3d ", i);
  418. /* LINTED E_SEC_PRINTF_VAR_FMT */
  419. (void) fprintf(stderr, format, chp->token);
  420. if (chp->text) {
  421. /* there is text associated with the token */
  422. pt = chp->text;
  423. while (*pt) {
  424. (void) fputc(*pt, stderr);
  425. if (*pt++ == '\n') {
  426. if (!(menup->attr & CKUNNUM))
  427. (void) fprintf(stderr,
  428. "%5s", "");
  429. /* LINTED E_SEC_PRINTF_VAR_FMT */
  430. (void) fprintf(stderr, format, "");
  431. while (isspace((unsigned char)*pt))
  432. ++pt;
  433. }
  434. }
  435. }
  436. (void) fputc('\n', stderr);
  437. chp = ((menup->attr & CKALPHA) ?
  438. next(menup->choice) : chp->next);
  439. if (chp && ((i % 10) == 0)) {
  440. /* page the choices */
  441. (void) fprintf(stderr,
  442. "\n... %d more menu choices to follow;",
  443. menup->nchoices - i);
  444. (void) fprintf(stderr,
  445. /* CSTYLED */
  446. "\n<RETURN> for more choices, <CTRL-D> to stop \
  447. display:");
  448. /* ignore other chars */
  449. while (((c = getc(stdin)) != EOF) && (c != '\n'))
  450. ;
  451. (void) fputc('\n', stderr);
  452. if (c == EOF)
  453. break; /* stop printing menu */
  454. }
  455. }
  456. }
  457. static int
  458. getstr(char *strval, char *defstr, char *error, char *help, char *prompt)
  459. {
  460. char input[MAX_INPUT];
  461. char end[MAX_INPUT];
  462. *end = '\0';
  463. if (defstr) {
  464. (void) snprintf(end, MAX_INPUT, "(default: %s) ", defstr);
  465. }
  466. if (ckquit) {
  467. (void) strlcat(end, "[?,??,q]", MAX_INPUT);
  468. } else {
  469. (void) strlcat(end, "[?,??]", MAX_INPUT);
  470. }
  471. start:
  472. (void) fputc('\n', stderr);
  473. (void) puttext(stderr, prompt, 0, 0);
  474. (void) fprintf(stderr, " %s: ", end);
  475. if (getinput(input))
  476. return (1);
  477. if (strlen(input) == 0) {
  478. if (defstr) {
  479. (void) strcpy(strval, defstr);
  480. return (0);
  481. }
  482. puterror(stderr, deferr, (errmsg ? errmsg : error));
  483. goto start;
  484. } else if (strcmp(input, "?") == 0) {
  485. puthelp(stderr, defhlp, help);
  486. goto start;
  487. } else if (ckquit && (strcmp(input, "q") == 0)) {
  488. /* (void) strcpy(strval, input); */
  489. return (3);
  490. }
  491. (void) strcpy(strval, input);
  492. return (0);
  493. }
  494. static struct _choice_ *
  495. next(struct _choice_ *chp)
  496. {
  497. static char *last;
  498. static char *first;
  499. struct _choice_ *found;
  500. if (!chp) {
  501. last = NULL;
  502. return (NULL);
  503. }
  504. found = NULL;
  505. for (first = NULL; chp; chp = chp->next) {
  506. if (last && strcmp(last, chp->token) >= 0)
  507. continue; /* lower than the last one we found */
  508. if (!first || strcmp(first, chp->token) > 0) {
  509. first = chp->token;
  510. found = chp;
  511. }
  512. }
  513. last = first;
  514. return (found);
  515. }
  516. static char *
  517. strtoki(char *string, char *sepset)
  518. {
  519. char *p, *q, *r;
  520. static char *savept;
  521. /* first or subsequent call */
  522. p = (string == NULL)? savept: string;
  523. if (p == NULL) /* return if no tokens remaining */
  524. return (NULL);
  525. q = p + strspn(p, sepset); /* skip leading separators */
  526. if (*q == '\0') /* return if no tokens remaining */
  527. return (NULL);
  528. if ((r = strpbrk(q, sepset)) == NULL) /* move past token */
  529. savept = 0; /* indicate this is last token */
  530. else {
  531. *r = '\0';
  532. savept = ++r;
  533. }
  534. return (q);
  535. }