/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2013 by Delphix. All rights reserved.
* Copyright (c) 2012 Joyent, Inc. All rights reserved.
* Copyright (c) 2013 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
*/
/*
* This file contains all of the interfaces for mdb's tab completion engine.
* Currently some interfaces are private to mdb and its internal implementation,
* those are in mdb_tab.h. Other pieces are public interfaces. Those are in
* mdb_modapi.h.
*
* Memory allocations in tab completion context have to be done very carefully.
* We need to think of ourselves as the same as any other command that is being
* executed by the user, which means we must use UM_GC to handle being
* interrupted.
*/
#include <mdb/mdb_modapi.h>
#include <mdb/mdb_ctf_impl.h>
#include <mdb/mdb_string.h>
#include <mdb/mdb_module.h>
#include <mdb/mdb_debug.h>
#include <mdb/mdb_print.h>
#include <mdb/mdb_target.h>
#include <ctype.h>
/*
* There may be another way to do this, but this works well enough.
*/
/*
* find_command_start --
*
* Given a buffer find the start of the last command.
*/
static char *
{
return (NULL);
for (;;) {
return (offset);
}
}
}
/*
* get_dcmd --
*
* Given a buffer containing a command and its argument return
* the name of the command and the offset in the buffer where
* the command arguments start.
*
* Note: This will modify the buffer.
*/
char *
{
separator++;
} else {
space = 1;
*separator++ = '\0';
}
if (space)
*flags |= DCMD_TAB_SPACE;
return (start);
}
/*
* count_args --
*
* Given a buffer containing dmcd arguments return the total number
* of arguments.
*
* While parsing arguments we need to keep track of whether or not the last
* arguments ends with a trailing space.
*/
static int
{
const char *index;
int argc = 0;
while (*index != '\0') {
index++;
space = 1;
}
argc++;
space = 0;
index++;
}
}
}
if (space)
*flags |= DCMD_TAB_SPACE;
else
*flags &= ~DCMD_TAB_SPACE;
return (argc);
}
/*
* copy_args --
*
* Given a buffer containing dcmd arguments and an array of mdb_arg_t's
* initialize the string value of each mdb_arg_t.
*
* Note: This will modify the buffer.
*/
static int
{
int i = 0;
char *index;
while (*index) {
index++;
}
end++;
}
if (*end) {
*end++ = '\0';
}
i++;
}
}
if (i != argc)
return (-1);
return (0);
}
/*
* parse-buf --
*
* Parse the given buffer and return the specified dcmd, the number
* of arguments, and array of mdb_arg_t containing the argument
* values.
*
* Note: this will modify the specified buffer. Caller is responisble
* for freeing argvp.
*/
static int
{
int argc = 0;
return (-1);
}
return (-1);
}
if (argc != 0) {
return (-1);
}
}
return (0);
}
/*
* tab_command --
*
* This function is executed anytime a tab is entered. It checks
* the current buffer to determine if there is a valid dmcd,
* if that dcmd has a tab completion handler it will invoke it.
*
* This function returns the string (if any) that should be added to the
* existing buffer to complete it.
*/
int
{
char *data;
int argc = 0;
int ret = 0;
/*
* Parsing the command and arguments will modify the buffer
* (replacing spaces with \0), so make a copy of the specified
* buffer first.
*/
/*
* Get the specified dcmd and arguments from the buffer.
*/
/*
* Match against global symbols if the input is not a dcmd
*/
if (ret != 0) {
goto out;
}
/*
* Check to see if the buffer contains a valid dcmd
*/
/*
* When argc is zero it indicates that we are trying to tab complete
* a dcmd or a global symbol. Note, that if there isn't the start of
* a dcmd, i.e. ::, then we will have already bailed in the call to
* tab_parse_buf.
*/
goto out;
}
/*
* Invoke the command specific tab completion handler or the built in
* dcmd one if there is no dcmd.
*/
else
out:
return (mdb_tab_size(mcp));
}
static int
{
/*
* The way that mdb is implemented, even commands like $C will show up
* here. As such, we don't want to match anything that doesn't start
* with an alpha or number. While nothing currently appears (via a
* cursory search with mdb -k) to start with a capital letter or a
* number, we'll support them anyways.
*/
return (0);
return (0);
}
int
{
return (0);
}
static int
{
return (0);
}
int
{
return (0);
}
mdb_tab_init(void)
{
return (mcp);
}
{
}
/*
* Determine whether the specified name is a valid tab completion for
* the given command. If the name is a valid tab completion then
* it will be saved in the mdb_tab_cookie_t.
*/
void
{
mdb_var_t *v;
/*
* If we have a match set, then we want to verify that we actually match
* it.
*/
return;
if (v != NULL)
return;
if (matches == 1) {
} else {
index = 0;
index++;
}
}
/*ARGSUSED*/
static int
{
return (0);
}
void
{
}
const char *
{
blen = 0;
else
}
void
{
}
/*
* This function is currently a no-op due to the fact that we have to GC because
* we're in command context.
*/
/*ARGSUSED*/
void
{
}
/*ARGSUSED*/
static int
{
return (0);
}
/*
* This function tab completes against all loaded global symbols.
*/
int
{
return (0);
}
/*
* This function takes a ctf id and determines whether or not the associated
* type should be considered as a potential match for the given tab
* completion command. We verify that the type itself is valid
* for completion given the current context of the command, resolve
* its actual name, and then pass it off to mdb_tab_insert to determine
* if it's an actual match.
*/
static int
{
int rkind;
/*
* CTF data includes types that mdb commands don't understand. Before
* we resolve the actual type prune any entry that is a type we
* don't care about.
*/
switch (mdb_ctf_type_kind(id)) {
case CTF_K_CONST:
case CTF_K_RESTRICT:
case CTF_K_VOLATILE:
return (0);
}
return (1);
rkind != CTF_K_UNION)
return (0);
return (0);
return (0);
return (0);
}
/*ARGSUSED*/
static int
{
return (0);
}
int
{
mcp);
return (0);
}
/*ARGSUSED*/
static int
{
return (0);
}
int
const char *member)
{
return (0);
}
int
const char *member)
{
return (-1);
}
int
{
int ret;
return (0);
if (argc == 0)
return (ret);
if (argc == 2)
return (0);
}
/*
* This is similar to mdb_print.c's args_to_typename, but it has subtle
* differences surrounding how the strings of one element are handled that have
* 'struct', 'enum', or 'union' in them and instead works with them for tab
* completion purposes.
*/
int
{
return (DCMD_USAGE);
if (argc == 1) {
return (1);
}
return (DCMD_USAGE);
} else {
}
return (0);
}