Logo Search packages:      
Sourcecode: lcrash version File versions  Download package

command.c

/*
 * $Id: command.c,v 1.1 2004/12/21 23:26:19 tjm Exp $
 *
 * This file is part of lcrash, an analysis tool for Linux memory dumps.
 *
 * Created by Silicon Graphics, Inc.
 * Contributions by IBM, and others
 *
 * Copyright (C) 1999 - 2002 Silicon Graphics, Inc. All rights reserved.
 * Copyright (C) 2001, 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version. See the file COPYING for more
 * information.
 */

#include <lcrash.h>
#include <setjmp.h>
#include <strings.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>

cmd_rec_t *cmd_tree = (cmd_rec_t *)0;
extern jmp_buf klib_jbuf;
extern char ql_have_terminal;

/*
 * register_cmds()
 */
int
register_cmds(_command_t cmds[])
{
      int i = 0, ret;
      cmd_rec_t *cmd_rec, **tmp_tree = &cmd_tree;

      while(cmds[i].cmd) {
            cmd_rec = (cmd_rec_t *)
                  kl_alloc_block(sizeof(*cmd_rec), K_PERM);
            cmd_rec->CMD_NAME = cmds[i].cmd;
            if (cmds[i].real_cmd) {
                  cmd_rec->real_cmd = (cmd_rec_t *)
                        kl_find_btnode((btnode_t *)cmd_tree, 
                        cmds[i].real_cmd, 0);
                  if (!cmd_rec->real_cmd) {
                        fprintf(KL_ERRORFP, "%s not found for "
                              "alias %s!\n", cmds[i].real_cmd, 
                              cmds[i].cmd);
                        i++;
                        continue;
                  } 
            } else {
                  cmd_rec->cmdfunc = cmds[i].cmdfunc;
                  cmd_rec->cmdparse = cmds[i].cmdparse;
                  cmd_rec->cmdhelp = cmds[i].cmdhelp;
                  cmd_rec->cmdusage = cmds[i].cmdusage;
                  cmd_rec->cmdcomplete = cmds[i].cmdcomplete;
            }
            ret = kl_insert_btnode((btnode_t **)tmp_tree,
                        (btnode_t *)cmd_rec, 0);
            if (ret == -1) {
                  fprintf(KL_ERRORFP, "%s is a duplicate cmd!\n",
                        cmd_rec->CMD_NAME);
                  kl_free_block(cmd_rec);
            }     
            i++;
      }
      return(0);
}

/*
 * unregister_cmds()
 */
void
unregister_cmd(char *name)
{
      cmd_rec_t *cmd_rec=find_cmd_rec(name);
      cmd_rec_t **tmp_tree = &cmd_tree;

      if(cmd_rec) {

            kl_delete_btnode((btnode_t **)tmp_tree, (btnode_t *)cmd_rec, 0, 0);
            kl_free_block(cmd_rec);
      }
}

/*
 * find_cmd_rec()
 */
cmd_rec_t *
find_cmd_rec(char *name) 
{
      cmd_rec_t *cmd_rec;

      cmd_rec = (cmd_rec_t *)kl_find_btnode((btnode_t *)cmd_tree, name, 0);
      return(cmd_rec);
}

/*
 * first_cmd_rec()
 */
cmd_rec_t *
first_cmd_rec()
{
      cmd_rec_t *crp;

      crp = (cmd_rec_t *)kl_first_btnode((btnode_t *)cmd_tree);
      return(crp);
}

/*
 * last_cmd_rec()
 */
cmd_rec_t *
last_cmd_rec()
{
      cmd_rec_t *crp = (cmd_rec_t *)NULL, *ncrp;

      ncrp = first_cmd_rec();
      while (ncrp) {
            crp = ncrp;
            ncrp = next_cmd_rec(crp);
      }
      return(crp);
}

/*
 * next_cmd_rec()
 */
cmd_rec_t *
next_cmd_rec(cmd_rec_t *crp)
{
      cmd_rec_t *ncrp;

      ncrp = (cmd_rec_t *)kl_next_btnode((btnode_t *)crp);
      return(ncrp);
}

/*
 * prev_cmd_rec()
 */
cmd_rec_t *
prev_cmd_rec(cmd_rec_t *crp)
{
      crp = (cmd_rec_t *)kl_prev_btnode((btnode_t *)crp);
      return(crp);
}

/*
 * clean_cmd()
 */
static void
clean_cmd(command_t *cmd)
{
      option_t *op, *opnext;

      if (!cmd) {
            return;
      }
      if (cmd->ofp && (cmd->ofp != stdout)) {
            /* reset libklib out stream */
            kl_set_stdout(stdout);
            fclose(cmd->ofp);
      }
      op = cmd->options;
      while (op) {
            opnext = op->op_next;
            kl_free_block(op);
            op = opnext;
      }
      if (cmd->pipe_cmd) {
            kl_free_block(cmd->pipe_cmd);
      }
      memset(cmd, 0, sizeof(*cmd));
}

/*
 * line_to_words()
 */
void
line_to_words(command_t *cmd)
{
      int i;
      char *cp, *ecp;

      i = 0;
      /* Get the command name. Make sure we strip off any 
       * leading blank space
       */
      while (*cmd->command == ' ') {
            cmd->command++;
      }
      cp = cmd->command;
      while (*cp != ' ') {
            if (!(*cp)) {
                  cmd->args[0] = 0;
                  cmd->nargs = 0;
                  return;
            }     
            cp++;
      }
      *cp++ = 0;
      cmd->cmdline = cp;

      /* Parse the remainder of the cmdline and separate into arguments. 
       * If an argument begins with a double quote ('"'), include all 
       * text through the next double quote (or end of line) in the 
       * argument.
       */
      while (*cp == ' ') {
            cp++;
      }
      if (!(*cp)) {
            cmd->args[0] = 0;
            cmd->nargs = 0;
            return;
      }

      /* Now get the arguments (if there are any)
       */
      while (*cp) {
            if (i == MAX_ARGS) {
                  fprintf(KL_ERRORFP, "Too many command line "
                        "arguments!\n");
                  cmd->nargs = i;
                  return;
            }
            if (*cp == '\"') {
                  ecp = cp + 1;
                  while (*ecp != '\"') {
                        if (!(*ecp)) {
                              break;
                        }
                        ecp++;
                  }
                  ecp++;
            } else {
                  ecp = cp;

                  /* Step over the non-blank characters
                   */
                  while (*ecp != ' ') {
                        if (!(*ecp)) {
                              break;
                        }
                        ecp++;
                  }
            }
            cmd->args[i] = cp;
            cp = ecp;
            if (*ecp) { 
                  *ecp = 0; 
                  cp++; 
            }
            i++;

            /* If we have reached the end of the input line then
             * return.
             */
            if (!(*cp)) {
                  if (i <= MAX_ARGS) {
                        cmd->args[i] = 0;
                  }
                  cmd->nargs = i;
                  return;
            }

            while (*cp == ' ') {
                  cp++;
            }
      }
      cmd->args[i] = 0;
      cmd->nargs = i;
}

/*
 * get_cmd()
 */
static void
get_cmd(command_t *cmd)
{
      int len;
      char *empty="";
      char *rl_getline(void);
      
      static char cmd_buf[256];

      clean_cmd(cmd);
      cmd->ofp = stdout;
      cmd->efp = stderr;
      
      if (!ql_have_terminal) {
            fprintf(stdout, "\n>> ");
            fflush(stdout);
            
            if (fgets(cmd_buf, sizeof(cmd_buf), stdin) == NULL) {
                  /* stdin closed */
                  exit(0);
            }
            else { /* get rid off the newline character */
                  len = strlen(cmd_buf);
                  cmd_buf[len - 1] = '\0';
                  cmd->command = cmd_buf;
            }
      }
      else {
            /* if we hit EOT we take that as a empty command line ]
             */
            if(!(cmd->command = rl_getline())) {
                  cmd->command = empty;
            }
      }
      strncpy(cmd->cmdstr, cmd->command, MAX_CMDLINE);
      line_to_words(cmd);
}

/*
 * parse_options()
 */
static int
parse_options(command_t *cmd, char *optstr, int flags)
{
      char *cp;
      int extra, i = 0, j;
      option_t *op = 0;

      while (cmd->args[i]) {
            extra = 0;
            if (cmd->args[i][0] == '-') {
                  if (strlen(cmd->args[i]) == 1) {
                        if (flags & C_NO_OPCHECK) {
                              i++;
                              continue;
                        }
                        fprintf(KL_ERRORFP, "Option letter missing\n"); 
                        return(1);
                  } else if ((cp = strchr(optstr, cmd->args[i][1]))) {
                        if (op) {
                              op->op_next = (option_t *)
                                    kl_alloc_block(sizeof(*op), 
                                    K_TEMP);
                              op = op->op_next;
                        } else {
                              op = (option_t *)
                                    kl_alloc_block(sizeof(*op),
                                    K_TEMP);
                              cmd->options = op;
                        }     
                        op->op_char = *cp;
                        if (*(cp+1) == ':') {
                              if (i == (cmd->nargs - 1)) {
                                    fprintf(KL_ERRORFP, 
                                          "Argument missing for "
                                          "command line option: "
                                          "\'%c\'\n", *cp);
                                    return(1);
                              }
                              if (cmd->args[i+1]) {
                                    if (cmd->args[i+1][0] != '-') {
                                          op->op_arg = 
                                                cmd->args[i+1];   
                                          extra++;
                                    } else {
                                          fprintf(KL_ERRORFP, 
                                          "Argument missing for "
                                          "command line option: "
                                          "\'%c\'.\n", *cp);
                                          return(1);
                                    }
                              }
                        }
                  } else {
                        if (flags & C_NO_OPCHECK) {
                              i++;
                              continue;
                        }
                        fprintf(KL_ERRORFP, "Illegal command line "
                              "option: \'%c\'\n", cmd->args[i][1]);
                        return(1);
                  }
                  for (j = i; j < cmd->nargs - extra; j++) {
                        cmd->args[j] = cmd->args[j + 1 + extra];
                  }
                  cmd->nargs -= (1 + extra);
            } else if (cmd->args[i][0] == '|') {
                  if ((cmd->nargs == 1) && !cmd->args[i][1]) {
                        fprintf(KL_ERRORFP, "No arguments to "
                              "pipe cmd\n");
                        return(1);
                        
                  }
                  cmd->pipe_cmd = 
                        (char *)kl_alloc_block(MAX_CMDLINE, K_TEMP);
                  if (klib_error) {
                        fprintf(KL_ERRORFP, "Could not allocate pipe "
                              "cmdline\n");
                        return(1);
                  }
                  if (strlen(cmd->args[i]) == 1) {
                        strcpy(cmd->pipe_cmd, cmd->args[i + 1]);
                        strcat(cmd->pipe_cmd, " ");
                        for (j = i + 2; j < cmd->nargs; j++) {
                              strcat(cmd->pipe_cmd, cmd->args[j]);
                              cmd->args[j] = 0;
                              if (j < cmd->nargs - 1) {
                                    strcat(cmd->pipe_cmd, " ");
                              }
                        }
                  } else {
                        strcpy(cmd->pipe_cmd, &cmd->args[i][1]);
                        strcat(cmd->pipe_cmd, " ");
                        for (j = i + 1; j < cmd->nargs; j++) {
                              strcat(cmd->pipe_cmd, cmd->args[j]);
                              cmd->args[j] = 0;
                              if (j < cmd->nargs - 1) {
                                    strcat(cmd->pipe_cmd, " ");
                              }
                        }
                  }
                  cmd->args[i] = 0;
                  cmd->nargs -= (cmd->nargs - i);
                  if ((cmd->ofp = popen(cmd->pipe_cmd, "w")) == NULL) {
                        fprintf(KL_ERRORFP, "Could not open pipe\n");
                        return (1);
                  }
                  setbuf(cmd->ofp, NULL);
                  kl_set_stdout(cmd->ofp);
                  return(0);
            } else {
                  i++;
            }
      }
      return(0);
}

/*
 * do_cmd()
 */
void
do_cmd(command_t *cmd)
{
      cmd_rec_t *cmd_rec;
      cmdfunc_t cmdfunc;
      cmdparse_t cmdparse;
      cmdhelp_t cmdhelp;
      cmdusage_t cmdusage;

      if (cmd->command[0]) {
            cmd_rec = find_cmd_rec(cmd->command);
            if (cmd_rec) {
                  if (cmd_rec->real_cmd) {
                        cmdfunc = cmd_rec->real_cmd->cmdfunc;
                        cmdparse = cmd_rec->real_cmd->cmdparse;
                        cmdusage = cmd_rec->real_cmd->cmdusage;
                        cmdhelp = cmd_rec->real_cmd->cmdhelp;
                  } else {
                        cmdfunc = cmd_rec->cmdfunc;
                        cmdparse = cmd_rec->cmdparse;
                        cmdusage = cmd_rec->cmdusage;
                        cmdhelp = cmd_rec->cmdhelp;
                  }     
                  
                  if ((cmdparse)(cmd)) {
                        (cmdusage)(cmd);
                  } else {
                        (cmdfunc)(cmd);
                  }
            } else {
                  fprintf(KL_ERRORFP, "unknown command\n");
            }
      } 
}

/*
 * process_cmds()
 */
int
process_cmds()
{
      command_t *cmd;
      
      if ((cmd = (command_t *)kl_alloc_block(sizeof(*cmd), K_PERM)) == NULL) {
            return(1);
      }
      while(1) {
              if (setjmp(klib_jbuf)) {
                  clean_cmd(cmd);
                  free_temp_blocks();
            }
            /* Reset global error status */
            kl_reset_error();
            get_cmd(cmd);
            do_cmd(cmd);
            clean_cmd(cmd);
            free_temp_blocks();
            iter_threshold = def_iter_threshold;
      }
}

/*
 * set_cmd_flags()
 */
int
set_cmd_flags(command_t *cmd, int flags, char *extraops)
{
      int i = 0, have_args = 0;
      char optstr[25];
      option_t *op;
      FILE *ofp;

      /* If more than one flag is set, we go with the most restrictive
       */
      if (flags & C_FALSE) {
            have_args = C_FALSE;
      } else if (flags & C_TRUE) {
            have_args = C_TRUE;
      } 

      /* Check for standard flags
       */
      if (flags & C_ALL) {
            optstr[i++] = 'a';
      }
      if (flags & C_FULL) {
            optstr[i++] = 'f';
      }
      if (flags & C_LIST) {
            optstr[i++] = 'l';
      }
      if (flags & C_NEXT) {
            optstr[i++] = 'n';
      }
      if (flags & C_WRITE) {
            optstr[i++] = 'w';
            optstr[i++] = ':';
      }
      optstr[i] = 0;

      /* Add any user defined options
       */
      if (extraops) {
            strcat(optstr, extraops);
      }

      if (parse_options(cmd, optstr, flags)) {
            return(1);
      }

      if ((have_args == C_TRUE) && (cmd->nargs  == 0)) {
            fprintf(KL_ERRORFP, "Command requires arguments\n"); 
            return(1);  
      }
      if ((have_args == C_FALSE) && cmd->nargs) {
            fprintf(KL_ERRORFP, "Command does not take any arguments\n"); 
            return(1);  
      }

      /* Now set flags for any of the standard options
       */
      op = cmd->options;
      while (op) {
            switch (op->op_char) {
                  case 'a':
                        cmd->flags |= C_ALL;
                        break;

                  case 'f':
                        cmd->flags |= C_FULL;
                        break;

                  case 'l':
                        cmd->flags |= C_LIST;
                        break;

                  case 'n':
                        cmd->flags |= C_NEXT;
                        break;

                  case 'w':
                        /* Check for pipe cmd output (it wont work 
                         * with -w option)
                         */
                        if (cmd->pipe_cmd) {
                              fprintf(KL_ERRORFP, "Cannot use -w "
                              "command line option when output has "
                              "bnen redirected to a pipe\n");
                              return(1);
                        }
                        ofp = fopen(op->op_arg, "a");
                        if (ofp == (FILE*)0) {
                              fprintf(KL_ERRORFP, "Cannot open file "
                                    ":%s\n", op->op_arg);
                        }
                        cmd->ofp = ofp;
                        fprintf(cmd->ofp, ">> %s\n", cmd->cmdstr);
                        /* redirect libklib messages */
                        kl_set_stdout(ofp);
            }
            op = op->op_next;
      }
      return(0);
}

#define INDENT_STR "    "

/*
 * helpformat() -- String format a line to within N - 3 characters, where
 *                 N is based on the winsize.  Return an allocated string.
 *                 Note that this string must be freed up when completed.
 */
char *
helpformat(char *helpstr)
{
      int indentsize = 0, index = 0, tmp = 0, col = 0;
      char *t, buf[1024];
      struct winsize w;

      /* if NULL string, return 
       */
      if (!helpstr) {
            return ((char *)0);
      }

      /* get the window size 
       */
      if (ioctl(fileno(stdout), TIOCGWINSZ, &w) < 0) {
            w.ws_col = 80;
      }

      indentsize = strlen(INDENT_STR);

      /* set up buffer plus a little extra for carriage returns, if needed 
       */
      t = (char *)kl_alloc_block(strlen(helpstr) + 256, K_TEMP);
      memset(t, 0, strlen(helpstr) + 256);

      /* Skip all initial whitespace -- do the indentions by hand. 
       */
      while (helpstr && isspace(*helpstr)) {
            helpstr++;
      }
      strcat(t, INDENT_STR);
      index = indentsize;
      col = indentsize;

      /* Keep getting words and putting them into the buffer, or put them on
       * the next line if they don't fit.
       */
      while (*helpstr != 0) {
            tmp = 0;
            memset(&buf, 0, 1024);
            while (*helpstr && !isspace(*helpstr)) {
                  buf[tmp++] = *helpstr;
                  if (*helpstr == '\n') {
                        strcat(t, buf);
                        strcat(t, INDENT_STR);
                        col = indentsize;
                        index += indentsize;
                        tmp = 0;
                  }
                  helpstr++;
            }

            /* if it fits, put it on, otherwise, put in a carriage return 
             */
            if (col + tmp > w.ws_col - 3) {
                  t[index++] = '\n';
                  strcat(t, INDENT_STR);
                  col = indentsize;
                  index += indentsize;
            }

            /* put it on, add it up 
             */
            strcat(t, buf);
            index += tmp;
            col += tmp;

            /* put all extra whitespace in (as much as they had in) 
             */
            while (helpstr && isspace(*helpstr)) {
                  t[index++] = *helpstr;
                  if (*helpstr == '\n') {
                        strcat(t, INDENT_STR);
                        index += indentsize;
                        col = 4;
                  }
                  else {
                        col++;
                  }
                  helpstr++;
            }
      }

      /* put on a final carriage return and NULL for good measure 
       */
      t[index++] = '\n';
      t[index] = 0;
      return (t);
}

/*
 * complete_cmds() -- Devide the string from the head of command line to the 
 *                    position of TAB into words.
 *                    Call the completion function for command names, if TAB 
 *                    is pressed on the first word. 
 *                    This function is registered to librl by 
 *                    rl_register_complete_func().
 *
 *                    Call the completion function for command arguments, if 
 *                    TAB is pressed on the word after the second it.
 *                    Note that it is not implemented.
 */
char *
complete_cmds(char *inputline, int tabpos)
{
      static command_t cmd;
      static char cline[DEF_LENGTH];
      int help_list(command_t *);

      /* copy string from the head of command line to the position of TAB to 
       * buffer. (tabpos + 1) does not exceed DEF_LENGTH, so error check is 
       * not needed.
       */
      clean_cmd(&cmd);
      cmd.ofp = stdout;
      strncpy(cline, inputline, tabpos + 1);
      cline[tabpos] = '\0';
      cmd.command = cline;

      /* command line is devided into a command name and arguments */
      line_to_words(&cmd); 

      /* TAB is pressed on the head of argument */
      if (*cmd.command && inputline[tabpos - 1] == ' ') {
            cmd.nargs++;
      }
      
      if (cmd.nargs == 0) {
            /* TAB is pressed on the command name */
            if (!(*(cmd.command))) {
                  /* if TAB is pressed at the head of a command name, 
                   * display the list of command names */   
                  fprintf(stdout, "\n");
                  help_list(&cmd); /* display the list of command names */
                  return(DRAW_NEW_ENTIRE_LINE);
            } else {
                  /* if TAB is pressed in the middle of a command name, 
                  call completion function for a command name */
                  return(complete_subcmd_name(cmd.command));
            }
      } else {
            /* TAB is pressed on the command argument */
            /* call completion function for command arguments */
            cmd_rec_t *crec;
            cmdcomplete_t cfunc;

            /* get internal data for cmd.command */
            if ((crec = find_cmd_rec(cmd.command)) == NULL) {
                  /* bad command name */
                  return(PRINT_BEEP);
            }
            cfunc = crec->real_cmd ? crec->real_cmd->cmdcomplete : crec->cmdcomplete;
            if (cfunc) {
                  /* call completion function for command arguments */
                  return(cfunc(&cmd));
            } else {
                  return(PRINT_BEEP);
            }
      }
}

/*
 * complete_subcmd_name() -- This function completes command names.
 *                           When there is no candidate, return PRINT_BEEP. 
 *                           When there is a candidate, return the string.
 *                           When there are two or more candidates, return the 
 *                           identical part of string of them. 
 *                           When there isn't the identical part of string, 
 *                           display the list of candidates and return  
 *                           DRAW_NEW_ENTIRE_LINE.          
 */
#define SV_CNM(i) save_crp[i]->CMD_NAME
char *
complete_subcmd_name(char *string)
{
      int slen, i, j, index;
      static int cmdnum = 0; 
      static cmd_rec_t **save_crp = (cmd_rec_t **)0;
      static char cptstr[DEF_LENGTH];
      cmd_rec_t *ncrp;
      int candidates_cnt = 0;

      /* get number of commands */
      if (!cmdnum) {
            if ((ncrp = first_cmd_rec())) {
                  do {
                        cmdnum++;
                  } while ((ncrp = next_cmd_rec(ncrp)));
            }
      }
      /* allocate pointer array */
      if (!save_crp) {
            save_crp = kl_alloc_block(cmdnum * sizeof(cmd_rec_t *), K_PERM);
            if (klib_error) {
                  fprintf(KL_ERRORFP, "Could not allocate memory for completion\n");
                  return(PRINT_BEEP);
            }
      }

      slen = strlen(string);
      cptstr[0] = '\0';

      /* find candidates */
      ncrp = first_cmd_rec();
      for (i = 0; i < cmdnum; i++) {
            if (!strncmp(ncrp->CMD_NAME, string, slen)) {
                  save_crp[candidates_cnt] = ncrp;
                  /* get a string to complete */
                  if (candidates_cnt == 0) {
                        strcpy(cptstr, SV_CNM(candidates_cnt)+slen);    
                  } else if (cptstr[0] != '\0') {
                        /* if there are two or more candidates, get the identical part 
                        of string of them */
                        for (j = 0; cptstr[j] != '\0' && 
                              *(SV_CNM(candidates_cnt)+slen+j) != '\0' &&
                              cptstr[j] == *(SV_CNM(candidates_cnt)+slen+j); j++); 
                        cptstr[j] = '\0';
                  }
                  candidates_cnt++;
            }
            ncrp = next_cmd_rec(ncrp);
      }

      if (candidates_cnt == 0) {
            /* there is no candidate */
            return(PRINT_BEEP);
      } else if (candidates_cnt == 1) {
            /* there is a candidate */
            strcat(cptstr, " ");
            return(cptstr);
      } else { 
            /* there are two or more candidates */
            if (cptstr[0] == '\0') { /* there is no the identical part of string */
                  goto print_list;
            } else { /* there is the identical part of string */
                  return(cptstr);
            }
      }
print_list:
      fprintf(stdout, "\n");
      index = candidates_cnt / 4 + (candidates_cnt % 4 ? 1 : 0);
      for (i = 0; i < index; i++) {
            fprintf(stdout, "%-17s", SV_CNM(i));
            if ((j = index + i) < candidates_cnt) {
                  fprintf(stdout, "%-17s", SV_CNM(j));
            }
            if ((j = index * 2 + i) < candidates_cnt) {
                  fprintf(stdout, "%-17s", SV_CNM(j));
            }
            if ((j = index * 3 + i) < candidates_cnt) {
                  fprintf(stdout, "%-17s", SV_CNM(j));
            }
            fprintf(stdout, "\n");
      }
      fflush(stdout);
      return(DRAW_NEW_ENTIRE_LINE);
}

/*
 * complete_standard_options() -- This function completes the standard options 
 *                                argument. 
 *                                If there is a standard option, it returns 
 *                                with the value which the completion function 
 *                                returned.
 *                                If there is no standard option, it returns 
 *                                NOT_COMPLETED.  
 */
char *
complete_standard_options(command_t *cmd)
{
      if (cmd->nargs > 1) {
            if (!strcmp(cmd->args[cmd->nargs - 2], "-w")) {
                  /* if previous word is "-w", complete file name */
                  return(complete_file_name(cmd->args[cmd->nargs -1], 100));
            } else {
                  return(NOT_COMPLETED);
            }
      } else {
            return(NOT_COMPLETED);
      }
}


/*
 * complete_symbol_name() -- This function completes 'keystr' as symbol name.
 *                           When there is no candidate, return PRINT_BEEP. 
 *                           When there is a candidate, return the string.
 *                           When there are two or more candidates, return 
 *                           the identical part of string of them. 
 *                           When there isn't the identical part of string, 
 *                           display the list of candidates and return  
 *                           DRAW_NEW_ENTIRE_LINE.          
 *                           If number of the candidates is more 
 *                           'print_max_candt', ask whether display or not. 
 */
char *
complete_symbol_name(char *keystr, int print_max_candt)
{
      syment_t    *sq_cur, *sq_head;
      static char retstr[KL_SYMBOL_NAME_LEN];
      int   candtcnt = 0;
      int i;
      int   candt_maxlen;
      int   print_column;
      char print_str[8];
      struct winsize w;

      if (!keystr) {
            keystr = "";
      }
      /* get que of the candidates for symbol name */
      sq_head = kl_get_similar_name(keystr, retstr, &candtcnt, &candt_maxlen);
      if (candtcnt == 0) {
            /* if there is no candidate, return PRINT_BEEP */
            return(PRINT_BEEP);
      } else if (candtcnt == 1) {
            /* if there is a candidate, return string to complete */
            strcat(retstr, " ");
            return(retstr);
      } else { /* candtcnt is 2 or more */
            if (retstr[0] == '\0') {
                  /* if there is no the identical part of string, print the list of 
                     candidates */
                  if (print_max_candt && candtcnt >= print_max_candt) {
                        /* if there are number of "print_max_candt" or more candidates, 
                           ask whether diaplay or not */
                        for (;;) {
                              int c;
                              fprintf(stdout, 
                                    "\nDisplay all %d possibilities? (y or n)", candtcnt);
                              c = getc(stdin);
                              if (c == 'y' || c == 'Y') {
                                    break;
                              } else if (c == 'n' || c == 'N') {
                                    fprintf(stdout, "\n");
                                    return(DRAW_NEW_ENTIRE_LINE);
                              } else {
                                    continue;
                              }
                        }
                  }
                  /* print list of candidates */
                  /* get the window size */
                  if (ioctl(fileno(stdout), TIOCGWINSZ, &w) < 0) {
                        w.ws_col = 80;
                  }
                  /* get number of the columns suited for printing candidates */ 
                  if (!(print_column = w.ws_col / (candt_maxlen + 1))) {
                        print_column = 1;
                  }
                  sprintf(print_str, "%%-%ds", 
                        (w.ws_col < candt_maxlen + 1) ? w.ws_col : candt_maxlen + 1); 
                  sq_cur = sq_head;
                  for (i = 0; i < candtcnt || sq_cur; i++) {
                        if (i % print_column == 0) {
                              fprintf(stdout, "\n");
                        }
                        fprintf(stdout, print_str, sq_cur->s_name);
                        sq_cur = sq_cur->s_forward;
                  }
                  fprintf(stdout, "\n");
                  fflush(stdout);
                  return(DRAW_NEW_ENTIRE_LINE);
            } else {
                  /* if there is the identical part of string, return string to
                     complete */
                  return(retstr);
            }
      }
}

/*
 * complete_file_name() --  This function completes 'string' as file name.
 *                          When there is no candidate, return PRINT_BEEP. 
 *                          When there is a candidate, return the string.
 *                          When there are two or more candidates, return the 
 *                          identical part of string of them. 
 *                          When there isn't the identical part of string, 
 *                          display the list of candidates and return  
 *                          DRAW_NEW_ENTIRE_LINE.           
 *                          If number of the candidates is more 
 *                          'print_max_candt', ask whether display or not. 
 */
char *
complete_file_name(char *string, int print_max_candt)
{
      char *last_slash_pos;
      static char dirname[DEF_LENGTH];
      static char keystr[NAME_MAX + 1], retstr[NAME_MAX + 1];
      int   candt_maxlen;
      int    dirlen, keylen;
      DIR *dp;
      struct dirent *dent;
      int candtcnt = 0;
      int   i;
      struct stat sbuf;
      struct candt_que_s {
            struct candt_que_s *next;
            char str[1];
      } *q_head, *q_tail, *q_cur;
      int   print_column;
      char print_str[8];
      struct winsize w;
      char *ret;

      /* string is '\0' */
      if (!string || string[0] == '\0') {
            strcpy(dirname, "./");
            strcpy(keystr, "");
      } else {
            /* get position of last slash */
            last_slash_pos = strrchr(string, '/');
            if (last_slash_pos == NULL) {
                  /* search current directory */
                  strcpy(dirname, "./");
                  strcpy(keystr, string);
            } else {
                  /* get search directory */
                  dirlen = last_slash_pos - string + 1;
                  strncpy(dirname, string, dirlen);
                  dirname[dirlen] = '\0';
                  /* get key string to complete */
                  strcpy(keystr, string+dirlen); 
            }
      }
      keylen = strlen(keystr);
      /* open search directory */
      if ((dp = opendir(dirname)) == NULL) {
            ret = PRINT_BEEP;
            goto out;
      }

      /* initialize q_head */
      q_head = 0; 

      /* get the queue of candidates for file name */ 
      while ((dent = readdir(dp)) != NULL) {
            if (!keylen || !strncmp(dent->d_name, keystr, keylen)) {
                  /* allocate memory for candidates queue */
                  q_cur = kl_alloc_block(sizeof(struct candt_que_s) + 
                        strlen(dent->d_name), K_PERM);
                  if (klib_error) {
                        fprintf(KL_ERRORFP, 
                              "Could not allocate memory for file name completion\n");
                        /* free memory for queue of candidates and return with value of 
                           'ret'*/
                        ret = PRINT_BEEP;
                        goto out;
                  }
                  strcpy(q_cur->str, dent->d_name);
                  if (candtcnt == 0) {
                        q_head = q_tail = q_cur;
                        /* save return string to 'retstr' */
                        strcpy(retstr, q_cur->str+keylen);
                        /* get max length of candidates */
                        candt_maxlen = strlen(q_cur->str);
                  } else {
                        q_tail->next = q_cur;
                        q_tail = q_cur;
                        if (retstr[0] != '\0') {
                              /* get the identical part of string of candidates and save 
                                 to 'retstr' */
                              for (i = 0; retstr[i] != '\0' && 
                                    retstr[i] == *(q_cur->str+keylen+i); i++);
                              retstr[i] = '\0';
                        }
                        /* get max length of candidates */
                        if (candt_maxlen < strlen(q_cur->str)) {
                              candt_maxlen = strlen(q_cur->str);
                        }
                  }
                  q_tail->next = 0;
                  candtcnt++;
            }
      }
      closedir(dp);

      if (candtcnt == 0) {
            ret = PRINT_BEEP;
            goto out;
      } else if (candtcnt == 1) {
            /* check if file is directory */
            strcat(dirname, q_head->str);
            stat(dirname, &sbuf);
            if (S_ISDIR(sbuf.st_mode)) {
                  strcat(retstr, "/");
            } else {
                  strcat(retstr, " ");
            }
            /* return string to complete */
            ret = retstr;
            /* free memory for queue of candidates and return with value of 'ret'*/
            goto out;
      } else { /* candtcnt >= 2 */
            if (retstr[0] == '\0') {
                  /* if there is no the identical part of string, print the list of 
                     candidates */
                  if (print_max_candt && candtcnt >= print_max_candt) {
                        /* if there are number of "print_max_candt" or more candidates,
                           ask whether display or not */
                        for (;;) {
                              int c;
                              fprintf(stdout, "\nDisplay all %d possibilities? (y or n)",
                                    candtcnt);
                              c = getc(stdin);
                              if (c == 'y' || c == 'Y') {
                                    break;
                              } else if (c == 'n' || c == 'N') {
                                    fprintf(stdout, "\n");
                                    /* free memory for queue of candidates and return with 
                                       value of 'ret' */
                                    ret = DRAW_NEW_ENTIRE_LINE; 
                                    goto out;
                              } else {
                                    continue;
                              }
                        }
                  }
                  /* print list of candidates */
                  /* get the window size */
                  if (ioctl(fileno(stdout), TIOCGWINSZ, &w) < 0) {
                        w.ws_col = 80;
                  }
                  /* get number of the columns suited for printing candidates */ 
                  if (!(print_column = w.ws_col / (candt_maxlen + 1)))
                        print_column = 1;
                  sprintf(print_str, "%%-%ds", 
                        (w.ws_col < candt_maxlen + 1) ? w.ws_col : candt_maxlen + 1); 
                  q_cur = q_head;
                  for (i = 0; i < candtcnt || q_cur; i++) {
                        if (i % print_column == 0) {
                              fprintf(stdout, "\n");
                        }
                        fprintf(stdout, print_str, q_cur->str);
                        q_cur = q_cur->next;
                  }
                  fprintf(stdout, "\n");
                  fflush(stdout);
                  /* free memory for queue of candidates and return with value of 
                     'ret'*/
                  ret = DRAW_NEW_ENTIRE_LINE;
                  goto out;
            } else {
                  /* if there is the identical part of string, return string to
                     complete */
                  /* free memory for queue of candidates and return with value of 
                     'ret'*/
                  ret = retstr;
                  goto out;
            }
      }
out:
      while (q_head) {
            q_cur = q_head;
            q_head = q_head->next;
            kl_free_block(q_cur);
      }
      return(ret);
}

Generated by  Doxygen 1.6.0   Back to index