initial revision
[ucgine.git] / lib / cmd / ucg_cmd.c
1 /*
2  * Copyright (c) 2009-2015, Olivier MATZ <zer0@droids-corp.org>
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  *     * Redistributions of source code must retain the above copyright
8  *       notice, this list of conditions and the following disclaimer.
9  *     * Redistributions in binary form must reproduce the above copyright
10  *       notice, this list of conditions and the following disclaimer in the
11  *       documentation and/or other materials provided with the distribution.
12  *     * Neither the name of the University of California, Berkeley nor the
13  *       names of its contributors may be used to endorse or promote products
14  *       derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 /*-
29  * Copyright (c) <2010>, Intel Corporation
30  * All rights reserved.
31  *
32  * Redistribution and use in source and binary forms, with or without
33  * modification, are permitted provided that the following conditions
34  * are met:
35  *
36  * - Redistributions of source code must retain the above copyright
37  *   notice, this list of conditions and the following disclaimer.
38  *
39  * - Redistributions in binary form must reproduce the above copyright
40  *   notice, this list of conditions and the following disclaimer in
41  *   the documentation and/or other materials provided with the
42  *   distribution.
43  *
44  * - Neither the name of Intel Corporation nor the names of its
45  *   contributors may be used to endorse or promote products derived
46  *   from this software without specific prior written permission.
47  *
48  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
49  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
50  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
51  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
52  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
53  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
54  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
55  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
57  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
58  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
59  * OF THE POSSIBILITY OF SUCH DAMAGE.
60  */
61
62 #include <stdio.h>
63 #include <string.h>
64 #include <stdlib.h>
65 #include <stdarg.h>
66 #include <inttypes.h>
67 #include <unistd.h>
68 #include <fcntl.h>
69
70 #include "ucg_cmd_parse.h"
71 #include "ucg_cmd_rdline.h"
72 #include "ucg_cmd.h"
73
74 static void
75 default_valid_buffer(struct ucg_rdline *rdl, const char *line)
76 {
77         struct ucg_cmd *cl = rdl->opaque;
78         int ret;
79
80         ret = ucg_cmd_parse(cl, line, cl);
81         if (ret == UCG_CMD_PARSE_AMBIGUOUS)
82                 ucg_cmd_printf(cl, "Ambiguous command\n");
83         else if (ret == UCG_CMD_PARSE_NOMATCH)
84                 ucg_cmd_printf(cl, "Bad arguments\n");
85         else if (ret == UCG_CMD_PARSE_UNTERMINATED_QUOTE)
86                 ucg_cmd_printf(cl, "Unterminated quote\n");
87 }
88
89 static int
90 default_complete_buffer(struct ucg_rdline *rdl, const char *line,
91         char *dstbuf, unsigned int dstsize)
92 {
93         int ret;
94         struct ucg_cmd *cl = rdl->opaque;
95         ret = ucg_cmd_complete(cl, line, dstbuf, dstsize);
96         if (ret == UCG_CMD_COMPLETE_APPEND)
97                 return 0;
98         return -1;
99 }
100
101
102 static void
103 default_help(struct ucg_rdline *rdl, const char *line)
104 {
105         struct ucg_cmd *cl = rdl->opaque;
106
107         ucg_cmd_help(cl, line);
108 }
109
110 /* ---- Some rdline wrappers ---- */
111
112 void
113 ucg_cmd_set_prompt(struct ucg_cmd *cl, const char *prompt)
114 {
115         snprintf(cl->prompt, sizeof(cl->prompt), "%s", prompt);
116 }
117
118 void
119 ucg_cmd_init(struct ucg_cmd *cl, ucg_cmd_ctx_t *ctx,
120         const char *prompt, FILE *f_in, FILE *f_out)
121 {
122         /* init cmd structure */
123         memset(cl, 0, sizeof(struct ucg_cmd));
124         cl->ctx = ctx;
125
126         /* init embedded rdline */
127         ucg_rdline_init(&cl->rdl, f_in, f_out,
128                 default_valid_buffer,
129                 default_complete_buffer,
130                 default_help);
131
132         cl->rdl.opaque = cl;
133         ucg_cmd_set_prompt(cl, prompt);
134         ucg_rdline_newline(&cl->rdl, cl->prompt);
135 }
136
137 struct ucg_cmd *
138 ucg_cmd_new(ucg_cmd_ctx_t *ctx, const char *prompt,
139         FILE *f_in, FILE *f_out)
140 {
141         struct ucg_cmd *cl;
142
143         cl = malloc(sizeof(struct ucg_cmd));
144         if (cl == NULL)
145                 return NULL;
146
147         ucg_cmd_init(cl, ctx, prompt, f_in, f_out);
148         return cl;
149 }
150
151 struct ucg_cmd *
152 ucg_cmd_file_new(ucg_cmd_ctx_t *ctx, const char *prompt,
153         const char *path, FILE *f_out)
154 {
155 #if UCG_CMD_HAVE_FILE
156         FILE *f_in;
157
158         f_in = fopen(path, "r");
159         if (f_in == NULL)
160                 return NULL;
161         return (ucg_cmd_new(ctx, prompt, f_in, f_out));
162 #else
163         (void)ctx;
164         (void)prompt;
165         (void)path;
166         (void)f_out;
167         return NULL;
168 #endif
169 }
170
171 void
172 ucg_cmd_free(struct ucg_cmd *cl)
173 {
174         struct ucg_rdline *rdl = &cl->rdl;
175
176         if (rdl->f_in != stdin)
177                 fclose(rdl->f_in);
178         if (rdl->f_out != rdl->f_in && rdl->f_out != stdout &&
179                 rdl->f_out != stderr)
180                 fclose(rdl->f_out);
181         free(cl);
182 }
183
184 int
185 ucg_cmd_printf(struct ucg_cmd *cl, const char *fmt, ...)
186 {
187         va_list ap;
188         int ret;
189
190         va_start(ap, fmt);
191         ret = ucg_rdline_vprintf(&cl->rdl, fmt, ap);
192         va_end(ap);
193
194         return ret;
195 }
196
197 /* Push an input buffer in the command line. Typically, this function
198  * is called by ucg_cmd_interact() to send the input characters to the
199  * cmd process. It can also be called by a user callback function,
200  * when a buffer is received from the input socket.
201  *
202  * The function returns the number of processed characters, or a
203  * negative value on error (EOF reached or command line exited. */
204 int
205 ucg_cmd_in(struct ucg_cmd *cl, const char *buf, int size)
206 {
207         int ret = 0;
208         int i;
209
210         for (i = 0; i < size; i++) {
211                 ret = ucg_rdline_char_in(&cl->rdl, buf[i]);
212
213                 if (ret == UCG_RDLINE_RES_VALIDATED &&
214                         cl->rdl.status == UCG_RDLINE_STOPPED)
215                         break;
216
217                 if (ret == UCG_RDLINE_RES_VALIDATED)
218                         ucg_rdline_newline(&cl->rdl, cl->prompt);
219                 else if (ret == UCG_RDLINE_RES_EOF)
220                         return -1;
221                 else if (ret == UCG_RDLINE_RES_EXITED)
222                         return -1;
223         }
224         return i;
225 }
226
227 /* Interrupt a running command line (exits from ucg_cmd_interact) */
228 void
229 ucg_cmd_quit(struct ucg_cmd *cl)
230 {
231         ucg_rdline_quit(&cl->rdl);
232 }
233
234 /* loop until the user explicitelly call ucg_cmd_quit(), or if the input
235  * fd reaches EOF. */
236 void
237 ucg_cmd_interact(struct ucg_cmd *cl, unsigned flags)
238 {
239         int ret;
240         char c;
241
242         c = -1;
243         while (1) {
244                 ret = fread(&c, 1, 1, cl->rdl.f_in);
245
246                 if (ret == 0) {
247                         if (flags & UCG_CMD_F_IGNORE_EOF) {
248                                 clearerr(cl->rdl.f_in);
249                                 continue;
250                         }
251                         break;
252                 }
253
254                 if (ucg_cmd_in(cl, &c, 1) < 0)
255                         break;
256         }
257 }