mk: build with _GNU_SOURCE defined by default
[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         if (cl->s_out < 0)
130                 return;
131         va_start(ap, fmt);
132         vdprintf(cl->s_out, fmt, ap);
133         va_end(ap);
134 }
135
136 int
137 cmdline_in(struct cmdline *cl, const char *buf, int size)
138 {
139         const char *history, *buffer;
140         size_t histlen, buflen;
141         int ret = 0;
142         int i, same;
143
144         if (!cl || !buf)
145                 return -1;
146
147         for (i=0; i<size; i++) {
148                 ret = rdline_char_in(&cl->rdl, buf[i]);
149
150                 if (ret == RDLINE_RES_VALIDATED) {
151                         buffer = rdline_get_buffer(&cl->rdl);
152                         history = rdline_get_history_item(&cl->rdl, 0);
153                         if (history) {
154                                 histlen = strnlen(history, RDLINE_BUF_SIZE);
155                                 same = !memcmp(buffer, history, histlen) &&
156                                         buffer[histlen] == '\n';
157                         }
158                         else
159                                 same = 0;
160                         buflen = strnlen(buffer, RDLINE_BUF_SIZE);
161                         if (buflen > 1 && !same)
162                                 rdline_add_history(&cl->rdl, buffer);
163                         rdline_newline(&cl->rdl, cl->prompt);
164                 }
165                 else if (ret == RDLINE_RES_EOF)
166                         return -1;
167                 else if (ret == RDLINE_RES_EXITED)
168                         return -1;
169         }
170         return i;
171 }
172
173 void
174 cmdline_quit(struct cmdline *cl)
175 {
176         if (!cl)
177                 return;
178         rdline_quit(&cl->rdl);
179 }
180
181 int
182 cmdline_poll(struct cmdline *cl)
183 {
184         struct pollfd pfd;
185         int status;
186         ssize_t read_status;
187         char c;
188
189         if (!cl)
190                 return -EINVAL;
191         else if (cl->rdl.status == RDLINE_EXITED)
192                 return RDLINE_EXITED;
193
194         pfd.fd = cl->s_in;
195         pfd.events = POLLIN;
196         pfd.revents = 0;
197
198         status = poll(&pfd, 1, 0);
199         if (status < 0)
200                 return status;
201         else if (status > 0) {
202                 c = -1;
203                 read_status = read(cl->s_in, &c, 1);
204                 if (read_status < 0)
205                         return read_status;
206
207                 status = cmdline_in(cl, &c, 1);
208                 if (status < 0 && cl->rdl.status != RDLINE_EXITED)
209                         return status;
210         }
211
212         return cl->rdl.status;
213 }
214
215 void
216 cmdline_interact(struct cmdline *cl)
217 {
218         char c;
219
220         if (!cl)
221                 return;
222
223         c = -1;
224         while (1) {
225                 if (read(cl->s_in, &c, 1) <= 0)
226                         break;
227                 if (cmdline_in(cl, &c, 1) < 0)
228                         break;
229         }
230 }