This patch adds help and quit commands.
It also adds tab completion for commands (it used to work
for interfaces).
NULL
};
+static struct method commands[];
+
+struct method *get_method(struct method *methods, const char *name)
+{
+ while (strcmp(methods->name, "") != 0) {
+ if (strcmp(methods->name, name) == 0)
+ return methods;
+ methods++;
+ }
+ return NULL;
+}
+
+/* function returns interface of given name or NULL if not found */
+const struct interface *get_interface(const char *name)
+{
+ int i;
+
+ for (i = 0; interfaces[i] != NULL; ++i) {
+ if (strcmp(interfaces[i]->name, name) == 0)
+ break;
+ }
+
+ return interfaces[i];
+}
+
int haltest_error(const char *format, ...)
{
va_list args;
return ret;
}
+static void help_print_interface(const struct interface *i)
+{
+ struct method *m;
+
+ for (m = i->methods; strcmp(m->name, "") != 0; m++)
+ haltest_info("%s %s %s\n", i->name, m->name,
+ (m->help ? m->help : ""));
+}
+
+/* Help completion */
+static void help_c(int argc, const char **argv,
+ enum_func *penum_func, void **puser)
+{
+ if (argc == 2)
+ *penum_func = interface_name;
+}
+
+/* Help execution */
+static void help_p(int argc, const char **argv)
+{
+ const struct method *m = commands;
+ const struct interface **ip = interfaces;
+ const struct interface *i;
+
+ if (argc == 1) {
+ terminal_print("haltest allows to call Android HAL methods.\n");
+ terminal_print("\nAvailable commands:\n");
+ while (0 != strcmp(m->name, "")) {
+ terminal_print("\t%s %s\n", m->name,
+ (m->help ? m->help : ""));
+ m++;
+ }
+ terminal_print("\nAvailable interfaces to use:\n");
+ while (NULL != *ip) {
+ terminal_print("\t%s\n", (*ip)->name);
+ ip++;
+ }
+ terminal_print("\nTo get help on methods for each interface type:\n");
+ terminal_print("\n\thelp <inerface>\n");
+ terminal_print("\nBasic scenario:\n\tadapter init\n");
+ terminal_print("\tadapter enable\n\tadapter start_discovery\n");
+ terminal_print("\tadapter get_profile_interface handsfree\n");
+ terminal_print("\thandsfree init\n\n");
+ return;
+ }
+ i = get_interface(argv[1]);
+ if (i == NULL) {
+ haltest_error("No such interface\n");
+ return;
+ }
+ help_print_interface(i);
+}
+
+/* quit/exit execution */
+static void quit_p(int argc, const char **argv)
+{
+ exit(0);
+}
+
+/* Commands available without interface */
+static struct method commands[] = {
+ STD_METHODCH(help, "[<interface>]"),
+ STD_METHOD(quit),
+ METHOD("exit", quit_p, NULL, NULL),
+ END_METHOD
+};
+
+/* Gets comman by name */
+struct method *get_command(const char *name)
+{
+ return get_method(commands, name);
+}
+
+/* Function to enumerate interface names */
+const char *interface_name(void *v, int i)
+{
+ return interfaces[i] ? interfaces[i]->name : NULL;
+}
+
+/* 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);
+ if (i >= cmd_cnt)
+ return interface_name(v, i - cmd_cnt);
+ else
+ return commands[i].name;
+}
+
/*
* This function changes input parameter line_buffer so it has
* null termination after each token (due to strtok)
char *argv[10];
int argc;
int i = 0;
- int j;
+ struct method *m;
argc = command_line_to_argv(line_buffer, argv, 10);
if (argc < 1)
continue;
}
if (argc < 2 || strcmp(argv[1], "?") == 0) {
- struct method *m = &interfaces[i]->methods[0];
- while (strcmp(m->name, "")) {
- haltest_info("%s %s %s\n", argv[0],
- m->name,
- (m->help ? m->help : ""));
- m++;
- }
+ help_print_interface(interfaces[i]);
return;
}
- j = 0;
- while (strcmp(interfaces[i]->methods[j].name, "")) {
- if (strcmp(interfaces[i]->methods[j].name, argv[1])) {
- j++;
- continue;
- }
- interfaces[i]->methods[j].func(argc,
- (const char **)argv);
- break;
+ m = get_method(interfaces[i]->methods, argv[1]);
+ if (m != NULL) {
+ m->func(argc, (const char **) argv);
+ return;
}
- if (strcmp(interfaces[i]->methods[j].name, "") == 0)
- printf("No function %s found\n", argv[1]);
- break;
+ haltest_error("No function %s found\n", argv[1]);
+ return;
}
-
- if (interfaces[i] == NULL)
- printf("No such interface %s\n", argv[0]);
+ /* No interface, try commands */
+ m = get_command(argv[0]);
+ if (m == NULL)
+ haltest_error("No such command %s\n", argv[0]);
+ else
+ m->func(argc, (const char **) argv);
}
/* called when there is something on stdin */
* Enumerator for discovered devices, to be used as tab completion enum_func
*/
const char *enum_devices(void *v, int i);
+const char *interface_name(void *v, int i);
+const char *command_name(void *v, int i);
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);
+
/* Helper macro for executing function on interface and printing BT_STATUS */
#define EXEC(f, ...) \
{ \
char ntcopy[1]; /* null terminated copy of argument */
} split_arg_t;
-/* function returns interface of given name or NULL if not found */
-static const struct interface *get_interface(const char *name)
-{
- int i;
-
- for (i = 0; interfaces[i] != NULL; ++i) {
- if (strcmp(interfaces[i]->name, name) == 0)
- break;
- }
-
- return interfaces[i];
-}
-
/* function returns method of given name or NULL if not found */
-static const struct method *get_method(const char *iname, const char *mname)
+static const struct method *get_interface_method(const char *iname,
+ const char *mname)
{
- int i;
const struct interface *iface = get_interface(iname);
if (iface == NULL)
return NULL;
- for (i = 0; iface->methods[i].name[0]; ++i) {
- if (0 == strcmp(iface->methods[i].name, mname))
- return &iface->methods[i];
- }
- return NULL;
+ return get_method(iface->methods, mname);
}
/* prints matching elements */
return argc;
}
-/* Function to enumerate interface names */
-static const char *interface_name(void *v, int i)
-{
- return interfaces[i] ? interfaces[i]->name : NULL;
-}
-
/* Function to enumerate method names */
static const char *methods_name(void *v, int i)
{
/*
* complete command line
*/
-static void command_completion(struct command_completion_args *args)
+static void tab_completion(struct command_completion_args *args)
{
const char *name = args->typed;
const int len = strlen(name);
}
/* interface completion */
-static void interface_completion(split_arg_t *arg)
+static void command_completion(split_arg_t *arg)
{
struct command_completion_args args = {
.arg = arg,
.typed = arg->ntcopy,
- .func = interface_name
+ .func = command_name
};
- command_completion(&args);
+ tab_completion(&args);
}
/* method completion */
if (iface == NULL)
return;
- command_completion(&args);
+ tab_completion(&args);
+}
+
+static const char *bold = "\x1b[1m";
+static const char *normal = "\x1b[0m";
+
+static bool find_nth_argument(const char *str, int n,
+ const char **s, const char **e)
+{
+ const char *p = str;
+ int argc = 0;
+ *e = NULL;
+
+ while (p != NULL && *p != 0) {
+
+ while (isspace(*p))
+ ++p;
+
+ if (n == argc)
+ *s = p;
+
+ if (*p == '[') {
+ p = strchr(p, ']');
+ if (p != NULL)
+ *e = ++p;
+ } else if (*p == '<') {
+ p = strchr(p, '>');
+ if (p != NULL)
+ *e = ++p;
+ } else {
+ *e = strchr(p, ' ');
+ if (*e == NULL)
+ *e = p + strlen(p);
+ p = *e;
+ }
+
+ if (n == argc)
+ break;
+
+ argc++;
+ *e = NULL;
+ }
+ return *e != NULL;
}
/* prints short help on method for interface */
static void method_help(struct command_completion_args *args)
{
+ int argc;
+ const split_arg_t *arg = args->arg;
+ const char *sb = NULL;
+ const char *eb = NULL;
+ const char *arg1 = "";
+ int arg1_size = 0; /* size of method field (for methods > 0) */
+
if (args->user_help == NULL)
return;
- haltest_info("%s %s %s\n", args->arg->ntcopy,
- args->arg->next->ntcopy, args->user_help);
+ for (argc = 0; arg != NULL; argc++)
+ arg = arg->next;
+
+ /* Check if this is method from interface */
+ if (get_command(args->arg->ntcopy) == NULL) {
+ /* if so help is missing interface and method name */
+ arg1 = args->arg->next->ntcopy;
+ arg1_size = strlen(arg1) + 1;
+ }
+
+ find_nth_argument(args->user_help, argc - (arg1_size ? 3 : 2),
+ &sb, &eb);
+
+ if (eb != NULL)
+ haltest_info("%s %-*s%.*s%s%.*s%s%s\n", args->arg->ntcopy,
+ arg1_size, arg1,
+ sb - (const char *) args->user_help,
+ args->user_help,
+ bold, eb - sb, sb, normal, eb);
+ else
+ haltest_info("%s %-*s%s\n", args->arg->ntcopy,
+ arg1_size, arg1, args->user_help);
}
/* So we have empty enumeration */
return NULL;
}
-/* parameter completion function */
-static void param_completion(int argc, const split_arg_t *arg)
+/*
+ * parameter completion function
+ * argc - number of elements in arg list
+ * arg - list of arguments
+ * megthod - method to get completion from (can be NULL)
+ */
+static void param_completion(int argc, const split_arg_t *arg,
+ const struct method *method, int hlpix)
{
- const struct method *method;
int i;
const char *argv[argc];
const split_arg_t *tmp = arg;
tmp = tmp->next;
}
- /* Find method for <interface, name> pair */
- method = get_method(argv[0], argv[1]);
-
if (method != NULL && method->complete != NULL) {
/* ask method for completion function */
method->complete(argc, argv, &args.func, &args.user);
args.help = method_help;
args.user_help = (void *) method->help;
- command_completion(&args);
+ tab_completion(&args);
}
}
{
int argc;
static split_arg_t buf[(LINE_BUF_MAX * 2) / sizeof(split_arg_t)];
+ const struct method *method;
argc = split_command(line, len, buf, sizeof(buf));
tab_hit_count++;
- if (argc == 1)
- interface_completion(buf);
- else if (argc == 2)
+ if (argc == 0)
+ return;
+
+ if (argc == 1) {
+ command_completion(buf);
+ return;
+ }
+ method = get_command(buf[0].ntcopy);
+ if (method != NULL) {
+ param_completion(argc, buf, method, 1);
+ } else if (argc == 2) {
method_completion(get_interface(buf[0].ntcopy), buf);
- else if (argc > 2)
- param_completion(argc, buf);
+ } else {
+ /* Find method for <interface, name> pair */
+ method = get_interface_method(buf[0].ntcopy,
+ buf[0].next->ntcopy);
+ param_completion(argc, buf, method, 2);
+ }
}