
		LCRASH sub-command line completion

		Naomi Haseo (naomi@pst.fujitsu.com)

		  Last Update: Nov 22, 2001

0. Introduction

LCRASH provides many sub-commands. And most of them have to be specified
some parameters such as a file name or a symbol name.

It's too inconvenient to remember sub-command names and their
parameters exactly.
So adding sub-command line completion can greatly help us investigating 
with LCRASH.

1. Overview

While editing sub-command line, if TAB key is pressed, LCRASH completes the 
line appropriately.

1.1. Complete sub-command name

LCRASH completes sub-command names with behavior almost equivalent to bash.

- When TAB key is pressed at the head of line, LCRASH prints the list of 
  sub-command names.
- When TAB key is pressed in the middle of the first word of line, LCRASH
  completes sub-command names.
	* When there is no candidate, LCRASH prints a BEEP character.
	* When there is only one candidate, LCRASH prints it.
	* When there are two or more candidates,
		+ When there is the identical string part of them, 
		  LCRASH prints the identical part.
		+ When there isn't the identical string part of them, 
		  LCRASH prints the list of them.

1.2. Complete sub-command's parameters

Each parameter of sub-commands has different characteristic.
So LCRASH provides facilities easily adding your own completion function.
Please see section 2 for more detail.

2. Adding your own completion function

You can add your own function which completes sub-command's parameters 
as follows:

  Step1: Write your own completion function for the sub-command you selected.

    You should name the function "'sub-command name'_complete", and
    add it to the file "lcrash/cmds/cmd_'sub-command name'.c".

    This function is called with the following API.

      char *'sub-command name'_complete(command_t *cmd)

    You can get various information with the command structure
    pointed to by cmd.

      cmd->command ... sub-command name
      cmd->nargs   ... the number of parameters
      cmd->args[]  ... the array of parameter names
      cmd->ofp     ... stream to where messages are printed
                       (stdout by default)

      Note:
        - In the args field, the args[0] points to first parameter name,
          not to sub-command name. The args[nargs-1] points to last
          parameter name.
        - The last parameter name is truncated by cursor position
          (See below examples).

      Examples:
      ------------------------------------------------------------------
        sub-command line                fields values
      ------------------------------------------------------------------
      - "findsym   kernel "             command:        "findsym"
                 ^  cursor              nargs:          1
                 +- position            args[0]:        null

      - "findsym   kernel "             command:        "findsym"
                   ^  cursor            nargs:          1
                   +- position          args[0]:        null

      - "findsym   kernel "             command:        "findsym"
                     ^  cursor          nargs:          1
                     +- position        args[0]:        "ke"

      - "findsym   kernel "             command:        "findsym"
                         ^  cursor      nargs:          1
                         +- position    args[0]:        "kernel"
      ------------------------------------------------------------------

    The function has to return one of the following values.

      a) The address of string
        The caller of this function will insert the string at cursor
        position and redraw it without printing newline.
        The memory region of the string has to be accessible after the
        function returned. So it has to be allocated statically.
        Note that the caller will not free it.

      b) DRAW_NEW_ENTER_LINE
        The caller of this function will print newline and redraw
        sub-command line.

      c) PRINT_BEEP
        The caller of this function will print a BEEP character.

    You can use the following common functions in your code.

      - char *complete_standard_options(command_t *cmd);

        This function completes a parameter of the standard option.
        At this point, only '-w' option is handled.

        The cmd parameter is the same as described above.

        This function returns one of the following values.

        a) The address of string
          The parameter was completed and the string to be inserted is 
          returned. This should be returned to the caller of your function
          without any changes.

        b) DRAW_NEW_ENTER_LINE
          The parameter wasn't completed but something happened (for
          example, printing out all candidates).
          This should be returned to the caller of your function
          without any changes.

        c) PRINT_BEEP
          The parameter wasn't completed but something happened (for 
          example, printing a BEEP character).
          This should be returned to the caller of your function
          without any changes.

        d) NOT_COMPLETED
          The parameter wasn't completed and nothing happened.
          Handling the completion has to be continued.

      - char *complete_symbol_name(char *keystr, int print_max_candt);

        This function completes the string pointed to by keystr as a
        symbol name.
        If there are many candidates and the number of them is more
        than print_max_candt, it confirms whether display all of them
        or not.

        This function returns one of the following values.

        a) The address of string
          The symbol name was completed and the string to be inserted is
          returned.

        b) DRAW_NEW_ENTER_LINE
          There were some candidates and they were printed out (or
          confirmed to print), so a newline should be printed out.

        c) PRINT_BEEP
          There is no candidate, so a BEEP character should be
          printed out.

      - char *complete_file_name(char *string, int print_max_candt);

        This function completes the string pointed to by string as a
        file name.
        This has the same functionality as complete_symbol_name()'s.

  Step2: Register your function

    In the cmdset[] of lcrash/cmds/cmds.c, find the record of the target
    sub-command and change the initial value of the cmdcomplete field to
    your function name.

3. Adding completion ability to FINDSYM sub-command

This section will show you an example of adding completion ability
to FINDSYM sub-command.

  Step1: We choose FINDSYM to add completion ability.
         And we wrote the code of findsym_complete() and added it to
         "lcrash/cmds/cmd_findsym.c"

    The usage of FINDSYM is as follows:

      findsym symname | symaddr [symname | symaddr [...] ]
              -f string [...] 
              [-w outfile]

    We'll add completion abilities as follows:
      - completes the parameter followed by '-w' as a file name.
      - completes the others as a symbol name.

    The function is written as follows:
  
    /*
     * findsym_complete() -- Complete arguments of 'findsym' command.
     */
    char *
    findsym_complete(command_t *cmd)
    {
      char *ret;
      int i;

      /* cmd->nargs is the number of arguments
       * cmd->args[] is the array of the arguments
       * so, the word to complete is cmd->args[cmd->nargs - 1]
       * cmd->ofp is stdout
       */
  
      /* first, complete the standard options (for example, -w option) 
       * arguments by the public function.
       */
      if ((ret = complete_standard_options(cmd)) != NOT_COMPLETED) {
        return(ret);
      }
      /* if the first character of the word is '-', 
       * print 'findsym' usage to stdout
       */
      if (cmd->args[cmd->nargs - 1] != 0 
        && cmd->args[cmd->nargs - 1][0] == '-') {
        fprintf(stdout, "\n");
        CMD_USAGE(cmd, _FINDSYM_USAGE);
        return(DRAW_NEW_ENTIRE_LINE);
      }
      if (cmd->nargs == 1) {
        /* if there is one argument, complete symbol name by the 
         * public function.
         * if the number of candidates is more 100, ask whether 
         * display or not the list of them.
         */
        return(complete_symbol_name(cmd->args[0], 100));
      } else {
        /* if there are two or more arguments */
        for (i = 0; i < cmd->nargs; i++) {
          if (!strcmp(cmd->args[i], "-f")) {
            /* don't complete the word following "-f" */
            return(PRINT_BEEP);
          }
        }
        /* complete symbol name by the public function */
        return(complete_symbol_name(cmd->args[cmd->nargs-1], 100));
      }
    }

  Step2: We registered findsym_complete() to cmdset[].
	
    findsym_complete() is defined in lcrash/cmds/cmds.c as follows:

      extern char *findsym_complete(command_t *); 

    The cmdcomplete field of findsym's record is changed from NULL to
    findsym_complete as follows:

      _command_t  cmdset[] = {
		:
        {"findsym", 0, findsym_cmd, findsym_parse, findsym_help, findsym_usage, findsym_complete},
		:

4. Design

This section will describe files and data structures that need to be
modified to implement sub-command line completion.

4.1. LCRASH Design details

4.1.1. Modified Files

The following files require changes to implement sub-command completion:

- lcrash/main.c
- lcrash/commondefs
- lcrash/include/command.h
- lcrash/cmds/command.c
- lcrash/cmds/cmds.c
- lcrash/cmds/cmd_findsym.c

4.1.2. New Files

The following files will be added to implement sub-command completion:

- lcrash/cmds/cmd-completion.txt

4.1.3. Modified Data Structures

The following existing data structures need to be altered to implement
sub-command completion:

- struct _command_t:    (lcrash/include/command.h)

  The following field is added and initialized to NULL.

    cmdcomplete_t   cmdcomplete; /* completion function */

- struct cmd_rec_t:    (lcrash/include/command.h)

  The following field is added and initialized to NULL.

    cmdcomplete_t   cmdcomplete; /* completion function */

4.1.4. Modified Functions

The following functions require changes to implement sub-command completion:

- main()    (lcrash/main.c)

  Call rl_register_complete_func() to register completion function to librl.

- register_cmds()    (lcrash/cmds/command.c)

  Add the initialization of the cmdcomplete field in the cmd_rec_t structure.

- get_cmd()    (lcrash/cmds/command.c)

  Split the block of parsing sub-command line and setting up the
  command structure into another function (line_to_words()).

4.1.5. New Functions

The following new functions will be added to implement sub-command completion:

- void line_to_words(command_t *);    (lcrash/cmds/command.c)

  Split sub-command line into sub-command name and parameters and set
  up the command structure.

- char *complete_cmds(char *, int);    (lcrash/cmds/command.c)

  Call line_to_words() to parse sub-command line.
  If cursor is on the first word
    Call complete_subcmd_name() to complete sub-command name.
  Else if the function which completes sub-command's parameters is registered
    Call the function to complete sub-command's parameters.

- char *complete_subcmd_name(char *);    (lcrash/cmds/command.c)

  Scan 'cmd_tree' and complete sub-command name.

- char *complete_standard_options(command_t *);    (lcrash/cmds/command.c)

  Complete the parameter followed by '-w' as a file name.

- char *complete_symbol_name(char *, int);    (lcrash/cmds/command.c)

  Call kl_get_similar_name() to get the candidates for completion and
  complete symbol name.

- char *complete_file_name(char *, int);    (lcrash/cmds/command.c)

  Scan file system and complete file name.

- char *findsym_complete(command_t *);    (lcrash/cmds/cmd_findsym.c)

  Complete the parameter followed by '-w' as a file name.
  Complete the others as a symbol name.

4.2. librl Design details

4.2.1. Modified Files

The following files require changes to implement sub-command completion:

- librl/rl.h
- librl/rl.c

4.2.2. Modified Functions

The following functions require changes to implement sub-command completion:
	
- getinput()    (librl/rl.c)

  If TAB character is pressed, return COMPLETE_LINE.

- getline()    (librl/rl.c)

  If getinput() returns COMPLETE_LINE
    Call (*rl_complete_func)().
    According to the return code, insert the string to sub-command
    line, print a BEEP character or redraw sub-command line with 
    printing newline.

4.2.3. New Functions

The following new functions will be added to implement sub-command completion:

- void rl_register_complete_func(rl_complete_func_t);    (librl/rl.c)

  Register the function which completes sub-command line.

4.3. libklib Design details

4.3.1. Modified Files

The following files require changes to implement sub-command completion:

- libklib/kl_symbol.c
- libklib/include/kl_sym.h

4.3.2. Modified Data Structures

The following existing data structures need to be altered to implement
sub-command completion:

- struct syment_t:    (libklib/include/kl_sym.h)

  The following field is added and initialized to NULL.

    struct syment_s    *s_forward; /* For linked lists */

4.3.3. New Functions

The following new functions will be added to implement sub-command completion:

- syment_t *kl_get_similar_name(char *, char *, int *, int *);    
  (libklib/kl_symbol.c)

 Scan all symnames of each maplist and make a list of the syment
 structure containing a match to the given name.

