Annotation of src/usr.bin/pmdb/clit.c, Revision 1.4
1.4 ! aaron 1: /* $OpenBSD: clit.c,v 1.3 2002/07/12 00:24:53 deraadt 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: #ifdef __NetBSD__
140: HistEvent ev;
141: #endif
142:
143: if ((env = malloc(sizeof(*env))) == NULL)
144: err(1, "Can't init cmd interpreter.");
145:
146: env->cmds = cmds;
147: env->ncmds = ncmds;
148:
149: env->hist = history_init();
150: #ifdef __NetBSD__
151: history(env->hist, &ev, H_SETSIZE, 100);
152: #else
153: history(env->hist, H_EVENT, 100);
154: #endif
155:
156: #ifdef __NetBSD__
157: env->el = el_init(__progname, stdin, stdout, stderr);
158: #else
159: env->el = el_init(__progname, stdin, stdout);
160: #endif
161: el_set(env->el, EL_EDITOR, "emacs");
162: el_set(env->el, EL_PROMPT, prompt);
163: el_set(env->el, EL_HIST, history, env->hist);
164: el_set(env->el, EL_ADDFN, "complt", "complete", complt);
165: el_set(env->el, EL_BIND, "\t", "complt");
166: el_source(env->el, NULL);
167:
168: /* XXX - EL_SIGNAL ? */
169:
170: return env;
171: }
172:
173: void
174: cmdend(void *arg)
175: {
176: struct clitenv *env = arg;
177:
178: el_end(env->el);
179: history_end(env->hist);
180:
181: free(env);
182: }
183:
184: int
185: cmdloop(void *arg)
186: {
187: struct clitenv *env = arg;
188: EditLine *el = env->el;
189: History *hist = env->hist;
190: const char *elline;
191: int cnt;
192: char **argv;
193: int maxargs = 16; /* XXX */
194: int stop;
195:
196: stop = 0;
197:
198: if ((argv = malloc(sizeof(char *) * maxargs)) == NULL)
199: err(1, "malloc");
200:
201: while (!stop && (elline = el_gets(el, &cnt)) != NULL) {
202: char *line, *orgline;
203: struct clit *cmdp;
204: char **ap;
205: int argc, res;
206: #ifdef __NetBSD__
207: HistEvent ev;
208: #endif
209:
1.4 ! aaron 210: memset(argv, 0, sizeof(char *) * maxargs);
1.1 art 211:
212: #ifdef __NetBSD__
213: history(hist, &ev, H_ENTER, elline);
214: #else
215: history(hist, H_ENTER, elline);
216: #endif
217:
218: orgline = line = strdup(elline);
1.3 deraadt 219: if (line == NULL)
220: err(1, "strdup");
1.1 art 221:
222: argc = 0;
223: for (ap = argv; (*ap = strsep(&line, " \t\n")) != NULL;) {
224: if (**ap != '\0') {
225: ++ap;
226: if (++argc == maxargs)
227: break;
228: }
229: }
230: if (argc == maxargs) {
231: fprintf(stderr, "Too many arguments\n");
232: goto cmdout;
233: }
234: if (!argc)
235: goto cmdout;
236:
237: /*
238: * Editline commands.
239: */
240: if (el_parse(el, argc, argv) != -1)
241: goto cmdout;
242:
243: if ((res = name_to_cmd(argv[0], env->cmds, env->ncmds,
244: &cmdp)) == 1) {
245: if (argc - 1 > cmdp->maxargc)
246: fprintf(stderr, "Too many arguments\n");
247: else if (argc - 1 < cmdp->minargc)
248: fprintf(stderr, "Too few arguments\n");
249: else
250: stop = (*cmdp->handler)(argc, argv,
251: cmdp->arg ? cmdp->arg : env);
252: } else {
253: fprintf(stderr, "%s command: %s\n",
254: res == 0 ? "unknown" : "ambiguous", argv[0]);
255: }
256: cmdout:
257: free(orgline);
258: }
259: free(argv);
260:
261: return stop;
262: }
263: