Annotation of src/usr.bin/pmdb/clit.c, Revision 1.6
1.6 ! deraadt 1: /* $OpenBSD: clit.c,v 1.5 2003/10/31 08:47:31 otto Exp $ */
1.1 art 2: /*
3: * Copyright (c) 2002 Artur Grabowski <art@openbsd.org>
4: * All rights reserved.
5: *
6: * Redistribution and use in source and binary forms, with or without
7: * modification, are permitted provided that the following conditions
8: * are met:
9: *
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. The name of the author may not be used to endorse or promote products
13: * derived from this software without specific prior written permission.
14: *
15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
16: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
17: * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
18: * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25: */
26:
27: #include <stdlib.h>
28: #include <stdio.h>
29: #include <histedit.h>
30: #include <err.h>
31: #include <string.h>
32:
33: #include "clit.h"
34:
35: extern char *__progname;
36:
37: char *prompt_add;
38:
39: static char *
40: prompt(EditLine *el)
41: {
42: static char p[64];
43:
44: snprintf(p, sizeof(p), "%s%s> ", __progname,
45: prompt_add ? prompt_add : "");
46:
47: return p;
48: }
49:
50: /*
51: * Returns number of commands that (at least partially) match "name".
52: */
53: static int
54: name_to_cmd(const char *name, struct clit *cmds, int ncmds, struct clit **res)
55: {
56: int i, len, ret;
57:
58: len = strlen(name);
59: ret = 0;
60:
61: for (i = 0; i < ncmds; i++) {
62: if (strncmp(cmds[i].cmd, name, len) == 0) {
63: *res = &cmds[i];
64: ret++;
65: }
66: }
67:
68: return ret;
69: }
70:
71: struct clitenv {
72: struct clit *cmds;
73: int ncmds;
74: EditLine *el;
75: History *hist;
76: };
77:
78: int
79: cmd_help(int argc, char **argv, void *arg)
80: {
81: struct clitenv *env = arg;
82: struct clit *cmds = env->cmds, *cmdp;
83: int ncmds = env->ncmds;
84: int i, res;
85:
86: if (argc > 1) {
87: res = name_to_cmd(argv[1], cmds, ncmds, &cmdp);
88: if (res == 1) {
89: printf("%s\t%s\n", cmdp->cmd, cmdp->help);
90: } else {
91: fprintf(stderr, "%s command: %s\n",
92: res == 0 ? "unknown" : "ambiguous", argv[1]);
93: }
94:
95: return 0;
96: }
97: for (i = 0; i < ncmds; i++) {
98: cmdp = &cmds[i];
99:
100: printf("%s\t%s\n", cmdp->cmd, cmdp->help);
101: }
102:
103: return 0;
104: }
105:
106: /*
107: * XXX - there is no way to push external args into this function.
108: */
109: unsigned char
110: complt(EditLine *el, int ch)
111: {
112: const LineInfo *line;
113: char str[1024];
114: int len, ret;
115:
116: line = el_line(el);
117: if (line->cursor != line->lastchar)
118: return CC_ERROR;
119:
120: len = line->lastchar - line->buffer;
121:
122: if (len >= 1023)
123: return CC_ERROR;
124:
125: memcpy(str, line->buffer, len);
126: str[len] = '\0';
127:
128: ret = cmd_complt(str, sizeof(str));
129:
130: el_push(el, &str[len]);
131:
132: return ret ? CC_ERROR : CC_REDISPLAY;
133: }
134:
135: void *
136: cmdinit(struct clit *cmds, int ncmds)
137: {
138: struct clitenv *env;
139: HistEvent ev;
140:
141: if ((env = malloc(sizeof(*env))) == NULL)
142: err(1, "Can't init cmd interpreter.");
143:
144: env->cmds = cmds;
145: env->ncmds = ncmds;
146:
147: env->hist = history_init();
148: history(env->hist, &ev, H_SETSIZE, 100);
149:
150: env->el = el_init(__progname, stdin, stdout, stderr);
1.5 otto 151:
1.1 art 152: el_set(env->el, EL_EDITOR, "emacs");
153: el_set(env->el, EL_PROMPT, prompt);
154: el_set(env->el, EL_HIST, history, env->hist);
155: el_set(env->el, EL_ADDFN, "complt", "complete", complt);
156: el_set(env->el, EL_BIND, "\t", "complt");
157: el_source(env->el, NULL);
158:
159: /* XXX - EL_SIGNAL ? */
160:
161: return env;
162: }
163:
164: void
165: cmdend(void *arg)
166: {
167: struct clitenv *env = arg;
168:
169: el_end(env->el);
170: history_end(env->hist);
171:
172: free(env);
173: }
174:
175: int
176: cmdloop(void *arg)
177: {
178: struct clitenv *env = arg;
179: EditLine *el = env->el;
180: History *hist = env->hist;
181: const char *elline;
182: int cnt;
183: char **argv;
184: int maxargs = 16; /* XXX */
185: int stop;
186:
187: stop = 0;
188:
1.6 ! deraadt 189: if ((argv = calloc(sizeof(char *), maxargs)) == NULL)
1.1 art 190: err(1, "malloc");
191:
192: while (!stop && (elline = el_gets(el, &cnt)) != NULL) {
193: char *line, *orgline;
194: struct clit *cmdp;
195: char **ap;
196: int argc, res;
197: HistEvent ev;
198:
1.4 aaron 199: memset(argv, 0, sizeof(char *) * maxargs);
1.1 art 200:
201: history(hist, &ev, H_ENTER, elline);
202:
203: orgline = line = strdup(elline);
1.3 deraadt 204: if (line == NULL)
205: err(1, "strdup");
1.1 art 206:
207: argc = 0;
208: for (ap = argv; (*ap = strsep(&line, " \t\n")) != NULL;) {
209: if (**ap != '\0') {
210: ++ap;
211: if (++argc == maxargs)
212: break;
213: }
214: }
215: if (argc == maxargs) {
216: fprintf(stderr, "Too many arguments\n");
217: goto cmdout;
218: }
219: if (!argc)
220: goto cmdout;
221:
222: /*
223: * Editline commands.
224: */
1.5 otto 225: if (el_parse(el, argc, (const char **)argv) != -1)
1.1 art 226: goto cmdout;
227:
228: if ((res = name_to_cmd(argv[0], env->cmds, env->ncmds,
229: &cmdp)) == 1) {
230: if (argc - 1 > cmdp->maxargc)
231: fprintf(stderr, "Too many arguments\n");
232: else if (argc - 1 < cmdp->minargc)
233: fprintf(stderr, "Too few arguments\n");
234: else
235: stop = (*cmdp->handler)(argc, argv,
236: cmdp->arg ? cmdp->arg : env);
237: } else {
238: fprintf(stderr, "%s command: %s\n",
239: res == 0 ? "unknown" : "ambiguous", argv[0]);
240: }
241: cmdout:
242: free(orgline);
243: }
244: free(argv);
245:
246: return stop;
247: }
248: