You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@celix.apache.org by pn...@apache.org on 2017/11/12 20:13:42 UTC
celix git commit: CELIX-415: Refactors shell tui and ads support for
configuring and detecting if ANSI control sequences are useable
Repository: celix
Updated Branches:
refs/heads/develop 0a78d5d54 -> 7d3792212
CELIX-415: Refactors shell tui and ads support for configuring and detecting if ANSI control sequences are useable
Project: http://git-wip-us.apache.org/repos/asf/celix/repo
Commit: http://git-wip-us.apache.org/repos/asf/celix/commit/7d379221
Tree: http://git-wip-us.apache.org/repos/asf/celix/tree/7d379221
Diff: http://git-wip-us.apache.org/repos/asf/celix/diff/7d379221
Branch: refs/heads/develop
Commit: 7d379221262f4625faf62f3877a8192ec680638d
Parents: 0a78d5d
Author: Pepijn Noltes <pe...@gmail.com>
Authored: Sun Nov 12 21:21:23 2017 +0100
Committer: Pepijn Noltes <pe...@gmail.com>
Committed: Sun Nov 12 21:21:23 2017 +0100
----------------------------------------------------------------------
.../private/include/dm_shell_list_command.h | 8 +-
.../private/src/dm_shell_activator.c | 46 ++-
.../private/src/dm_shell_list_command.c | 18 +-
dependency_manager/readme.md | 13 +
.../public/include/service_tracker_customizer.h | 2 +
shell_tui/README.md | 10 +-
shell_tui/private/include/shell_tui.h | 20 +-
shell_tui/private/src/activator.c | 86 +++--
shell_tui/private/src/history.c | 7 -
shell_tui/private/src/shell_tui.c | 369 ++++++++++++-------
10 files changed, 362 insertions(+), 217 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/celix/blob/7d379221/dependency_manager/private/include/dm_shell_list_command.h
----------------------------------------------------------------------
diff --git a/dependency_manager/private/include/dm_shell_list_command.h b/dependency_manager/private/include/dm_shell_list_command.h
index e8405c2..6ab0581 100644
--- a/dependency_manager/private/include/dm_shell_list_command.h
+++ b/dependency_manager/private/include/dm_shell_list_command.h
@@ -26,10 +26,14 @@ extern "C" {
#include <stdlib.h>
#include <string.h>
-
#include "command.h"
-void dmListCommand_execute(bundle_context_pt context, char * line, FILE *out, FILE *err);
+typedef struct dm_command_handle {
+ bundle_context_pt context;
+ bool useColors;
+} dm_command_handle_t;
+
+void dmListCommand_execute(dm_command_handle_t* handle, char * line, FILE *out, FILE *err);
#ifdef __cplusplus
}
http://git-wip-us.apache.org/repos/asf/celix/blob/7d379221/dependency_manager/private/src/dm_shell_activator.c
----------------------------------------------------------------------
diff --git a/dependency_manager/private/src/dm_shell_activator.c b/dependency_manager/private/src/dm_shell_activator.c
index 43b8e3e..833051b 100644
--- a/dependency_manager/private/src/dm_shell_activator.c
+++ b/dependency_manager/private/src/dm_shell_activator.c
@@ -31,9 +31,12 @@
#include "dm_shell_list_command.h"
+#define DM_SHELL_USE_ANSI_COLORS "DM_SHELL_USE_ANSI_COLORS"
+
struct bundle_instance {
service_registration_pt reg;
- command_service_pt dmCommand;
+ command_service_t dmCommand;
+ dm_command_handle_t dmHandle;
};
typedef struct bundle_instance * bundle_instance_pt;
@@ -50,6 +53,11 @@ celix_status_t bundleActivator_create(bundle_context_pt context, void **userData
return CELIX_ENOMEM;
}
+ bi->dmHandle.context = context;
+ const char* config = NULL;
+ bundleContext_getPropertyWithDefault(context, DM_SHELL_USE_ANSI_COLORS, "true", &config);
+ bi->dmHandle.useColors = config != NULL && strncmp("true", config, 5) == 0;
+
(*userData) = bi;
return CELIX_SUCCESS;
@@ -58,27 +66,18 @@ celix_status_t bundleActivator_create(bundle_context_pt context, void **userData
celix_status_t bundleActivator_start(void * userData, bundle_context_pt context) {
celix_status_t status = CELIX_SUCCESS;
bundle_instance_pt bi = (bundle_instance_pt) userData;
- command_service_pt commandService = calloc(1, sizeof(*commandService));
-
- if (commandService != NULL) {
- commandService->handle = context;
- commandService->executeCommand = (void *)dmListCommand_execute;
-
- properties_pt props = properties_create();
- properties_set(props, CELIX_FRAMEWORK_SERVICE_LANGUAGE, CELIX_FRAMEWORK_SERVICE_C_LANGUAGE);
- properties_set(props, OSGI_SHELL_COMMAND_NAME, "dm");
- properties_set(props, OSGI_SHELL_COMMAND_USAGE, "dm");
- properties_set(props, OSGI_SHELL_COMMAND_DESCRIPTION,
- "Gives an overview of the component managemend by a dependency manager.");
-
- bi->dmCommand = commandService;
-
- status = bundleContext_registerService(context, (char *) OSGI_SHELL_COMMAND_SERVICE_NAME, commandService, props,
- &bi->reg);
- } else {
- status = CELIX_ENOMEM;
- free(commandService);
- }
+
+ bi->dmCommand.handle = &bi->dmHandle;
+ bi->dmCommand.executeCommand = (void *)dmListCommand_execute;
+
+ properties_pt props = properties_create();
+ properties_set(props, CELIX_FRAMEWORK_SERVICE_LANGUAGE, CELIX_FRAMEWORK_SERVICE_C_LANGUAGE);
+ properties_set(props, OSGI_SHELL_COMMAND_NAME, "dm");
+ properties_set(props, OSGI_SHELL_COMMAND_USAGE, "dm");
+ properties_set(props, OSGI_SHELL_COMMAND_DESCRIPTION,
+ "Gives an overview of the component managemend by a dependency manager.");
+
+ status = bundleContext_registerService(context, OSGI_SHELL_COMMAND_SERVICE_NAME, &bi->dmCommand, props, &bi->reg);
return status;
}
@@ -91,9 +90,6 @@ celix_status_t bundleActivator_stop(void * userData, bundle_context_pt context)
celix_status_t bundleActivator_destroy(void * userData, bundle_context_pt context) {
bundle_instance_pt bi = (bundle_instance_pt) userData;
- if (bi != NULL) {
- free(bi->dmCommand);
- }
free(bi);
return CELIX_SUCCESS;
}
http://git-wip-us.apache.org/repos/asf/celix/blob/7d379221/dependency_manager/private/src/dm_shell_list_command.c
----------------------------------------------------------------------
diff --git a/dependency_manager/private/src/dm_shell_list_command.c b/dependency_manager/private/src/dm_shell_list_command.c
index c6fe68c..1600710 100644
--- a/dependency_manager/private/src/dm_shell_list_command.c
+++ b/dependency_manager/private/src/dm_shell_list_command.c
@@ -26,6 +26,7 @@
#include <stdlib.h>
#include <string.h>
#include <dm_dependency_manager.h>
+#include <dm_shell_list_command.h>
#include "dm_info.h"
#include "service_reference.h"
#include "array_list.h"
@@ -39,28 +40,25 @@ static const char * const WARNING_COLOR = "\033[93m";
static const char * const NOK_COLOR = "\033[91m";
static const char * const END_COLOR = "\033[m";
-void dmListCommand_execute(bundle_context_pt context, char * line, FILE *out, FILE *err) {
+void dmListCommand_execute(dm_command_handle_t* handle, char * line, FILE *out, FILE *err) {
+
array_list_pt servRefs = NULL;
int i;
- bundleContext_getServiceReferences(context, DM_INFO_SERVICE_NAME ,NULL, &servRefs);
+ bundleContext_getServiceReferences(handle->context, DM_INFO_SERVICE_NAME ,NULL, &servRefs);
if(servRefs==NULL){
fprintf(out, "Invalid dm_info ServiceReferences List\n");
return;
}
- char *term = getenv("TERM");
- bool colors = false;
- if (strcmp("xterm-256color", term) == 0) {
- colors = true;
- }
+ bool colors = handle->useColors;
for(i = 0; i < arrayList_size(servRefs); i++) {
dm_dependency_manager_info_pt info = NULL;
dm_info_service_pt infoServ = NULL;
service_reference_pt servRef = NULL;
servRef = arrayList_get(servRefs, i);
- bundleContext_getService(context, servRef, (void**)&infoServ);
+ bundleContext_getService(handle->context, servRef, (void**)&infoServ);
infoServ->getInfo(infoServ->handle, &info);
int cmpCnt;
@@ -117,8 +115,8 @@ void dmListCommand_execute(bundle_context_pt context, char * line, FILE *out, FI
infoServ->destroyInfo(infoServ->handle, info);
- bundleContext_ungetService(context,servRef,NULL);
- bundleContext_ungetServiceReference(context,servRef);
+ bundleContext_ungetService(handle->context, servRef, NULL);
+ bundleContext_ungetServiceReference(handle->context, servRef);
}
http://git-wip-us.apache.org/repos/asf/celix/blob/7d379221/dependency_manager/readme.md
----------------------------------------------------------------------
diff --git a/dependency_manager/readme.md b/dependency_manager/readme.md
index 1289c46..864fc3a 100644
--- a/dependency_manager/readme.md
+++ b/dependency_manager/readme.md
@@ -113,6 +113,19 @@ celix_status_t dm_destroy(void * userData, bundle_context_pt context, dm_depende
return CELIX_SUCCESS;
}
```
+
+
+### Dependency Manager Shell support
+
+There is support for retrieving information of the dm components with
+use of the `dm` command. This command will print all known dm component,
+their state, provided interfaces and required interfaces.
+
+#### Dependency Manager Shell Config Options
+
+- DM_SHELL_USE_ANSI_COLORS - Wether to use ANSI colors when printing dm
+info. default is true.
+
### References
For more information examples please see
http://git-wip-us.apache.org/repos/asf/celix/blob/7d379221/framework/public/include/service_tracker_customizer.h
----------------------------------------------------------------------
diff --git a/framework/public/include/service_tracker_customizer.h b/framework/public/include/service_tracker_customizer.h
index 660bbb4..19672d8 100644
--- a/framework/public/include/service_tracker_customizer.h
+++ b/framework/public/include/service_tracker_customizer.h
@@ -44,6 +44,8 @@ typedef celix_status_t (*modified_callback_pt)(void *handle, service_reference_p
typedef celix_status_t (*removed_callback_pt)(void *handle, service_reference_pt reference, void *service);
typedef struct serviceTrackerCustomizer *service_tracker_customizer_pt;
+typedef struct serviceTrackerCustomizer service_tracker_customizer_t;
+
FRAMEWORK_EXPORT celix_status_t serviceTrackerCustomizer_create(void *handle,
adding_callback_pt addingFunction,
http://git-wip-us.apache.org/repos/asf/celix/blob/7d379221/shell_tui/README.md
----------------------------------------------------------------------
diff --git a/shell_tui/README.md b/shell_tui/README.md
index 4cdcda4..a637214 100644
--- a/shell_tui/README.md
+++ b/shell_tui/README.md
@@ -1,6 +1,12 @@
-## Shell TUI
+# Shell TUI
The Celix Shell TUI implements a textual user interface for the Celix Shell.
-###### CMake option
+## CMake option
BUILD_SHELL_TUI=ON
+
+## Config options
+
+- SHELL_USE_ANSI_CONTROL_SEQUENCES - Wether to use ANSI control
+sequences to support backspace, left, up, etc key commands in the
+shell tui. Default is true if a TERM environment is set else false.
http://git-wip-us.apache.org/repos/asf/celix/blob/7d379221/shell_tui/private/include/shell_tui.h
----------------------------------------------------------------------
diff --git a/shell_tui/private/include/shell_tui.h b/shell_tui/private/include/shell_tui.h
index 29f5eda..b561ff6 100644
--- a/shell_tui/private/include/shell_tui.h
+++ b/shell_tui/private/include/shell_tui.h
@@ -29,24 +29,16 @@
#include <stdlib.h>
-#include "bundle_context.h"
#include "celix_threads.h"
-#include "service_reference.h"
#include "shell.h"
-#include "service_tracker.h"
-struct shellTuiActivator {
- bundle_context_pt context;
- shell_service_pt shell;
- service_tracker_pt tracker;
- bool running;
- celix_thread_t runnable;
- celix_thread_mutex_t mutex;
-};
+typedef struct shell_tui shell_tui_t ;
-typedef struct shellTuiActivator * shell_tui_activator_pt;
+shell_tui_t* shellTui_create(bool useAnsiControlSequences);
+celix_status_t shellTui_start(shell_tui_t* shellTui);
+celix_status_t shellTui_stop(shell_tui_t* shellTui);
+void shellTui_destroy(shell_tui_t* shellTui);
-celix_status_t shellTui_start(shell_tui_activator_pt activator);
-celix_status_t shellTui_stop(shell_tui_activator_pt activator);
+celix_status_t shellTui_setShell(shell_tui_t* shellTui, shell_service_t* svc);
#endif /* SHELL_TUI_H_ */
http://git-wip-us.apache.org/repos/asf/celix/blob/7d379221/shell_tui/private/src/activator.c
----------------------------------------------------------------------
diff --git a/shell_tui/private/src/activator.c b/shell_tui/private/src/activator.c
index ec28088..f25dd5b 100644
--- a/shell_tui/private/src/activator.c
+++ b/shell_tui/private/src/activator.c
@@ -24,6 +24,7 @@
* \copyright Apache License, Version 2.0
*/
#include <stdlib.h>
+#include <string.h>
#include "bundle_context.h"
#include "bundle_activator.h"
@@ -32,36 +33,65 @@
#include "shell_tui.h"
#include "service_tracker.h"
+#define SHELL_USE_ANSI_CONTROL_SEQUENCES "SHELL_USE_ANSI_CONTROL_SEQUENCES"
+
+typedef struct shell_tui_activator {
+ shell_tui_t* shellTui;
+ service_tracker_pt tracker;
+ shell_service_t* currentSvc;
+ bool useAnsiControlSequences;
+} shell_tui_activator_t;
+
static celix_status_t activator_addShellService(void *handle, service_reference_pt ref, void *svc) {
- shell_tui_activator_pt act = (shell_tui_activator_pt) handle;
- celixThreadMutex_lock(&act->mutex);
- act->shell = svc;
- celixThreadMutex_unlock(&act->mutex);
+ shell_tui_activator_t* act = (shell_tui_activator_t*) handle;
+ act->currentSvc = svc;
+ shellTui_setShell(act->shellTui, svc);
return CELIX_SUCCESS;
}
static celix_status_t activator_removeShellService(void *handle, service_reference_pt ref, void *svc) {
- shell_tui_activator_pt act = (shell_tui_activator_pt) handle;
- celixThreadMutex_lock(&act->mutex);
- if (act->shell == svc) {
- act->shell = NULL;
+ shell_tui_activator_t* act = (shell_tui_activator_t*) handle;
+ if (act->currentSvc == svc) {
+ act->currentSvc = NULL;
+ shellTui_setShell(act->shellTui, NULL);
}
- celixThreadMutex_unlock(&act->mutex);
return CELIX_SUCCESS;
}
celix_status_t bundleActivator_create(bundle_context_pt context, void **userData) {
celix_status_t status = CELIX_SUCCESS;
- shell_tui_activator_pt activator = (shell_tui_activator_pt) calloc(1, sizeof(*activator));
+ shell_tui_activator_t* activator = calloc(1, sizeof(*activator));
+
+ if (activator != NULL) {
+ bool useCommands;
+ const char* config = NULL;
+ bundleContext_getProperty(context, SHELL_USE_ANSI_CONTROL_SEQUENCES, &config);
+ if (config != NULL) {
+ useCommands = strncmp("true", config, 5) == 0;
+ } else {
+ char *term = getenv("TERM");
+ useCommands = term != NULL;
+ }
- if (activator) {
- activator->shell = NULL;
- celixThreadMutex_create(&activator->mutex, NULL);
- (*userData) = activator;
+ activator->shellTui = shellTui_create(useCommands);
+
+ service_tracker_customizer_t* cust = NULL;
+ serviceTrackerCustomizer_create(activator, NULL, activator_addShellService, NULL, activator_removeShellService, &cust);
+ serviceTracker_create(context, OSGI_SHELL_SERVICE_NAME, cust, &activator->tracker);
}
- else {
+
+ if (activator != NULL && activator->shellTui != NULL) {
+ (*userData) = activator;
+ } else {
+ if (activator != NULL) {
+ shellTui_destroy(activator->shellTui);
+ if (activator->tracker != NULL) {
+ serviceTracker_destroy(activator->tracker);
+ }
+ }
+ free(activator);
status = CELIX_ENOMEM;
}
@@ -71,39 +101,33 @@ celix_status_t bundleActivator_create(bundle_context_pt context, void **userData
celix_status_t bundleActivator_start(void * userData, bundle_context_pt context) {
celix_status_t status = CELIX_SUCCESS;
- shell_tui_activator_pt act = (shell_tui_activator_pt) userData;
+ shell_tui_activator_t* act = (shell_tui_activator_t*) userData;
- service_tracker_customizer_pt cust = NULL;
- serviceTrackerCustomizer_create(userData, NULL, activator_addShellService, NULL, activator_removeShellService, &cust);
- serviceTracker_create(context, (char *) OSGI_SHELL_SERVICE_NAME, cust, &act->tracker);
+ act->currentSvc = NULL;
serviceTracker_open(act->tracker);
-
- shellTui_start(act);
+ shellTui_start(act->shellTui);
return status;
}
celix_status_t bundleActivator_stop(void * userData, bundle_context_pt context) {
celix_status_t status = CELIX_SUCCESS;
- shell_tui_activator_pt act = (shell_tui_activator_pt) userData;
+ shell_tui_activator_t* act = (shell_tui_activator_t*) userData;
if (act != NULL) {
- shellTui_stop(act);
- if (act->tracker != NULL) {
- serviceTracker_close(act->tracker);
- }
+ serviceTracker_close(act->tracker);
+ shellTui_stop(act->shellTui);
}
return status;
}
celix_status_t bundleActivator_destroy(void * userData, bundle_context_pt context) {
- shell_tui_activator_pt activator = (shell_tui_activator_pt) userData;
+ shell_tui_activator_t* act = (shell_tui_activator_t*) userData;
- if (activator->tracker != NULL) {
- serviceTracker_destroy(activator->tracker);
- }
- free(activator);
+ shellTui_destroy(act->shellTui);
+ serviceTracker_destroy(act->tracker);
+ free(act);
return CELIX_SUCCESS;
}
http://git-wip-us.apache.org/repos/asf/celix/blob/7d379221/shell_tui/private/src/history.c
----------------------------------------------------------------------
diff --git a/shell_tui/private/src/history.c b/shell_tui/private/src/history.c
index ee77f2e..e58c502 100644
--- a/shell_tui/private/src/history.c
+++ b/shell_tui/private/src/history.c
@@ -16,13 +16,6 @@
*specific language governing permissions and limitations
*under the License.
*/
-/*
- * activator.c
- *
- * \date Jan 15, 2016
- * \author <a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
- * \copyright Apache License, Version 2.0
- */
#include "history.h"
#include <stdlib.h>
http://git-wip-us.apache.org/repos/asf/celix/blob/7d379221/shell_tui/private/src/shell_tui.c
----------------------------------------------------------------------
diff --git a/shell_tui/private/src/shell_tui.c b/shell_tui/private/src/shell_tui.c
index 7c2fa3b..f421e6e 100644
--- a/shell_tui/private/src/shell_tui.c
+++ b/shell_tui/private/src/shell_tui.c
@@ -39,6 +39,7 @@
#include "utils.h"
#include <signal.h>
#include <unistd.h>
+#include <fcntl.h>
#include "history.h"
#define LINE_SIZE 256
@@ -56,6 +57,25 @@
#define KEY_DEL1 '3'
#define KEY_DEL2 '~'
+struct shell_tui {
+ celix_thread_mutex_t mutex; //protects shell
+ shell_service_t* shell;
+ celix_thread_t thread;
+
+ int readPipeFd;
+ int writePipeFd;
+
+ bool useAnsiControlSequences;
+};
+
+typedef struct shell_context {
+ char in[LINE_SIZE];
+ char buffer[LINE_SIZE];
+ char dline[LINE_SIZE];
+ int pos;
+ history_t* hist;
+} shell_context_t;
+
// static function declarations
static void remove_newlines(char* line);
static void clearLine();
@@ -63,161 +83,254 @@ static void cursorLeft(int n);
static void writeLine(const char*line, int pos);
static int autoComplete(shell_service_pt shellSvc, char *in, int cursorPos, size_t maxLen);
static void* shellTui_runnable(void *data);
+static void shellTui_parseInputForControl(shell_tui_t* shellTui, shell_context_t* ctx);
+static void shellTui_parseInput(shell_tui_t* shellTui, shell_context_t* ctx);
+static void writePrompt(void);
+shell_tui_t* shellTui_create(bool useAnsiControlSequences) {
+ shell_tui_t* result = calloc(1, sizeof(*result));
+ if (result != NULL) {
+ result->useAnsiControlSequences = useAnsiControlSequences;
+ celixThreadMutex_create(&result->mutex, NULL);
+ }
+ return result;
+}
-celix_status_t shellTui_start(shell_tui_activator_pt activator) {
-
+celix_status_t shellTui_start(shell_tui_t* shellTui) {
celix_status_t status = CELIX_SUCCESS;
- activator->running = true;
- celixThread_create(&activator->runnable, NULL, shellTui_runnable, activator);
+ int fds[2];
+ int rc = pipe(fds);
+ if (rc == 0) {
+ shellTui->readPipeFd = fds[0];
+ shellTui->writePipeFd = fds[1];
+ fcntl(shellTui->writePipeFd, F_SETFL, O_NONBLOCK);
+ celixThread_create(&shellTui->thread, NULL, shellTui_runnable, shellTui);
+ } else {
+ fprintf(stderr, "Cannot create pipe");
+ status = CELIX_BUNDLE_EXCEPTION;
+ }
return status;
}
-celix_status_t shellTui_stop(shell_tui_activator_pt act) {
+celix_status_t shellTui_stop(shell_tui_t* shellTui) {
celix_status_t status = CELIX_SUCCESS;
- act->running = false;
- celixThread_kill(act->runnable, SIGUSR1);
- celixThread_join(act->runnable, NULL);
+ write(shellTui->writePipeFd, "\0", 1); //trigger select to stop
+ celixThread_join(shellTui->thread, NULL);
+ close(shellTui->writePipeFd);
+ close(shellTui->readPipeFd);
return status;
}
+void shellTui_destroy(shell_tui_t* shellTui) {
+ if (shellTui == NULL) return;
+
+ celixThreadMutex_destroy(&shellTui->mutex);
+ free(shellTui);
+}
+celix_status_t shellTui_setShell(shell_tui_t* shellTui, shell_service_t* svc) {
+ celixThreadMutex_lock(&shellTui->mutex);
+ shellTui->shell = svc;
+ celixThreadMutex_unlock(&shellTui->mutex);
+ return CELIX_SUCCESS;
+}
static void* shellTui_runnable(void *data) {
- shell_tui_activator_pt act = (shell_tui_activator_pt) data;
+ shell_tui_t* shellTui = (shell_tui_t*) data;
- char in[LINE_SIZE] = "";
- char buffer[LINE_SIZE];
- int pos = 0;
- char dline[LINE_SIZE];
- fd_set rfds;
- struct timeval tv;
+ //setup shell context
+ shell_context_t ctx;
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.hist = historyCreate();
+ //setup term
struct termios term_org, term_new;
- tcgetattr(STDIN_FILENO, &term_org);
- term_new = term_org;
- term_new.c_lflag &= ~( ICANON | ECHO);
- tcsetattr(STDIN_FILENO, TCSANOW, &term_new);
+ if (shellTui->useAnsiControlSequences) {
+ tcgetattr(STDIN_FILENO, &term_org);
+ term_new = term_org;
+ term_new.c_lflag &= ~(ICANON | ECHO);
+ tcsetattr(STDIN_FILENO, TCSANOW, &term_new);
+ }
- history_t *hist = historyCreate();
+ //setup file descriptors
+ fd_set rfds;
+ int nfds = shellTui->writePipeFd > STDIN_FILENO ? (shellTui->writePipeFd +1) : (STDIN_FILENO + 1);
- while (act->running) {
- char * line = NULL;
- writeLine(in, pos);
+ for (;;) {
+ if (shellTui->useAnsiControlSequences) {
+ writeLine(ctx.in, ctx.pos);
+ } else {
+ writePrompt();
+ }
FD_ZERO(&rfds);
FD_SET(STDIN_FILENO, &rfds);
+ FD_SET(shellTui->readPipeFd, &rfds);
- tv.tv_sec = 1;
- tv.tv_usec = 0;
-
- if (select(1, &rfds, NULL, NULL, &tv) > 0) {
- int nr_chars = read(STDIN_FILENO, buffer, LINE_SIZE-pos);
- for(int bufpos = 0; bufpos < nr_chars; bufpos++) {
- if (buffer[bufpos] == KEY_ESC1 && buffer[bufpos+1] == KEY_ESC2) {
- switch (buffer[bufpos+2]) {
- case KEY_UP:
- if(historySize(hist) > 0) {
- strncpy(in, historyGetPrevLine(hist), LINE_SIZE);
- pos = strlen(in);
- writeLine(in, pos);
- }
- break;
- case KEY_DOWN:
- if(historySize(hist) > 0) {
- strncpy(in, historyGetNextLine(hist), LINE_SIZE);
- pos = strlen(in);
- writeLine(in, pos);
- }
- break;
- case KEY_RIGHT:
- if (pos < strlen(in)) {
- pos++;
- }
- writeLine(in, pos);
- break;
- case KEY_LEFT:
- if (pos > 0) {
- pos--;
- }
- writeLine(in, pos);
- break;
- case KEY_DEL1:
- if(buffer[bufpos+3] == KEY_DEL2) {
- bufpos++; // delete cmd takes 4 chars
- int len = strlen(in);
- if (pos < len) {
- for (int i = pos; i <= len; i++) {
- in[i] = in[i + 1];
- }
- }
- writeLine(in, pos);
- }
- break;
- default:
- // Unsupported char, do nothing
- break;
- }
- bufpos+=2;
- continue;
- } else if(buffer[bufpos] == KEY_BACKSPACE) { // backspace
- if(pos > 0) {
- int len = strlen(in);
- for(int i = pos-1; i <= len; i++) {
- in[i] = in[i+1];
- }
- pos--;
- }
- writeLine(in, pos);
- continue;
- } else if(buffer[bufpos] == KEY_TAB) {
- pos = autoComplete(act->shell, in, pos, LINE_SIZE);
- continue;
- } else if(buffer[bufpos] != KEY_ENTER) { //text
- if(in[pos] == '\0') {
- in[pos+1] = '\0';
- }
- in[pos] = buffer[bufpos];
- pos++;
- writeLine(in, pos);
- fflush(stdout);
- continue;
+ if (select(nfds, &rfds, NULL, NULL, NULL) > 0) {
+ if (FD_ISSET(shellTui->readPipeFd, &rfds)) {
+ break; //something is written to the pipe -> exit thread
+ } else if (FD_ISSET(STDIN_FILENO, &rfds)) {
+ if (shellTui->useAnsiControlSequences) {
+ shellTui_parseInputForControl(shellTui, &ctx);
+ } else {
+ shellTui_parseInput(shellTui, &ctx);
}
- writeLine(in, pos);
- write(STDOUT_FILENO, "\n", 1);
- remove_newlines(in);
- history_addLine(hist, in);
+ }
+ }
+ }
+ tcsetattr(STDIN_FILENO, TCSANOW, &term_org); //TODO or after SIGINT
+ historyDestroy(ctx.hist);
+
+ return NULL;
+}
- memset(dline, 0, LINE_SIZE);
- strncpy(dline, in, LINE_SIZE);
+static void shellTui_parseInput(shell_tui_t* shellTui, shell_context_t* ctx) {
+ char* buffer = ctx->buffer;
+ char* in = ctx->in;
+ int pos = ctx->pos;
- pos = 0;
- in[pos] = '\0';
+ char* line = NULL;
- line = utils_stringTrim(dline);
- if ((strlen(line) == 0) || (act->shell == NULL)) {
- continue;
- }
- historyLineReset(hist);
- celixThreadMutex_lock(&act->mutex);
- if (act->shell != NULL) {
- act->shell->executeCommand(act->shell->shell, line, stdout, stderr);
- pos = 0;
- nr_chars = 0;
- celixThreadMutex_unlock(&act->mutex);
+
+ int nr_chars = read(STDIN_FILENO, buffer, LINE_SIZE-pos-1);
+ for(int bufpos = 0; bufpos < nr_chars; bufpos++) {
+ if (buffer[bufpos] == KEY_ENTER) { //end of line -> forward command
+ line = utils_stringTrim(in);
+ celixThreadMutex_lock(&shellTui->mutex);
+ if (shellTui->shell != NULL) {
+ printf("Providing command '%s' from in '%s'\n", line, in);
+ shellTui->shell->executeCommand(shellTui->shell->shell, line, stdout, stderr);
+ } else {
+ fprintf(stderr, "Shell service not available\n");
+ }
+ celixThreadMutex_unlock(&shellTui->mutex);
+ pos = 0;
+ in[pos] = '\0';
+ } else { //text
+ in[pos] = buffer[bufpos];
+ in[pos+1] = '\0';
+ pos++;
+ continue;
+ }
+ } // for
+ ctx->pos = pos;
+}
+
+static void shellTui_parseInputForControl(shell_tui_t* shellTui, shell_context_t* ctx) {
+ char* buffer = ctx->buffer;
+ char* in = ctx->in;
+ char* dline = ctx->dline;
+ history_t* hist = ctx->hist;
+ int pos = ctx->pos;
+
+ char* line = NULL;
+
+ int nr_chars = read(STDIN_FILENO, buffer, LINE_SIZE-pos-1);
+ for(int bufpos = 0; bufpos < nr_chars; bufpos++) {
+ if (buffer[bufpos] == KEY_ESC1 && buffer[bufpos+1] == KEY_ESC2) {
+ switch (buffer[bufpos+2]) {
+ case KEY_UP:
+ if(historySize(hist) > 0) {
+ strncpy(in, historyGetPrevLine(hist), LINE_SIZE);
+ pos = strlen(in);
+ writeLine(in, pos);
+ }
break;
- } else {
- fprintf(stderr, "Shell service not available\n");
+ case KEY_DOWN:
+ if(historySize(hist) > 0) {
+ strncpy(in, historyGetNextLine(hist), LINE_SIZE);
+ pos = strlen(in);
+ writeLine(in, pos);
+ }
+ break;
+ case KEY_RIGHT:
+ if (pos < strlen(in)) {
+ pos++;
+ }
+ writeLine(in, pos);
+ break;
+ case KEY_LEFT:
+ if (pos > 0) {
+ pos--;
+ }
+ writeLine(in, pos);
+ break;
+ case KEY_DEL1:
+ if(buffer[bufpos+3] == KEY_DEL2) {
+ bufpos++; // delete cmd takes 4 chars
+ int len = strlen(in);
+ if (pos < len) {
+ for (int i = pos; i <= len; i++) {
+ in[i] = in[i + 1];
+ }
+ }
+ writeLine(in, pos);
+ }
+ break;
+ default:
+ // Unsupported char, do nothing
+ break;
+ }
+ bufpos+=2;
+ continue;
+ } else if (buffer[bufpos] == KEY_BACKSPACE) { // backspace
+ if(pos > 0) {
+ int len = strlen(in);
+ for(int i = pos-1; i <= len; i++) {
+ in[i] = in[i+1];
}
- celixThreadMutex_unlock(&act->mutex);
- } // for
+ pos--;
+ }
+ writeLine(in, pos);
+ continue;
+ } else if(buffer[bufpos] == KEY_TAB) {
+ celixThreadMutex_lock(&shellTui->mutex);
+ if (shellTui != NULL) {
+ pos = autoComplete(shellTui->shell, in, pos, LINE_SIZE);
+ }
+ celixThreadMutex_unlock(&shellTui->mutex);
+ continue;
+ } else if (buffer[bufpos] != KEY_ENTER) { //not end of line -> text
+ if (in[pos] == '\0') {
+ in[pos+1] = '\0';
+ }
+ in[pos] = buffer[bufpos];
+ pos++;
+ writeLine(in, pos);
+ fflush(stdout);
+ continue;
}
- }
- tcsetattr(STDIN_FILENO, TCSANOW, &term_org);
- historyDestroy(hist);
- return NULL;
+ //parse enter
+ writeLine(in, pos);
+ write(STDOUT_FILENO, "\n", 1);
+ remove_newlines(in);
+ history_addLine(hist, in);
+
+ memset(dline, 0, LINE_SIZE);
+ strncpy(dline, in, LINE_SIZE);
+
+ pos = 0;
+ in[pos] = '\0';
+
+ line = utils_stringTrim(dline);
+ if ((strlen(line) == 0)) {
+ continue;
+ }
+ historyLineReset(hist);
+ celixThreadMutex_lock(&shellTui->mutex);
+ if (shellTui->shell != NULL) {
+ shellTui->shell->executeCommand(shellTui->shell->shell, line, stdout, stderr);
+ pos = 0;
+ nr_chars = 0;
+ } else {
+ fprintf(stderr, "Shell service not available\n");
+ }
+ celixThreadMutex_unlock(&shellTui->mutex);
+ } // for
+ ctx->pos = pos;
}
static void remove_newlines(char* line) {
@@ -242,14 +355,18 @@ static void cursorLeft(int n) {
}
}
-static void writeLine(const char*line, int pos) {
+static void writePrompt(void) {
+ write(STDIN_FILENO, PROMPT, strlen(PROMPT));
+}
+
+static void writeLine(const char* line, int pos) {
clearLine();
write(STDOUT_FILENO, PROMPT, strlen(PROMPT));
write(STDOUT_FILENO, line, strlen(line));
cursorLeft(strlen(line)-pos);
}
-static int autoComplete(shell_service_pt shellSvc, char *in, int cursorPos, size_t maxLen) {
+static int autoComplete(shell_service_t* shellSvc, char *in, int cursorPos, size_t maxLen) {
array_list_pt commandList = NULL;
array_list_pt possibleCmdList = NULL;
shellSvc->getCommands(shellSvc->shell, &commandList);