iotivity 0.9.0
[platform/upstream/iotivity.git] / service / protocol-plugin / lib / cpluff / console / cmdinput_readline.c
1 /*-------------------------------------------------------------------------
2  * C-Pluff, a plug-in framework for C
3  * Copyright 2007 Johannes Lehtinen
4  * 
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included
13  * in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  *-----------------------------------------------------------------------*/
23
24 // GNU readline based command line input 
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <ctype.h>
29 #include <readline/readline.h>
30 #include <readline/history.h>
31 #include "console.h"
32
33 static cp_plugin_info_t **plugins = NULL;
34
35 static char *cp_console_compl_cmdgen(const char *text, int state) {
36         static int counter;
37         static int textlen;
38
39         if (!state) {
40                 counter = 0;
41                 textlen = strlen(text);
42         }
43         while (commands[counter].name != NULL && strncmp(text, commands[counter].name, textlen)) {
44                 counter++;
45         }
46         if (commands[counter].name == NULL) {
47                 return NULL;
48         } else {
49                 char *buffer = strdup(commands[counter].name);
50                 counter++;
51                 return buffer;
52         }
53 }
54
55 static char *cp_console_compl_flagsgen(const char *text, int state) {
56         static int counter;
57         static int textlen;
58         
59         if (!state) {
60                 counter = 0;
61                 textlen = strlen(text);
62         }
63         while(load_flags[counter].name != NULL && strncmp(text, load_flags[counter].name, textlen)) {
64                 counter++;
65         }
66         if (load_flags[counter].name == NULL) {
67                 return NULL;
68         } else {
69                 char *buffer = strdup(load_flags[counter].name);
70                 counter++;
71                 return buffer;
72         }
73 }
74
75 static char *cp_console_compl_loggen(const char *text, int state) {
76         static int counter;
77         static int textlen;
78         
79         if (!state) {
80                 counter = 0;
81                 textlen = strlen(text);
82         }
83         while (log_levels[counter].name != NULL && strncmp(text, log_levels[counter].name, textlen)) {
84                 counter++;
85         }
86         if (log_levels[counter].name == NULL) {
87                 return NULL;
88         } else {
89                 char *buffer = strdup(log_levels[counter].name);
90                 counter++;
91                 return buffer;
92         }
93 }
94
95 static char *cp_console_compl_plugingen(const char *text, int state) {
96         static int counter;
97         static int textlen;
98         
99         if (!state) {
100                 counter = 0;
101                 textlen = strlen(text);
102                 if (plugins != NULL) {
103                         cp_release_info(context, plugins);
104                 }
105                 plugins = cp_get_plugins_info(context, NULL, NULL);
106         }
107         if (plugins != NULL) {
108                 while (plugins[counter] != NULL && strncmp(text, plugins[counter]->identifier, textlen)) {
109                         counter++;
110                 }
111                 if (plugins[counter] == NULL) {
112                         cp_release_info(context, plugins);
113                         plugins = NULL;
114                         return NULL;
115                 } else {
116                         char *buffer = strdup(plugins[counter]->identifier);
117                         counter++;
118                         return buffer;
119                 }
120         } else {
121                 return NULL;
122         }
123 }
124
125 static char **cp_console_completion(const char *text, int start, int end) {
126         int cs, ce;
127         char **matches = NULL;
128
129         // Search for start and end of command  
130         for (cs = 0; cs < start && isspace(rl_line_buffer[cs]); cs++);
131         for (ce = cs; ce <= start && !isspace(rl_line_buffer[ce]); ce++);
132         
133         // If no command entered yet, use command completion
134         if (ce >= start) {
135                 matches = rl_completion_matches(text, cp_console_compl_cmdgen);
136                 rl_attempted_completion_over = 1;
137         }
138         
139         // Otherwise check if known command and complete accordingly
140         else {
141                 int j = 0;
142                 while (commands[j].name != NULL
143                                 && strncmp(rl_line_buffer + cs, commands[j].name, ce - cs)) {
144                         j++;
145                 }
146                 if (commands[j].name != NULL) {
147                         switch(commands[j].arg_completion) {
148                                 case CPC_COMPL_FILE:
149                                         break;
150                                 case CPC_COMPL_FLAG:
151                                         matches = rl_completion_matches(text, cp_console_compl_flagsgen);
152                                         rl_attempted_completion_over = 1;
153                                         break;
154                                 case CPC_COMPL_LOG_LEVEL:
155                                         matches = rl_completion_matches(text, cp_console_compl_loggen);
156                                         rl_attempted_completion_over = 1;
157                                         break;
158                                 case CPC_COMPL_PLUGIN:
159                                         matches = rl_completion_matches(text, cp_console_compl_plugingen);
160                                         rl_attempted_completion_over = 1;
161                                         break;
162                                 default:
163                                         rl_attempted_completion_over = 1;
164                                         break;
165                         }
166                 } else {
167                         rl_attempted_completion_over = 1;
168                 }
169         }
170         return matches;
171 }
172
173 CP_HIDDEN void cmdline_init(void) {
174         rl_readline_name = PACKAGE_NAME;
175         rl_attempted_completion_function = cp_console_completion;
176 }
177
178 CP_HIDDEN char *cmdline_input(const char *prompt) {
179         static char *cmdline = NULL;
180         
181         // Free previously returned command line, if any 
182         if (cmdline != NULL) {
183                 free(cmdline);
184                 cmdline = NULL;
185         }
186         
187         // Obtain new command line and record it for history 
188         cmdline = readline(prompt);
189         if (cmdline != NULL && *cmdline != '\0') {
190                 add_history(cmdline);
191         }
192         
193         return cmdline;
194 }
195
196 CP_HIDDEN void cmdline_destroy(void) {
197         if (plugins != NULL) {
198                 cp_release_info(context, plugins);
199                 plugins = NULL;
200         }
201 }