2013-11-08 12:48:22

by Jerzy Kasenberg

[permalink] [raw]
Subject: [PATCH 0/8] Improve user experience

This patchset works towards improving user interface.
- Command line parsing (--help, --version, --no-init)
- All interfaces are now initialized at start by default
- --no-init allows to disable this initialization
- pin_request_cb will now present prompt and send reply
- ssp_request_cb will now present prompt and sent reply

As part of adding those features terminal.c was restructured.
Big switch inside terminal_process_char was distributed between
number of small functions. This work was necessary due to input
handling of prompted data.

Version print may need to be changed according to bluez culture.

Jerzy Kasenberg (8):
android/client: Export get_interface_method
android/client: Add NELEM macro for count elements
android/client: Initialize all interfaces at start
android/client: Add command line arguments
android/client: Split terminal_process_char
android/client: Add prompting for answer
android/client: Add pin handling for bind
android/client: Add ssp key confirmation helper

android/client/haltest.c | 102 ++++++-
android/client/if-bt.c | 46 +++
android/client/if-main.h | 4 +
android/client/tabcompletion.c | 2 +-
android/client/terminal.c | 605 +++++++++++++++++++++++++++-------------
android/client/terminal.h | 5 +-
6 files changed, 567 insertions(+), 197 deletions(-)

--
1.7.9.5



2013-11-08 13:16:37

by Johan Hedberg

[permalink] [raw]
Subject: Re: [PATCH 0/8] Improve user experience

Hi Jerzy,

On Fri, Nov 08, 2013, Jerzy Kasenberg wrote:
> This patchset works towards improving user interface.
> - Command line parsing (--help, --version, --no-init)
> - All interfaces are now initialized at start by default
> - --no-init allows to disable this initialization
> - pin_request_cb will now present prompt and send reply
> - ssp_request_cb will now present prompt and sent reply
>
> As part of adding those features terminal.c was restructured.
> Big switch inside terminal_process_char was distributed between
> number of small functions. This work was necessary due to input
> handling of prompted data.
>
> Version print may need to be changed according to bluez culture.
>
> Jerzy Kasenberg (8):
> android/client: Export get_interface_method
> android/client: Add NELEM macro for count elements
> android/client: Initialize all interfaces at start
> android/client: Add command line arguments
> android/client: Split terminal_process_char
> android/client: Add prompting for answer
> android/client: Add pin handling for bind
> android/client: Add ssp key confirmation helper
>
> android/client/haltest.c | 102 ++++++-
> android/client/if-bt.c | 46 +++
> android/client/if-main.h | 4 +
> android/client/tabcompletion.c | 2 +-
> android/client/terminal.c | 605 +++++++++++++++++++++++++++-------------
> android/client/terminal.h | 5 +-
> 6 files changed, 567 insertions(+), 197 deletions(-)

All eight patches have been applied. Thanks.

Johan

2013-11-08 12:48:29

by Jerzy Kasenberg

[permalink] [raw]
Subject: [PATCH 7/8] android/client: Add pin handling for bind

This patch ask user for ping in pin_request_cb, which does
what otherwise would be required to manually type
bluetooth pin_reply address pin.
---
android/client/if-bt.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)

diff --git a/android/client/if-bt.c b/android/client/if-bt.c
index 4c501a5..0a580e1 100644
--- a/android/client/if-bt.c
+++ b/android/client/if-bt.c
@@ -16,6 +16,7 @@
*/

#include "if-main.h"
+#include "terminal.h"

const bt_interface_t *if_bluetooth;

@@ -209,14 +210,33 @@ static void discovery_state_changed_cb(bt_discovery_state_t state)
static char last_remote_addr[MAX_ADDR_STR_LEN];
static bt_ssp_variant_t last_ssp_variant = (bt_ssp_variant_t) -1;

+static bt_bdaddr_t pin_request_addr;
+static void pin_request_answer(char *reply)
+{
+ bt_pin_code_t pin;
+ int accept = 0;
+ int pin_len = strlen(reply);
+
+ if (pin_len > 0) {
+ accept = 1;
+ if (pin_len > 16)
+ pin_len = 16;
+ memcpy(&pin.pin, reply, pin_len);
+ }
+
+ EXEC(if_bluetooth->pin_reply, &pin_request_addr, accept, pin_len, &pin);
+}
+
static void pin_request_cb(bt_bdaddr_t *remote_bd_addr, bt_bdname_t *bd_name,
uint32_t cod)
{
/* Store for command completion */
bt_bdaddr_t2str(remote_bd_addr, last_remote_addr);
+ pin_request_addr = *remote_bd_addr;

haltest_info("%s: remote_bd_addr=%s bd_name=%s cod=%06x\n", __func__,
last_remote_addr, bd_name->name, cod);
+ terminal_prompt_for("Enter pin: ", pin_request_answer);
}

static void ssp_request_cb(bt_bdaddr_t *remote_bd_addr, bt_bdname_t *bd_name,
--
1.7.9.5


2013-11-08 12:48:30

by Jerzy Kasenberg

[permalink] [raw]
Subject: [PATCH 8/8] android/client: Add ssp key confirmation helper

This patch adds handling of ssp_request_cb that prints prompt
asking user if pass key matches. User does not need to type:
bluetooth ssp_reply address BT_SSP_VARIANT_PASSKEY_CONFIRMATION 1 key
---
android/client/if-bt.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)

diff --git a/android/client/if-bt.c b/android/client/if-bt.c
index 0a580e1..10ae125 100644
--- a/android/client/if-bt.c
+++ b/android/client/if-bt.c
@@ -239,10 +239,26 @@ static void pin_request_cb(bt_bdaddr_t *remote_bd_addr, bt_bdname_t *bd_name,
terminal_prompt_for("Enter pin: ", pin_request_answer);
}

+/* Variables to store information from ssp_request_cb used for ssp_reply */
+static bt_bdaddr_t ssp_request_addr;
+static bt_ssp_variant_t ssp_request_variant;
+static uint32_t ssp_request_pask_key;
+
+/* Called when user hit enter on prompt for confirmation */
+static void ssp_request_yes_no_answer(char *reply)
+{
+ int accept = *reply == 0 || *reply == 'y' || *reply == 'Y';
+
+ if_bluetooth->ssp_reply(&ssp_request_addr, ssp_request_variant, accept,
+ ssp_request_pask_key);
+}
+
static void ssp_request_cb(bt_bdaddr_t *remote_bd_addr, bt_bdname_t *bd_name,
uint32_t cod, bt_ssp_variant_t pairing_variant,
uint32_t pass_key)
{
+ static char prompt[50];
+
/* Store for command completion */
bt_bdaddr_t2str(remote_bd_addr, last_remote_addr);
last_ssp_variant = pairing_variant;
@@ -250,6 +266,16 @@ static void ssp_request_cb(bt_bdaddr_t *remote_bd_addr, bt_bdname_t *bd_name,
haltest_info("%s: remote_bd_addr=%s bd_name=%s cod=%06x pairing_variant=%s pass_key=%d\n",
__func__, last_remote_addr, bd_name->name, cod,
bt_ssp_variant_t2str(pairing_variant), pass_key);
+
+ if (pairing_variant == BT_SSP_VARIANT_PASSKEY_CONFIRMATION) {
+ sprintf(prompt, "Does other device show %d [Y/n] ?", pass_key);
+
+ ssp_request_addr = *remote_bd_addr;
+ ssp_request_variant = pairing_variant;
+ ssp_request_pask_key = pass_key;
+
+ terminal_prompt_for(prompt, ssp_request_yes_no_answer);
+ }
}

static void bond_state_changed_cb(bt_status_t status,
--
1.7.9.5


2013-11-08 12:48:28

by Jerzy Kasenberg

[permalink] [raw]
Subject: [PATCH 6/8] android/client: Add prompting for answer

This patch allows to switch to prompt mode where user will be asked
to supply some information.
---
android/client/terminal.c | 67 +++++++++++++++++++++++++++++++++++++++++++++
android/client/terminal.h | 1 +
2 files changed, 68 insertions(+)

diff --git a/android/client/terminal.c b/android/client/terminal.c
index 3674f89..f7b56de 100644
--- a/android/client/terminal.c
+++ b/android/client/terminal.c
@@ -684,6 +684,9 @@ TERMINAL_ACTION(terminal_action_default)
terminal_insert_into_command_line(str);
}

+/* Callback to call when user hit enter during prompt for */
+static line_callback prompt_callback;
+
static KeyAction normal_actions[] = {
{ 0, terminal_action_default },
{ KEY_LEFT, terminal_action_left },
@@ -709,6 +712,59 @@ static KeyAction normal_actions[] = {
{ 0, NULL },
};

+TERMINAL_ACTION(terminal_action_answer)
+{
+ putchar(c);
+
+ terminal_set_actions(normal_actions);
+ /* Restore default prompt */
+ current_prompt = prompt_buf;
+
+ /* No prompt for prints */
+ prompt = noprompt;
+ line_buf_ix = 0;
+ line_len = 0;
+ /* Call user function with what was typed */
+ prompt_callback(line_buf);
+
+ line_buf[0] = 0;
+ /* promot_callback could change current_prompt */
+ prompt = current_prompt;
+
+ printf("%s", prompt);
+}
+
+TERMINAL_ACTION(terminal_action_prompt_ctrl_c)
+{
+ printf("^C\n");
+ line_buf_ix = 0;
+ line_len = 0;
+ line_buf[0] = 0;
+
+ current_prompt = prompt_buf;
+ prompt = current_prompt;
+ terminal_set_actions(normal_actions);
+
+ printf("%s", prompt);
+}
+
+static KeyAction prompt_actions[] = {
+ { 0, terminal_action_default },
+ { KEY_LEFT, terminal_action_left },
+ { KEY_RIGHT, terminal_action_right },
+ { KEY_HOME, terminal_action_home },
+ { KEY_END, terminal_action_end },
+ { KEY_DELETE, terminal_action_del },
+ { KEY_CLEFT, terminal_action_word_left },
+ { KEY_CRIGHT, terminal_action_word_right },
+ { KEY_BACKSPACE, terminal_action_backspace },
+ { KEY_C_C, terminal_action_prompt_ctrl_c },
+ { KEY_C_D, terminal_action_ctrl_d },
+ { '\r', terminal_action_answer },
+ { '\n', terminal_action_answer },
+ { 0, NULL },
+};
+
void terminal_process_char(int c, line_callback process_line)
{
KeyAction *a;
@@ -726,6 +782,17 @@ void terminal_process_char(int c, line_callback process_line)
fflush(stdout);
}

+void terminal_prompt_for(const char *s, line_callback process_line)
+{
+ current_prompt = s;
+ if (prompt != noprompt) {
+ prompt = s;
+ terminal_clear_line();
+ }
+ prompt_callback = process_line;
+ terminal_set_actions(prompt_actions);
+}
+
static struct termios origianl_tios;

static void terminal_cleanup(void)
diff --git a/android/client/terminal.h b/android/client/terminal.h
index b5e402d..0e63936 100644
--- a/android/client/terminal.h
+++ b/android/client/terminal.h
@@ -57,5 +57,6 @@ int terminal_vprint(const char *format, va_list args);
void terminal_process_char(int c, line_callback process_line);
void terminal_insert_into_command_line(const char *p);
void terminal_draw_command_line(void);
+void terminal_prompt_for(const char *s, line_callback process_line);

void process_tab(const char *line, int len);
--
1.7.9.5


2013-11-08 12:48:26

by Jerzy Kasenberg

[permalink] [raw]
Subject: [PATCH 4/8] android/client: Add command line arguments

This patch adds command line argument parsing.
Options added:
-h, --help
-n, --no-init - disable initialization of interfaces
--version
---
android/client/haltest.c | 68 ++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 66 insertions(+), 2 deletions(-)

diff --git a/android/client/haltest.c b/android/client/haltest.c
index 107dfec..7154d27 100644
--- a/android/client/haltest.c
+++ b/android/client/haltest.c
@@ -23,6 +23,7 @@
#include <unistd.h>
#include <poll.h>
#include <unistd.h>
+#include <getopt.h>

#include "if-main.h"
#include "terminal.h"
@@ -222,7 +223,7 @@ const char *interface_name(void *v, int i)
/* Function to enumerate command and interface names */
const char *command_name(void *v, int i)
{
- int cmd_cnt = (int) (sizeof(commands)/sizeof(commands[0]) - 1);
+ int cmd_cnt = NELEM(commands);

if (i >= cmd_cnt)
return interface_name(v, i - cmd_cnt);
@@ -318,6 +319,65 @@ static void stdin_handler(struct pollfd *pollfd)
}
}

+static void usage(void)
+{
+ printf("haltest Android Bluetooth HAL testing tool\n"
+ "Usage:\n");
+ printf("\thaltest [options]\n");
+ printf("options:\n"
+ "\t-n, --no-init Don't call init for interfaces\n"
+ "\t --version Print version\n"
+ "\t-h, --help Show help options\n");
+}
+
+enum {
+ PRINT_VERSION = 1000
+};
+
+int version = 1;
+int revision = 0;
+
+static void print_version(void)
+{
+ printf("haltest version %d.%d\n", version, revision);
+}
+
+static const struct option main_options[] = {
+ { "no-init", no_argument, NULL, 'n' },
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, PRINT_VERSION },
+ { NULL }
+};
+
+static bool no_init = false;
+
+static void parse_command_line(int argc, char *argv[])
+{
+ for (;;) {
+ int opt;
+
+ opt = getopt_long(argc, argv, "nh", main_options, NULL);
+ if (opt < 0)
+ break;
+
+ switch (opt) {
+ case 'n':
+ no_init = true;
+ break;
+ case 'h':
+ usage();
+ exit(0);
+ case PRINT_VERSION:
+ print_version();
+ exit(0);
+ default:
+ putchar('\n');
+ exit(-1);
+ break;
+ }
+ }
+}
+
static void init(void)
{
static const char * const inames[] = {
@@ -356,8 +416,12 @@ int main(int argc, char **argv)
{
struct stat rcstat;

+ parse_command_line(argc, argv);
+
terminal_setup();
- init();
+
+ if (!no_init)
+ init();

history_restore(".haltest_history");

--
1.7.9.5


2013-11-08 12:48:24

by Jerzy Kasenberg

[permalink] [raw]
Subject: [PATCH 2/8] android/client: Add NELEM macro for count elements

NELEM macro will be used in several places.
---
android/client/if-main.h | 2 ++
1 file changed, 2 insertions(+)

diff --git a/android/client/if-main.h b/android/client/if-main.h
index 647162c..dea7237 100644
--- a/android/client/if-main.h
+++ b/android/client/if-main.h
@@ -144,6 +144,8 @@ struct method *get_command(const char *name);
const struct method *get_interface_method(const char *iname,
const char *mname);

+#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
+
/* Helper macro for executing function on interface and printing BT_STATUS */
#define EXEC(f, ...) \
{ \
--
1.7.9.5


2013-11-08 12:48:25

by Jerzy Kasenberg

[permalink] [raw]
Subject: [PATCH 3/8] android/client: Initialize all interfaces at start

Patch adds function that initializes all HAL interfaces.
---
android/client/haltest.c | 36 ++++++++++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)

diff --git a/android/client/haltest.c b/android/client/haltest.c
index f511025..107dfec 100644
--- a/android/client/haltest.c
+++ b/android/client/haltest.c
@@ -318,11 +318,47 @@ static void stdin_handler(struct pollfd *pollfd)
}
}

+static void init(void)
+{
+ static const char * const inames[] = {
+ BT_PROFILE_HANDSFREE_ID,
+ BT_PROFILE_ADVANCED_AUDIO_ID,
+ BT_PROFILE_HEALTH_ID,
+ BT_PROFILE_HIDHOST_ID,
+ BT_PROFILE_PAN_ID,
+#if PLATFORM_SDK_VERSION > 17
+ BT_PROFILE_GATT_ID,
+#endif
+ BT_PROFILE_SOCKETS_ID
+ };
+ const struct method *m;
+ const char *argv[4];
+ char init_line[] = "bluetooth init";
+ uint32_t i;
+
+ process_line(init_line);
+ m = get_interface_method("bluetooth", "get_profile_interface");
+
+ for (i = 0; i < NELEM(inames); ++i) {
+ argv[2] = inames[i];
+ m->func(3, argv);
+ }
+
+ /* Init what is available to init */
+ for (i = 1; i < NELEM(interfaces) - 1; ++i) {
+ m = get_interface_method(interfaces[i]->name, "init");
+ if (m != NULL)
+ m->func(2, argv);
+ }
+}
+
int main(int argc, char **argv)
{
struct stat rcstat;

terminal_setup();
+ init();
+
history_restore(".haltest_history");

fd_stack[fd_stack_pointer++] = 0;
--
1.7.9.5


2013-11-08 12:48:27

by Jerzy Kasenberg

[permalink] [raw]
Subject: [PATCH 5/8] android/client: Split terminal_process_char

This patch changes the way input characters are handled in function
terminal_process_char from big switch statement to smaller functions.
No functionality is changed in this patch.
Splitting to smaller functions will make easier to change behaviour
of terminal for prompt handling when user will be asked for something
and history substitution or auto completion will not be used.
---
android/client/terminal.c | 538 +++++++++++++++++++++++++++++----------------
android/client/terminal.h | 4 +-
2 files changed, 347 insertions(+), 195 deletions(-)

diff --git a/android/client/terminal.c b/android/client/terminal.c
index b152bf3..3674f89 100644
--- a/android/client/terminal.c
+++ b/android/client/terminal.c
@@ -118,6 +118,8 @@ static int line_len = 0;
static int line_index = 0;

static char prompt_buf[10] = "> ";
+static const char *const noprompt = "";
+static const char *current_prompt = prompt_buf;
static const char *prompt = prompt_buf;
/*
* Moves cursor to right or left
@@ -232,6 +234,7 @@ static void terminal_line_replaced(void)
/* set up indexes to new line */
line_len = strlen(line_buf);
line_buf_ix = line_len;
+ fflush(stdout);
}

static void terminal_clear_line(void)
@@ -365,217 +368,361 @@ static int terminal_convert_sequence(int c)
return c;
}

-void terminal_process_char(int c, void (*process_line)(char *line))
+typedef void (*terminal_action)(int c, line_callback process_line);
+
+#define TERMINAL_ACTION(n) \
+ static void n(int c, void (*process_line)(char *line))
+
+TERMINAL_ACTION(terminal_action_null)
{
- int refresh_from = -1;
- int old_pos;
+}

- c = terminal_convert_sequence(c);
+/* Mapping between keys and function */
+typedef struct {
+ int key;
+ terminal_action func;
+} KeyAction;
+
+int action_keys[] = {
+ KEY_SEQUNCE_NOT_FINISHED,
+ KEY_LEFT,
+ KEY_RIGHT,
+ KEY_HOME,
+ KEY_END,
+ KEY_DELETE,
+ KEY_CLEFT,
+ KEY_CRIGHT,
+ KEY_SUP,
+ KEY_SDOWN,
+ KEY_UP,
+ KEY_DOWN,
+ KEY_BACKSPACE,
+ KEY_INSERT,
+ KEY_PGUP,
+ KEY_PGDOWN,
+ KEY_CUP,
+ KEY_CDOWN,
+ KEY_SLEFT,
+ KEY_SRIGHT,
+ KEY_MLEFT,
+ KEY_MRIGHT,
+ KEY_MUP,
+ KEY_MDOWN,
+ KEY_STAB,
+ KEY_M_n,
+ KEY_M_p,
+ KEY_C_C,
+ KEY_C_D,
+ KEY_C_L,
+ '\t',
+ '\r',
+ '\n',
+};

- switch (c) {
- case KEY_SEQUNCE_NOT_FINISHED:
- break;
- case KEY_LEFT:
- /* if not at the beginning move to previous character */
- if (line_buf_ix <= 0)
- break;
- line_buf_ix--;
- terminal_move_cursor(-1);
- break;
- case KEY_RIGHT:
- /*
- * If not at the end, just print current character
- * and modify position
- */
- if (line_buf_ix < line_len)
- putchar(line_buf[line_buf_ix++]);
- break;
- case KEY_HOME:
- /* move to beginning of line and update position */
- printf("\r%s", prompt);
- line_buf_ix = 0;
- break;
- case KEY_END:
- /* if not at the end of line */
- if (line_buf_ix < line_len) {
- /* print everything from cursor */
- printf("%s", line_buf + line_buf_ix);
- /* just modify current position */
- line_buf_ix = line_len;
- }
- break;
- case KEY_DELETE:
- terminal_delete_char();
- break;
- case KEY_CLEFT:
+#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
+
+/*
+ * current_actions holds all recognizable kes and actions for them
+ * additional element (index 0) is used for default action
+ */
+static KeyAction current_actions[NELEM(action_keys) + 1];
+
+/* KeyAction comparator by key, for qsort and bsearch */
+static int KeyActionKeyCompare(const void *a, const void *b)
+{
+ return ((const KeyAction *) a)->key - ((const KeyAction *) b)->key;
+}
+
+/* Find action by key, NULL if no action for this key */
+static KeyAction *terminal_get_action(int key)
+{
+ KeyAction a = { .key = key };
+
+ return bsearch(&a, current_actions + 1, NELEM(action_keys), sizeof(a),
+ KeyActionKeyCompare);
+}
+
+/* Sets new set of actions to use */
+static void terminal_set_actions(const KeyAction *actions)
+{
+ int i;
+
+ /* Make map with empty function for every key */
+ for (i = 0; i < NELEM(action_keys); ++i) {
/*
- * Move by word left
- *
- * Are we at the beginning of line?
+ * + 1 due to 0 index reserved for default action that is
+ * called for non mapped key
*/
- if (line_buf_ix <= 0)
- break;
+ current_actions[i + 1].key = action_keys[i];
+ current_actions[i + 1].func = terminal_action_null;
+ }
+
+ /* Sort action from 1 (index 0 - default action) */
+ qsort(current_actions + 1, NELEM(action_keys), sizeof(KeyAction),
+ KeyActionKeyCompare);
+ /* Set default action (first in array) */
+ current_actions[0] = *actions++;
+
+ /* Copy rest of actions into their places */
+ for (; actions->key; ++actions) {
+ KeyAction *place = terminal_get_action(actions->key);
+
+ if (place)
+ place->func = actions->func;
+ }
+}
+
+TERMINAL_ACTION(terminal_action_left)
+{
+ /* if not at the beginning move to previous character */
+ if (line_buf_ix <= 0)
+ return;
+ line_buf_ix--;
+ terminal_move_cursor(-1);
+}
+
+TERMINAL_ACTION(terminal_action_right)
+{
+ /*
+ * If not at the end, just print current character
+ * and modify position
+ */
+ if (line_buf_ix < line_len)
+ putchar(line_buf[line_buf_ix++]);
+}
+
+TERMINAL_ACTION(terminal_action_home)
+{
+ /* move to beginning of line and update position */
+ printf("\r%s", prompt);
+ line_buf_ix = 0;
+}
+
+TERMINAL_ACTION(terminal_action_end)
+{
+ /* if not at the end of line */
+ if (line_buf_ix < line_len) {
+ /* print everything from cursor */
+ printf("%s", line_buf + line_buf_ix);
+ /* just modify current position */
+ line_buf_ix = line_len;
+ }
+}
+
+TERMINAL_ACTION(terminal_action_del)
+{
+ terminal_delete_char();
+}
+
+TERMINAL_ACTION(terminal_action_word_left)
+{
+ int old_pos;
+ /*
+ * Move by word left
+ *
+ * Are we at the beginning of line?
+ */
+ if (line_buf_ix <= 0)
+ return;

- old_pos = line_buf_ix;
+ old_pos = line_buf_ix;
+ line_buf_ix--;
+ /* skip spaces left */
+ while (line_buf_ix && isspace(line_buf[line_buf_ix]))
line_buf_ix--;
- /* skip spaces left */
- while (line_buf_ix && isspace(line_buf[line_buf_ix]))
- line_buf_ix--;
- /* skip all non spaces to the left */
- while (line_buf_ix > 0 &&
+
+ /* skip all non spaces to the left */
+ while (line_buf_ix > 0 &&
!isspace(line_buf[line_buf_ix - 1]))
- line_buf_ix--;
- /* move cursor to new position */
- terminal_move_cursor(line_buf_ix - old_pos);
- break;
- case KEY_CRIGHT:
- /*
- * Move by word right
- *
- * are we at the end of line?
- */
- if (line_buf_ix >= line_len)
- break;
+ line_buf_ix--;

- old_pos = line_buf_ix;
- /* skip all spaces */
- while (line_buf_ix < line_len &&
- isspace(line_buf[line_buf_ix]))
- line_buf_ix++;
- /* skip all non spaces */
- while (line_buf_ix < line_len &&
- !isspace(line_buf[line_buf_ix]))
- line_buf_ix++;
- /*
- * Move cursor to right by printing text
- * between old cursor and new
- */
- if (line_buf_ix > old_pos)
- printf("%.*s", (int) (line_buf_ix - old_pos),
+ /* move cursor to new position */
+ terminal_move_cursor(line_buf_ix - old_pos);
+}
+
+TERMINAL_ACTION(terminal_action_word_right)
+{
+ int old_pos;
+ /*
+ * Move by word right
+ *
+ * are we at the end of line?
+ */
+ if (line_buf_ix >= line_len)
+ return;
+
+ old_pos = line_buf_ix;
+ /* skip all spaces */
+ while (line_buf_ix < line_len && isspace(line_buf[line_buf_ix]))
+ line_buf_ix++;
+
+ /* skip all non spaces */
+ while (line_buf_ix < line_len && !isspace(line_buf[line_buf_ix]))
+ line_buf_ix++;
+ /*
+ * Move cursor to right by printing text
+ * between old cursor and new
+ */
+ if (line_buf_ix > old_pos)
+ printf("%.*s", (int) (line_buf_ix - old_pos),
line_buf + old_pos);
- break;
- case KEY_SUP:
- terminal_get_line_from_history(-1);
- break;
- case KEY_SDOWN:
- if (line_index > 0)
- terminal_get_line_from_history(0);
- break;
- case KEY_UP:
- terminal_get_line_from_history(line_index + 1);
- break;
- case KEY_DOWN:
- if (line_index > 0)
- terminal_get_line_from_history(line_index - 1);
- break;
- case '\n':
- case '\r':
- /*
- * On new line add line to history
- * forget history position
- */
- history_add_line(line_buf);
- line_len = 0;
- line_buf_ix = 0;
- line_index = -1;
- /* print new line */
- putchar(c);
- prompt = "";
- process_line(line_buf);
- /* clear current line */
- line_buf[0] = '\0';
- prompt = prompt_buf;
- printf("%s", prompt);
- break;
- case '\t':
- /* tab processing */
- process_tab(line_buf, line_buf_ix);
- break;
- case KEY_BACKSPACE:
- if (line_buf_ix <= 0)
- break;
+}

- if (line_buf_ix == line_len) {
- printf("\b \b");
- line_len = --line_buf_ix;
- line_buf[line_len] = 0;
- } else {
- putchar('\b');
- refresh_from = --line_buf_ix;
- line_len--;
- memmove(line_buf + line_buf_ix,
+TERMINAL_ACTION(terminal_action_history_begin)
+{
+ terminal_get_line_from_history(-1);
+}
+
+TERMINAL_ACTION(terminal_action_history_end)
+{
+ if (line_index > 0)
+ terminal_get_line_from_history(0);
+}
+
+TERMINAL_ACTION(terminal_action_history_up)
+{
+ terminal_get_line_from_history(line_index + 1);
+}
+
+TERMINAL_ACTION(terminal_action_history_down)
+{
+ if (line_index > 0)
+ terminal_get_line_from_history(line_index - 1);
+}
+
+TERMINAL_ACTION(terminal_action_tab)
+{
+ /* tab processing */
+ process_tab(line_buf, line_buf_ix);
+}
+
+
+TERMINAL_ACTION(terminal_action_backspace)
+{
+ if (line_buf_ix <= 0)
+ return;
+
+ if (line_buf_ix == line_len) {
+ printf("\b \b");
+ line_len = --line_buf_ix;
+ line_buf[line_len] = 0;
+ } else {
+ putchar('\b');
+ line_buf_ix--;
+ line_len--;
+ memmove(line_buf + line_buf_ix,
line_buf + line_buf_ix + 1,
line_len - line_buf_ix + 1);
- }
- break;
- case KEY_INSERT:
- case KEY_PGUP:
- case KEY_PGDOWN:
- case KEY_CUP:
- case KEY_CDOWN:
- case KEY_SLEFT:
- case KEY_SRIGHT:
- case KEY_MLEFT:
- case KEY_MRIGHT:
- case KEY_MUP:
- case KEY_MDOWN:
- case KEY_STAB:
- case KEY_M_n:
- /* Search history forward */
- terminal_match_hitory(false);
- break;
- case KEY_M_p:
- /* Search history backward */
- terminal_match_hitory(true);
- break;
- case KEY_C_C:
- terminal_clear_line();
- break;
- case KEY_C_D:
- if (line_len > 0) {
- terminal_delete_char();
- } else {
- puts("");
- exit(0);
- }
- break;
- case KEY_C_L:
- terminal_clear_screen();
- break;
- default:
- if (!isprint(c)) {
- /*
- * TODO: remove this print once all meaningful sequences
- * are identified
- */
- printf("char-0x%02x\n", c);
- break;
- }
-
- if (line_buf_ix < LINE_BUF_MAX - 1) {
- if (line_len == line_buf_ix) {
- putchar(c);
- line_buf[line_buf_ix++] = (char) c;
- line_len++;
- line_buf[line_len] = '\0';
- } else {
- memmove(line_buf + line_buf_ix + 1,
- line_buf + line_buf_ix,
- line_len - line_buf_ix + 1);
- line_buf[line_buf_ix] = c;
- refresh_from = line_buf_ix++;
- line_len++;
- }
- }
- break;
+ printf("%s \b", line_buf + line_buf_ix);
+ terminal_move_cursor(line_buf_ix - line_len);
}
+}

- if (refresh_from >= 0) {
- printf("%s \b", line_buf + refresh_from);
- terminal_move_cursor(line_buf_ix - line_len);
+TERMINAL_ACTION(terminal_action_find_history_forward)
+{
+ /* Search history forward */
+ terminal_match_hitory(false);
+}
+
+TERMINAL_ACTION(terminal_action_find_history_backward)
+{
+ /* Search history forward */
+ terminal_match_hitory(true);
+}
+
+TERMINAL_ACTION(terminal_action_ctrl_c)
+{
+ terminal_clear_line();
+}
+
+TERMINAL_ACTION(terminal_action_ctrl_d)
+{
+ if (line_len > 0) {
+ terminal_delete_char();
+ } else {
+ puts("");
+ exit(0);
}
+}
+
+TERMINAL_ACTION(terminal_action_clear_screen)
+{
+ terminal_clear_screen();
+}
+
+TERMINAL_ACTION(terminal_action_enter)
+{
+ /*
+ * On new line add line to history
+ * forget history position
+ */
+ history_add_line(line_buf);
+ line_len = 0;
+ line_buf_ix = 0;
+ line_index = -1;
+ /* print new line */
+ putchar(c);
+ prompt = noprompt;
+ process_line(line_buf);
+ /* clear current line */
+ line_buf[0] = '\0';
+ prompt = current_prompt;
+ printf("%s", prompt);
+}
+
+TERMINAL_ACTION(terminal_action_default)
+{
+ char str[2] = { c, 0 };
+
+ if (!isprint(c))
+ /*
+ * TODO: remove this print once all meaningful sequences
+ * are identified
+ */
+ printf("char-0x%02x\n", c);
+ else if (line_buf_ix < LINE_BUF_MAX - 1)
+ terminal_insert_into_command_line(str);
+}

- /* Flush output after all user input */
+static KeyAction normal_actions[] = {
+ { 0, terminal_action_default },
+ { KEY_LEFT, terminal_action_left },
+ { KEY_RIGHT, terminal_action_right },
+ { KEY_HOME, terminal_action_home },
+ { KEY_END, terminal_action_end },
+ { KEY_DELETE, terminal_action_del },
+ { KEY_CLEFT, terminal_action_word_left },
+ { KEY_CRIGHT, terminal_action_word_right },
+ { KEY_SUP, terminal_action_history_begin },
+ { KEY_SDOWN, terminal_action_history_end },
+ { KEY_UP, terminal_action_history_up },
+ { KEY_DOWN, terminal_action_history_down },
+ { '\t', terminal_action_tab },
+ { KEY_BACKSPACE, terminal_action_backspace },
+ { KEY_M_n, terminal_action_find_history_forward },
+ { KEY_M_p, terminal_action_find_history_backward },
+ { KEY_C_C, terminal_action_ctrl_c },
+ { KEY_C_D, terminal_action_ctrl_d },
+ { KEY_C_L, terminal_action_clear_screen },
+ { '\r', terminal_action_enter },
+ { '\n', terminal_action_enter },
+ { 0, NULL },
+};
+
+void terminal_process_char(int c, line_callback process_line)
+{
+ KeyAction *a;
+
+ c = terminal_convert_sequence(c);
+
+ /* Get action for this key */
+ a = terminal_get_action(c);
+
+ /* No action found, get default one */
+ if (a == NULL)
+ a = &current_actions[0];
+
+ a->func(c, process_line);
fflush(stdout);
}

@@ -589,6 +736,9 @@ static void terminal_cleanup(void)
void terminal_setup(void)
{
struct termios tios;
+
+ terminal_set_actions(normal_actions);
+
tcgetattr(0, &origianl_tios);
tios = origianl_tios;

diff --git a/android/client/terminal.h b/android/client/terminal.h
index e53750f..b5e402d 100644
--- a/android/client/terminal.h
+++ b/android/client/terminal.h
@@ -49,10 +49,12 @@ enum key_codes {
KEY_M_n
};

+typedef void (*line_callback)(char *);
+
void terminal_setup(void);
int terminal_print(const char *format, ...);
int terminal_vprint(const char *format, va_list args);
-void terminal_process_char(int c, void (*process_line)(char *line));
+void terminal_process_char(int c, line_callback process_line);
void terminal_insert_into_command_line(const char *p);
void terminal_draw_command_line(void);

--
1.7.9.5


2013-11-08 12:48:23

by Jerzy Kasenberg

[permalink] [raw]
Subject: [PATCH 1/8] android/client: Export get_interface_method

This method will be used outside tab completion.c.
---
android/client/if-main.h | 2 ++
android/client/tabcompletion.c | 2 +-
2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/android/client/if-main.h b/android/client/if-main.h
index f638b91..647162c 100644
--- a/android/client/if-main.h
+++ b/android/client/if-main.h
@@ -141,6 +141,8 @@ void add_remote_device(const bt_bdaddr_t *addr);
const struct interface *get_interface(const char *name);
struct method *get_method(struct method *methods, const char *name);
struct method *get_command(const char *name);
+const struct method *get_interface_method(const char *iname,
+ const char *mname);

/* Helper macro for executing function on interface and printing BT_STATUS */
#define EXEC(f, ...) \
diff --git a/android/client/tabcompletion.c b/android/client/tabcompletion.c
index 4a6329f..f965620 100644
--- a/android/client/tabcompletion.c
+++ b/android/client/tabcompletion.c
@@ -30,7 +30,7 @@ typedef struct split_arg {
} split_arg_t;

/* function returns method of given name or NULL if not found */
-static const struct method *get_interface_method(const char *iname,
+const struct method *get_interface_method(const char *iname,
const char *mname)
{
const struct interface *iface = get_interface(iname);
--
1.7.9.5