examples: use new API to create control threads
[dpdk.git] / lib / librte_cmdline / cmdline.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2014 Intel Corporation.
3  * Copyright (c) 2009, Olivier MATZ <zer0@droids-corp.org>
4  * All rights reserved.
5  */
6
7 #include <stdio.h>
8 #include <string.h>
9 #include <unistd.h>
10 #include <stdlib.h>
11 #include <stdarg.h>
12 #include <inttypes.h>
13 #include <fcntl.h>
14 #include <poll.h>
15 #include <errno.h>
16 #include <termios.h>
17 #include <netinet/in.h>
18
19 #include <rte_string_fns.h>
20
21 #include "cmdline_parse.h"
22 #include "cmdline_rdline.h"
23 #include "cmdline.h"
24
25 static void
26 cmdline_valid_buffer(struct rdline *rdl, const char *buf,
27                      __attribute__((unused)) unsigned int size)
28 {
29         struct cmdline *cl = rdl->opaque;
30         int ret;
31         ret = cmdline_parse(cl, buf);
32         if (ret == CMDLINE_PARSE_AMBIGUOUS)
33                 cmdline_printf(cl, "Ambiguous command\n");
34         else if (ret == CMDLINE_PARSE_NOMATCH)
35                 cmdline_printf(cl, "Command not found\n");
36         else if (ret == CMDLINE_PARSE_BAD_ARGS)
37                 cmdline_printf(cl, "Bad arguments\n");
38 }
39
40 static int
41 cmdline_complete_buffer(struct rdline *rdl, const char *buf,
42                         char *dstbuf, unsigned int dstsize,
43                         int *state)
44 {
45         struct cmdline *cl = rdl->opaque;
46         return cmdline_complete(cl, buf, state, dstbuf, dstsize);
47 }
48
49 int
50 cmdline_write_char(struct rdline *rdl, char c)
51 {
52         int ret = -1;
53         struct cmdline *cl;
54
55         if (!rdl)
56                 return -1;
57
58         cl = rdl->opaque;
59
60         if (cl->s_out >= 0)
61                 ret = write(cl->s_out, &c, 1);
62
63         return ret;
64 }
65
66
67 void
68 cmdline_set_prompt(struct cmdline *cl, const char *prompt)
69 {
70         if (!cl || !prompt)
71                 return;
72         snprintf(cl->prompt, sizeof(cl->prompt), "%s", prompt);
73 }
74
75 struct cmdline *
76 cmdline_new(cmdline_parse_ctx_t *ctx, const char *prompt, int s_in, int s_out)
77 {
78         struct cmdline *cl;
79         int ret;
80
81         if (!ctx || !prompt)
82                 return NULL;
83
84         cl = malloc(sizeof(struct cmdline));
85         if (cl == NULL)
86                 return NULL;
87         memset(cl, 0, sizeof(struct cmdline));
88         cl->s_in = s_in;
89         cl->s_out = s_out;
90         cl->ctx = ctx;
91
92         ret = rdline_init(&cl->rdl, cmdline_write_char, cmdline_valid_buffer,
93                         cmdline_complete_buffer);
94         if (ret != 0) {
95                 free(cl);
96                 return NULL;
97         }
98
99         cl->rdl.opaque = cl;
100         cmdline_set_prompt(cl, prompt);
101         rdline_newline(&cl->rdl, cl->prompt);
102
103         return cl;
104 }
105
106 void
107 cmdline_free(struct cmdline *cl)
108 {
109         dprintf("called\n");
110
111         if (!cl)
112                 return;
113
114         if (cl->s_in > 2)
115                 close(cl->s_in);
116         if (cl->s_out != cl->s_in && cl->s_out > 2)
117                 close(cl->s_out);
118         free(cl);
119 }
120
121 void
122 cmdline_printf(const struct cmdline *cl, const char *fmt, ...)
123 {
124         va_list ap;
125
126         if (!cl || !fmt)
127                 return;
128
129 #ifdef _GNU_SOURCE
130         if (cl->s_out < 0)
131                 return;
132         va_start(ap, fmt);
133         vdprintf(cl->s_out, fmt, ap);
134         va_end(ap);
135 #else
136         int ret;
137         char *buf;
138
139         if (cl->s_out < 0)
140                 return;
141
142         buf = malloc(BUFSIZ);
143         if (buf == NULL)
144                 return;
145         va_start(ap, fmt);
146         ret = vsnprintf(buf, BUFSIZ, fmt, ap);
147         va_end(ap);
148         if (ret < 0) {
149                 free(buf);
150                 return;
151         }
152         if (ret >= BUFSIZ)
153                 ret = BUFSIZ - 1;
154         ret = write(cl->s_out, buf, ret);
155         (void)ret;
156         free(buf);
157 #endif
158 }
159
160 int
161 cmdline_in(struct cmdline *cl, const char *buf, int size)
162 {
163         const char *history, *buffer;
164         size_t histlen, buflen;
165         int ret = 0;
166         int i, same;
167
168         if (!cl || !buf)
169                 return -1;
170
171         for (i=0; i<size; i++) {
172                 ret = rdline_char_in(&cl->rdl, buf[i]);
173
174                 if (ret == RDLINE_RES_VALIDATED) {
175                         buffer = rdline_get_buffer(&cl->rdl);
176                         history = rdline_get_history_item(&cl->rdl, 0);
177                         if (history) {
178                                 histlen = strnlen(history, RDLINE_BUF_SIZE);
179                                 same = !memcmp(buffer, history, histlen) &&
180                                         buffer[histlen] == '\n';
181                         }
182                         else
183                                 same = 0;
184                         buflen = strnlen(buffer, RDLINE_BUF_SIZE);
185                         if (buflen > 1 && !same)
186                                 rdline_add_history(&cl->rdl, buffer);
187                         rdline_newline(&cl->rdl, cl->prompt);
188                 }
189                 else if (ret == RDLINE_RES_EOF)
190                         return -1;
191                 else if (ret == RDLINE_RES_EXITED)
192                         return -1;
193         }
194         return i;
195 }
196
197 void
198 cmdline_quit(struct cmdline *cl)
199 {
200         if (!cl)
201                 return;
202         rdline_quit(&cl->rdl);
203 }
204
205 int
206 cmdline_poll(struct cmdline *cl)
207 {
208         struct pollfd pfd;
209         int status;
210         ssize_t read_status;
211         char c;
212
213         if (!cl)
214                 return -EINVAL;
215         else if (cl->rdl.status == RDLINE_EXITED)
216                 return RDLINE_EXITED;
217
218         pfd.fd = cl->s_in;
219         pfd.events = POLLIN;
220         pfd.revents = 0;
221
222         status = poll(&pfd, 1, 0);
223         if (status < 0)
224                 return status;
225         else if (status > 0) {
226                 c = -1;
227                 read_status = read(cl->s_in, &c, 1);
228                 if (read_status < 0)
229                         return read_status;
230
231                 status = cmdline_in(cl, &c, 1);
232                 if (status < 0 && cl->rdl.status != RDLINE_EXITED)
233                         return status;
234         }
235
236         return cl->rdl.status;
237 }
238
239 void
240 cmdline_interact(struct cmdline *cl)
241 {
242         char c;
243
244         if (!cl)
245                 return;
246
247         c = -1;
248         while (1) {
249                 if (read(cl->s_in, &c, 1) <= 0)
250                         break;
251                 if (cmdline_in(cl, &c, 1) < 0)
252                         break;
253         }
254 }