[BACK]Return to readline.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / lib / libedit

Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.

Diff for /src/lib/libedit/readline.c between version 1.39 and 1.40

version 1.39, 2003/10/19 06:28:35 version 1.40, 2003/10/27 22:26:35
Line 68  __RCSID("$NetBSD$");
Line 68  __RCSID("$NetBSD$");
 #include "fcns.h"               /* for EL_NUM_FCNS */  #include "fcns.h"               /* for EL_NUM_FCNS */
   
 /* for rl_complete() */  /* for rl_complete() */
 #define TAB             '\r'  #define TAB             '\r'
   
 /* see comment at the #ifdef for sense of this */  /* see comment at the #ifdef for sense of this */
 #define GDB_411_HACK  /* #define GDB_411_HACK */
   
 /* readline compatibility stuff - look at readline sources/documentation */  /* readline compatibility stuff - look at readline sources/documentation */
 /* to see what these variables mean */  /* to see what these variables mean */
Line 97  char history_expansion_char = '!';
Line 97  char history_expansion_char = '!';
 char history_subst_char = '^';  char history_subst_char = '^';
 char *history_no_expand_chars = expand_chars;  char *history_no_expand_chars = expand_chars;
 Function *history_inhibit_expansion_function = NULL;  Function *history_inhibit_expansion_function = NULL;
   char *history_arg_extract(int start, int end, const char *str);
   
 int rl_inhibit_completion = 0;  int rl_inhibit_completion = 0;
 int rl_attempted_completion_over = 0;  int rl_attempted_completion_over = 0;
Line 163  static int el_rl_complete_cmdnum = 0;
Line 164  static int el_rl_complete_cmdnum = 0;
 static unsigned char     _el_rl_complete(EditLine *, int);  static unsigned char     _el_rl_complete(EditLine *, int);
 static char             *_get_prompt(EditLine *);  static char             *_get_prompt(EditLine *);
 static HIST_ENTRY       *_move_history(int);  static HIST_ENTRY       *_move_history(int);
 static int               _history_search_gen(const char *, int, int);  static int               _history_expand_command(const char *, size_t, size_t,
 static int               _history_expand_command(const char *, size_t, char **);      char **);
 static char             *_rl_compat_sub(const char *, const char *,  static char             *_rl_compat_sub(const char *, const char *,
                             const char *, int);      const char *, int);
 static int               rl_complete_internal(int);  static int               rl_complete_internal(int);
 static int               _rl_qsort_string_compare(const void *, const void *);  static int               _rl_qsort_string_compare(const void *, const void *);
 static int               _rl_event_read_char(EditLine *, char *);  static int               _rl_event_read_char(EditLine *, char *);
Line 194  _move_history(int op)
Line 195  _move_history(int op)
                 return (HIST_ENTRY *) NULL;                  return (HIST_ENTRY *) NULL;
   
         rl_he.line = ev.str;          rl_he.line = ev.str;
         rl_he.data = "";          rl_he.data = NULL;
   
         return (&rl_he);          return (&rl_he);
 }  }
Line 391  static char *
Line 392  static char *
 _rl_compat_sub(const char *str, const char *what, const char *with,  _rl_compat_sub(const char *str, const char *what, const char *with,
     int globally)      int globally)
 {  {
         char *result;          const   char    *s;
         const char *temp, *new;          char    *r, *result;
         size_t len, with_len, what_len, add;          size_t  len, with_len, what_len;
         size_t size, i;  
   
         result = malloc((size = 16));          len = strlen(str);
         if (result == NULL)  
                 return NULL;  
         temp = str;  
         with_len = strlen(with);          with_len = strlen(with);
         what_len = strlen(what);          what_len = strlen(what);
         len = 0;  
         do {          /* calculate length we need for result */
                 new = strstr(temp, what);          s = str;
                 if (new) {          while (*s) {
                         i = new - temp;                  if (*s == *what && !strncmp(s, what, what_len)) {
                         add = i + with_len;                          len += with_len - what_len;
                         if (i + add + 1 >= size) {                          if (!globally)
                                 char *nresult;                                  break;
                                 size += add + 1;                          s += what_len;
                                 nresult = realloc(result, size);                  } else
                                 if (nresult == NULL) {                          s++;
                                         free(result);          }
                                         return NULL;          r = result = malloc(len + 1);
                                 }          if (result == NULL)
                                 result = nresult;                  return NULL;
                         }          s = str;
                         (void) strncpy(&result[len], temp, i);          while (*s) {
                         len += i;                  if (*s == *what && !strncmp(s, what, what_len)) {
                         (void) strcpy(&result[len], with);      /* safe */                          (void)strncpy(r, with, with_len);
                         len += with_len;                          r += with_len;
                         temp = new + what_len;                          s += what_len;
                 } else {                          if (!globally) {
                         add = strlen(temp);                                  (void)strcpy(r, s);
                         if (len + add + 1 >= size) {                                  return(result);
                                 char *nresult;  
                                 size += add + 1;  
                                 nresult = realloc(result, size);  
                                 if (nresult == NULL) {  
                                         free(result);  
                                         return NULL;  
                                 }  
                                 result = nresult;  
                         }                          }
                         (void) strcpy(&result[len], temp);      /* safe */                  } else
                         len += add;                          *r++ = *s++;
                         temp = NULL;          }
           *r = 0;
           return(result);
   }
   
   static  char    *last_search_pat;       /* last !?pat[?] search pattern */
   static  char    *last_search_match;     /* last !?pat[?] that matched */
   
   const char *
   get_history_event(const char *cmd, int *cindex, int qchar)
   {
           int idx, sign, sub, num, begin, ret;
           size_t len;
           char    *pat;
           const char *rptr;
           HistEvent ev;
   
           idx = *cindex;
           if (cmd[idx++] != history_expansion_char)
                   return(NULL);
   
           /* find out which event to take */
           if (cmd[idx] == history_expansion_char || cmd[idx] == 0) {
                   if (history(h, &ev, H_FIRST) != 0)
                           return(NULL);
                   *cindex = cmd[idx]? (idx + 1):idx;
                   return(ev.str);
           }
           sign = 0;
           if (cmd[idx] == '-') {
                   sign = 1;
                   idx++;
           }
   
           if ('0' <= cmd[idx] && cmd[idx] <= '9') {
                   HIST_ENTRY *rl_he;
   
                   num = 0;
                   while (cmd[idx] && '0' <= cmd[idx] && cmd[idx] <= '9') {
                           num = num * 10 + cmd[idx] - '0';
                           idx++;
                 }                  }
         } while (temp && globally);                  if (sign)
         result[len] = '\0';                          num = history_length - num + 1;
   
         return (result);                  if (!(rl_he = history_get(num)))
 }                          return(NULL);
   
                   *cindex = idx;
                   return(rl_he->line);
           }
           sub = 0;
           if (cmd[idx] == '?') {
                   sub = 1;
                   idx++;
           }
           begin = idx;
           while (cmd[idx]) {
                   if (cmd[idx] == '\n')
                           break;
                   if (sub && cmd[idx] == '?')
                           break;
                   if (!sub && (cmd[idx] == ':' || cmd[idx] == ' '
                                       || cmd[idx] == '\t' || cmd[idx] == qchar))
                           break;
                   idx++;
           }
           len = idx - begin;
           if (sub && cmd[idx] == '?')
                   idx++;
           if (sub && len == 0 && last_search_pat && *last_search_pat)
                   pat = last_search_pat;
           else if (len == 0)
                   return(NULL);
           else {
                   if ((pat = malloc(len + 1)) == NULL)
                           return NULL;
                   (void)strncpy(pat, cmd + begin, len);
                   pat[len] = '\0';
           }
   
           if (history(h, &ev, H_CURR) != 0) {
                   if (pat != last_search_pat)
                           free(pat);
                   return (NULL);
           }
           num = ev.num;
   
           if (sub) {
                   if (pat != last_search_pat) {
                           if (last_search_pat)
                                   free(last_search_pat);
                           last_search_pat = pat;
                   }
                   ret = history_search(pat, -1);
           } else
                   ret = history_search_prefix(pat, -1);
   
           if (ret == -1) {
                   /* restore to end of list on failed search */
                   history(h, &ev, H_FIRST);
                   (void)fprintf(rl_outstream, "%s: Event not found\n", pat);
                   if (pat != last_search_pat)
                           free(pat);
                   return(NULL);
           }
   
           if (sub && len) {
                   if (last_search_match && last_search_match != pat)
                           free(last_search_match);
                   last_search_match = pat;
           }
   
           if (pat != last_search_pat)
                   free(pat);
   
           if (history(h, &ev, H_CURR) != 0)
                   return(NULL);
           *cindex = idx;
           rptr = ev.str;
   
           /* roll back to original position */
           (void)history(h, &ev, H_SET, num);
   
           return rptr;
   }
   
 /*  /*
  * the real function doing history expansion - takes as argument command   * the real function doing history expansion - takes as argument command
  * to do and data upon which the command should be executed   * to do and data upon which the command should be executed
  * does expansion the way I've understood readline documentation   * does expansion the way I've understood readline documentation
  * word designator ``%'' isn't supported (yet ?)  
  *   *
  * returns 0 if data was not modified, 1 if it was and 2 if the string   * returns 0 if data was not modified, 1 if it was and 2 if the string
  * should be only printed and not executed; in case of error,   * should be only printed and not executed; in case of error,
Line 458  _rl_compat_sub(const char *str, const ch
Line 564  _rl_compat_sub(const char *str, const ch
  * it's callers responsibility to free() string returned in *result   * it's callers responsibility to free() string returned in *result
  */   */
 static int  static int
 _history_expand_command(const char *command, size_t cmdlen, char **result)  _history_expand_command(const char *command, size_t offs, size_t cmdlen,
       char **result)
 {  {
         char **arr, *tempcmd, *line, *search = NULL, *cmd;          char *tmp, *search = NULL, *aptr;
         const char *event_data = NULL;          const char *ptr, *cmd;
         static char *from = NULL, *to = NULL;          static char *from = NULL, *to = NULL;
         int start = -1, end = -1, max, i, idx;          int start, end, idx, has_mods = 0;
         int h_on = 0, t_on = 0, r_on = 0, e_on = 0, p_on = 0, g_on = 0;          int p_on = 0, g_on = 0;
         int event_num = 0, retval;  
         size_t cmdsize;  
   
         *result = NULL;          *result = NULL;
           aptr = NULL;
   
         cmd = alloca(cmdlen + 1);          /* First get event specifier */
         (void) strncpy(cmd, command, cmdlen);          idx = 0;
         cmd[cmdlen] = 0;  
   
         idx = 1;          if (strchr(":^*$", command[offs + 1])) {
         /* find out which event to take */                  char str[4];
         if (cmd[idx] == history_expansion_char) {                  /*
                 event_num = history_length;                  * "!:" is shorthand for "!!:".
                 idx++;                  * "!^", "!*" and "!$" are shorthand for
                   * "!!:^", "!!:*" and "!!:$" respectively.
                   */
                   str[0] = str[1] = '!';
                   str[2] = '0';
                   ptr = get_history_event(str, &idx, 0);
                   idx = (command[offs + 1] == ':')? 1:0;
                   has_mods = 1;
         } else {          } else {
                 int off, num;                  if (command[offs + 1] == '#') {
                 size_t len;                          /* use command so far */
                 off = idx;                          if ((aptr = malloc(offs + 1)) == NULL)
                 while (cmd[off] && !strchr(":^$*-%", cmd[off]))                                  return -1;
                         off++;                          (void)strncpy(aptr, command, offs);
                 num = atoi(&cmd[idx]);                          aptr[offs] = '\0';
                 if (num != 0) {                          idx = 1;
                         event_num = num;  
                         if (num < 0)  
                                 event_num += history_length + 1;  
                 } else {                  } else {
                         int prefix = 1, curr_num;                          int     qchar;
                         HistEvent ev;  
   
                         len = off - idx;  
                         if (cmd[idx] == '?') {  
                                 idx++, len--;  
                                 if (cmd[off - 1] == '?')  
                                         len--;  
                                 else if (cmd[off] != '\n' && cmd[off] != '\0')  
                                         return (-1);  
                                 prefix = 0;  
                         }  
                         search = alloca(len + 1);  
                         (void) strncpy(search, &cmd[idx], len);  
                         search[len] = '\0';  
   
                         if (history(h, &ev, H_CURR) != 0)  
                                 return (-1);  
                         curr_num = ev.num;  
   
                         if (prefix)                          qchar = (offs > 0 && command[offs - 1] == '"')? '"':0;
                                 retval = history_search_prefix(search, -1);                          ptr = get_history_event(command + offs, &idx, qchar);
                         else  
                                 retval = history_search(search, -1);  
   
                         if (retval == -1) {  
                                 fprintf(rl_outstream, "%s: Event not found\n",  
                                     search);  
                                 return (-1);  
                         }  
                         if (history(h, &ev, H_CURR) != 0)  
                                 return (-1);  
                         event_data = ev.str;  
   
                         /* roll back to original position */  
                         history(h, &ev, H_NEXT_EVENT, curr_num);  
                 }                  }
                 idx = off;                  has_mods = command[offs + idx] == ':';
         }          }
   
         if (!event_data && event_num >= 0) {          if (ptr == NULL && aptr == NULL)
                 HIST_ENTRY *rl_he;                  return(-1);
                 rl_he = history_get(event_num);  
                 if (!rl_he)          if (!has_mods) {
                         return (0);                  *result = strdup(aptr? aptr : ptr);
                 event_data = rl_he->line;                  if (aptr)
                           free(aptr);
                   return(1);
           }
   
           cmd = command + offs + idx + 1;
   
           /* Now parse any word designators */
   
           if (*cmd == '%')        /* last word matched by ?pat? */
                   tmp = strdup(last_search_match? last_search_match:"");
           else if (strchr("^*$-0123456789", *cmd)) {
                   start = end = -1;
                   if (*cmd == '^')
                           start = end = 1, cmd++;
                   else if (*cmd == '$')
                           start = -1, cmd++;
                   else if (*cmd == '*')
                           start = 1, cmd++;
                  else if (*cmd == '-' || isdigit((unsigned char) *cmd)) {
                           start = 0;
                           while (*cmd && '0' <= *cmd && *cmd <= '9')
                                   start = start * 10 + *cmd++ - '0';
   
                           if (*cmd == '-') {
                                   if (isdigit((unsigned char) cmd[1])) {
                                           cmd++;
                                           end = 0;
                                           while (*cmd && '0' <= *cmd && *cmd <= '9')
                                                   end = end * 10 + *cmd++ - '0';
                                   } else if (cmd[1] == '$') {
                                           cmd += 2;
                                           end = -1;
                                   } else {
                                           cmd++;
                                           end = -2;
                                   }
                           } else if (*cmd == '*')
                                   end = -1, cmd++;
                           else
                                   end = start;
                   }
                   tmp = history_arg_extract(start, end, aptr? aptr:ptr);
                   if (tmp == NULL) {
                           (void)fprintf(rl_outstream, "%s: Bad word specifier",
                               command + offs + idx);
                           if (aptr)
                                   free(aptr);
                           return(-1);
                   }
         } else          } else
                 return (-1);                  tmp = strdup(aptr? aptr:ptr);
   
         if (cmd[idx] != ':')          if (aptr)
                 return (-1);                  free(aptr);
         cmd += idx + 1;  
           if (*cmd == 0 || (cmd - (command + offs) >= cmdlen)) {
                   *result = tmp;
                   return(1);
           }
   
         /* recognize cmd */  
         if (*cmd == '^')  
                 start = end = 1, cmd++;  
         else if (*cmd == '$')  
                 start = end = -1, cmd++;  
         else if (*cmd == '*')  
                 start = 1, end = -1, cmd++;  
         else if (isdigit((unsigned char) *cmd)) {  
                 const char *temp;  
                 int shifted = 0;  
   
                 start = atoi(cmd);  
                 temp = cmd;  
                 for (; isdigit((unsigned char) *cmd); cmd++);  
                 if (temp != cmd)  
                         shifted = 1;  
                 if (shifted && *cmd == '-') {  
                         if (!isdigit((unsigned char) *(cmd + 1)))  
                                 end = -2;  
                         else {  
                                 end = atoi(cmd + 1);  
                                 for (; isdigit((unsigned char) *cmd); cmd++);  
                         }  
                 } else if (shifted && *cmd == '*')  
                         end = -1, cmd++;  
                 else if (shifted)  
                         end = start;  
         }  
         if (*cmd == ':')  
                 cmd++;  
   
         line = strdup(event_data);  
         if (line == NULL)  
                 return 0;  
         for (; *cmd; cmd++) {          for (; *cmd; cmd++) {
                 if (*cmd == ':')                  if (*cmd == ':')
                         continue;                          continue;
                 else if (*cmd == 'h')                  else if (*cmd == 'h') {         /* remove trailing path */
                         h_on = 1 | g_on, g_on = 0;                          if ((aptr = strrchr(tmp, '/')) != NULL)
                 else if (*cmd == 't')                                  *aptr = 0;
                         t_on = 1 | g_on, g_on = 0;                  } else if (*cmd == 't') {       /* remove leading path */
                 else if (*cmd == 'r')                          if ((aptr = strrchr(tmp, '/')) != NULL) {
                         r_on = 1 | g_on, g_on = 0;                                  aptr = strdup(aptr + 1);
                 else if (*cmd == 'e')                                  free(tmp);
                         e_on = 1 | g_on, g_on = 0;                                  tmp = aptr;
                 else if (*cmd == 'p')                          }
                         p_on = 1 | g_on, g_on = 0;                  } else if (*cmd == 'r') {       /* remove trailing suffix */
                           if ((aptr = strrchr(tmp, '.')) != NULL)
                                   *aptr = 0;
                   } else if (*cmd == 'e') {       /* remove all but suffix */
                           if ((aptr = strrchr(tmp, '.')) != NULL) {
                                   aptr = strdup(aptr);
                                   free(tmp);
                                   tmp = aptr;
                           }
                   } else if (*cmd == 'p')         /* print only */
                           p_on = 1;
                 else if (*cmd == 'g')                  else if (*cmd == 'g')
                         g_on = 2;                          g_on = 2;
                 else if (*cmd == 's' || *cmd == '&') {                  else if (*cmd == 's' || *cmd == '&') {
Line 610  _history_expand_command(const char *comm
Line 716  _history_expand_command(const char *comm
                                 }                                  }
                                 len = 0;                                  len = 0;
                                 for (; *cmd && *cmd != delim; cmd++) {                                  for (; *cmd && *cmd != delim; cmd++) {
                                         if (*cmd == '\\'                                          if (*cmd == '\\' && cmd[1] == delim)
                                             && *(cmd + 1) == delim)  
                                                 cmd++;                                                  cmd++;
                                         if (len >= size) {                                          if (len >= size) {
                                                 char *nwhat;                                                  char *nwhat;
                                                 nwhat = realloc(what,                                                  nwhat = realloc(what,
                                                     (size <<= 1));                                                                  (size <<= 1));
                                                 if (nwhat == NULL) {                                                  if (nwhat == NULL) {
                                                         free(what);                                                          free(what);
                                                         return 0;                                                          return 0;
Line 663  _history_expand_command(const char *comm
Line 768  _history_expand_command(const char *comm
                                         }                                          }
                                         if (*cmd == '&') {                                          if (*cmd == '&') {
                                                 /* safe */                                                  /* safe */
                                                 (void) strcpy(&with[len], from);                                                  (void)strcpy(&with[len], from);
                                                 len += from_len;                                                  len += from_len;
                                                 continue;                                                  continue;
                                         }                                          }
Line 675  _history_expand_command(const char *comm
Line 780  _history_expand_command(const char *comm
                                 }                                  }
                                 with[len] = '\0';                                  with[len] = '\0';
                                 to = with;                                  to = with;
   
                                 tempcmd = _rl_compat_sub(line, from, to,  
                                     (g_on) ? 1 : 0);  
                                 if (tempcmd) {  
                                         free(line);  
                                         line = tempcmd;  
                                 }  
                                 g_on = 0;  
                         }                          }
                 }  
         }  
   
         arr = history_tokenize(line);  
         free(line);             /* no more needed */  
         if (arr && *arr == NULL)  
                 free(arr), arr = NULL;  
         if (!arr)  
                 return (-1);  
   
         /* find out max valid idx to array of array */  
         max = 0;  
         for (i = 0; arr[i]; i++)  
                 max++;  
         max--;  
   
         /* set boundaries to something relevant */  
         if (start < 0)  
                 start = 1;  
         if (end < 0)  
                 end = max - ((end < -1) ? 1 : 0);  
   
         /* check boundaries ... */  
         if (start > max || end > max || start > end)  
                 return (-1);  
   
         for (i = 0; i <= max; i++) {                          aptr = _rl_compat_sub(tmp, from, to, g_on);
                 char *temp;                          if (aptr) {
                 if (h_on && (i == 1 || h_on > 1) &&                                  free(tmp);
                     (temp = strrchr(arr[i], '/')))                                  tmp = aptr;
                         *(temp + 1) = '\0';  
                 if (t_on && (i == 1 || t_on > 1) &&  
                     (temp = strrchr(arr[i], '/')))  
                         (void) strcpy(arr[i], temp + 1);  
                 if (r_on && (i == 1 || r_on > 1) &&  
                     (temp = strrchr(arr[i], '.')))  
                         *temp = '\0';  
                 if (e_on && (i == 1 || e_on > 1) &&  
                     (temp = strrchr(arr[i], '.')))  
                         (void) strcpy(arr[i], temp);  
         }  
   
         cmdsize = 1, cmdlen = 0;  
         if ((tempcmd = malloc(cmdsize)) == NULL)  
                 return 0;  
         for (i = start; start <= i && i <= end; i++) {  
                 int arr_len;  
   
                 arr_len = strlen(arr[i]);  
                 if (cmdlen + arr_len + 1 >= cmdsize) {  
                         char *ntempcmd;  
                         cmdsize += arr_len + 1;  
                         ntempcmd = realloc(tempcmd, cmdsize);  
                         if (ntempcmd == NULL) {  
                                 free(tempcmd);  
                                 return 0;  
                         }                          }
                         tempcmd = ntempcmd;                          g_on = 0;
                 }                  }
                 (void) strcpy(&tempcmd[cmdlen], arr[i]);        /* safe */  
                 cmdlen += arr_len;  
                 tempcmd[cmdlen++] = ' ';        /* add a space */  
         }          }
         while (cmdlen > 0 && isspace((unsigned char) tempcmd[cmdlen - 1]))          *result = tmp;
                 cmdlen--;          return (p_on? 2:1);
         tempcmd[cmdlen] = '\0';  
   
         *result = tempcmd;  
   
         for (i = 0; i <= max; i++)  
                 free(arr[i]);  
         free(arr), arr = (char **) NULL;  
         return (p_on) ? 2 : 1;  
 }  }
   
   
Line 766  _history_expand_command(const char *comm
Line 801  _history_expand_command(const char *comm
 int  int
 history_expand(char *str, char **output)  history_expand(char *str, char **output)
 {  {
         int i, retval = 0, idx;          int ret = 0;
         size_t size;          size_t idx, i, size;
         char *temp, *result;          char *tmp, *result;
   
         if (h == NULL || e == NULL)          if (h == NULL || e == NULL)
                 rl_initialize();                  rl_initialize();
   
         *output = strdup(str);  /* do it early */          if (history_expansion_char == 0) {
         if (*output == NULL)                  *output = strdup(str);
                 return 0;                  return(0);
           }
   
           *output = NULL;
         if (str[0] == history_subst_char) {          if (str[0] == history_subst_char) {
                 /* ^foo^foo2^ is equivalent to !!:s^foo^foo2^ */                  /* ^foo^foo2^ is equivalent to !!:s^foo^foo2^ */
                 temp = alloca(4 + strlen(str) + 1);                  *output = malloc(strlen(str) + 4 + 1);
                 temp[0] = temp[1] = history_expansion_char;                  if (*output == NULL)
                 temp[2] = ':';                          return 0;
                 temp[3] = 's';                  (*output)[0] = (*output)[1] = history_expansion_char;
                 (void) strcpy(temp + 4, str);                  (*output)[2] = ':';
                 str = temp;                  (*output)[3] = 's';
                   (void)strcpy((*output) + 4, str);
                   str = *output;
           } else {
                   *output = strdup(str);
                   if (*output == NULL)
                           return 0;
         }          }
 #define ADD_STRING(what, len)                                           \  
   #define ADD_STRING(what, len)                                           \
         {                                                               \          {                                                               \
                 if (idx + len + 1 > size) {                             \                  if (idx + len + 1 > size) {                             \
                         char *nresult = realloc(result, (size += len + 1));\                          char *nresult = realloc(result, (size += len + 1));\
Line 804  history_expand(char *str, char **output)
Line 848  history_expand(char *str, char **output)
         result = NULL;          result = NULL;
         size = idx = 0;          size = idx = 0;
         for (i = 0; str[i];) {          for (i = 0; str[i];) {
                 int start, j, loop_again;                  int qchar, loop_again;
                 size_t len;                  size_t len, start, j;
   
                   qchar = 0;
                 loop_again = 1;                  loop_again = 1;
                 start = j = i;                  start = j = i;
 loop:  loop:
                 for (; str[j]; j++) {                  for (; str[j]; j++) {
                         if (str[j] == '\\' &&                          if (str[j] == '\\' &&
                             str[j + 1] == history_expansion_char) {                              str[j + 1] == history_expansion_char) {
                                 (void) strcpy(&str[j], &str[j + 1]);                                  (void)strcpy(&str[j], &str[j + 1]);
                                 continue;                                  continue;
                         }                          }
                         if (!loop_again) {                          if (!loop_again) {
                                 if (str[j] == '?') {                                  if (isspace((unsigned char) str[j])
                                         while (str[j] && str[++j] != '?');                                      || str[j] == qchar)
                                         if (str[j] == '?')  
                                                 j++;  
                                 } else if (isspace((unsigned char) str[j]))  
                                         break;                                          break;
                         }                          }
                         if (str[j] == history_expansion_char                          if (str[j] == history_expansion_char
                             && !strchr(history_no_expand_chars, str[j + 1])                              && !strchr(history_no_expand_chars, str[j + 1])
                             && (!history_inhibit_expansion_function ||                              && (!history_inhibit_expansion_function ||
                             (*history_inhibit_expansion_function)(str, j) == 0))                              (*history_inhibit_expansion_function)(str,
                               (int)j) == 0))
                                 break;                                  break;
                 }                  }
   
                 if (str[j] && str[j + 1] != '#' && loop_again) {                  if (str[j] && loop_again) {
                         i = j;                          i = j;
                           qchar = (j > 0 && str[j - 1] == '"' )? '"':0;
                         j++;                          j++;
                         if (str[j] == history_expansion_char)                          if (str[j] == history_expansion_char)
                                 j++;                                  j++;
Line 840  loop:
Line 884  loop:
                         goto loop;                          goto loop;
                 }                  }
                 len = i - start;                  len = i - start;
                 temp = &str[start];                  tmp = &str[start];
                 ADD_STRING(temp, len);                  ADD_STRING(tmp, len);
   
                 if (str[i] == '\0' || str[i] != history_expansion_char                  if (str[i] == '\0' || str[i] != history_expansion_char) {
                     || str[i + 1] == '#') {  
                         len = j - i;                          len = j - i;
                         temp = &str[i];                          tmp = &str[i];
                         ADD_STRING(temp, len);                          ADD_STRING(tmp, len);
                         if (start == 0)                          if (start == 0)
                                 retval = 0;                                  ret = 0;
                         else                          else
                                 retval = 1;                                  ret = 1;
                         break;                          break;
                 }                  }
                 retval = _history_expand_command(&str[i], (size_t) (j - i),                  ret = _history_expand_command (str, i, (j - i), &tmp);
                     &temp);                  if (ret > 0 && tmp) {
                 if (retval != -1) {                          len = strlen(tmp);
                         len = strlen(temp);                          ADD_STRING(tmp, len);
                         ADD_STRING(temp, len);                          free(tmp);
                 }                  }
                 i = j;                  i = j;
         }                       /* for(i ...) */          }
   
         if (retval == 2) {          /* ret is 2 for "print only" option */
                 add_history(temp);          if (ret == 2) {
                   add_history(result);
 #ifdef GDB_411_HACK  #ifdef GDB_411_HACK
                 /* gdb 4.11 has been shipped with readline, where */                  /* gdb 4.11 has been shipped with readline, where */
                 /* history_expand() returned -1 when the line     */                  /* history_expand() returned -1 when the line     */
                 /* should not be executed; in readline 2.1+       */                  /* should not be executed; in readline 2.1+       */
                 /* it should return 2 in such a case              */                  /* it should return 2 in such a case              */
                 retval = -1;                  ret = -1;
 #endif  #endif
         }          }
         free(*output);          free(*output);
         *output = result;          *output = result;
   
         return (retval);          return (ret);
 }  }
   
   /*
   * Return a string consisting of arguments of "str" from "start" to "end".
   */
   char *
   history_arg_extract(int start, int end, const char *str)
   {
           size_t  i, len, max;
           char    **arr, *result;
   
           arr = history_tokenize(str);
           if (!arr)
                   return(NULL);
           if (arr && *arr == NULL) {
                   free(arr);
                   return(NULL);
           }
   
           for (max = 0; arr[max]; max++)
                   continue;
           max--;
   
           if (start == '$')
                   start = max;
           if (end == '$')
                   end = max;
           if (end < 0)
                   end = max + end + 1;
           if (start < 0)
                   start = end;
   
           if (start < 0 || end < 0 || start > max || end > max || start > end)
                   return(NULL);
   
           for (i = start, len = 0; i <= end; i++)
                   len += strlen(arr[i]) + 1;
           len++;
           result = malloc(len);
           if (result == NULL)
                   return NULL;
   
           for (i = start, len = 0; i <= end; i++) {
                   (void)strcpy(result + len, arr[i]);
                   len += strlen(arr[i]);
                   if (i < end)
                           result[len++] = ' ';
           }
           result[len] = 0;
   
           for (i = 0; arr[i]; i++)
                   free(arr[i]);
           free(arr);
   
           return(result);
   }
   
 /*  /*
  * Parse the string into individual tokens, similarily to how shell would do it.   * Parse the string into individual tokens,
    * similar to how shell would do it.
  */   */
 char **  char **
 history_tokenize(const char *str)  history_tokenize(const char *str)
 {  {
         int size = 1, result_idx = 0, i, start;          int size = 1, idx = 0, i, start;
         size_t len;          size_t len;
         char **result = NULL, *temp, delim = '\0';          char **result = NULL, *temp, delim = '\0';
   
         for (i = 0; str[i]; i++) {          for (i = 0; str[i];) {
                 while (isspace((unsigned char) str[i]))                  while (isspace((unsigned char) str[i]))
                         i++;                          i++;
                 start = i;                  start = i;
                 for (; str[i]; i++) {                  for (; str[i];) {
                         if (str[i] == '\\') {                          if (str[i] == '\\') {
                                 if (str[i+1] != '\0')                                  if (str[i+1] != '\0')
                                         i++;                                          i++;
Line 906  history_tokenize(const char *str)
Line 1005  history_tokenize(const char *str)
                                 break;                                  break;
                         else if (!delim && strchr("'`\"", str[i]))                          else if (!delim && strchr("'`\"", str[i]))
                                 delim = str[i];                                  delim = str[i];
                           if (str[i])
                                   i++;
                 }                  }
   
                 if (result_idx + 2 >= size) {                  if (idx + 2 >= size) {
                         char **nresult;                          char **nresult;
                         size <<= 1;                          size <<= 1;
                         nresult = realloc(result, size * sizeof(char *));                          nresult = realloc(result, size * sizeof(char *));
Line 921  history_tokenize(const char *str)
Line 1022  history_tokenize(const char *str)
                 len = i - start;                  len = i - start;
                 temp = malloc(len + 1);                  temp = malloc(len + 1);
                 if (temp == NULL) {                  if (temp == NULL) {
                           for (i = 0; i < idx; i++)
                                   free(result[i]);
                         free(result);                          free(result);
                         return NULL;                          return NULL;
                 }                  }
                 (void) strncpy(temp, &str[start], len);                  (void)strncpy(temp, &str[start], len);
                 temp[len] = '\0';                  temp[len] = '\0';
                 result[result_idx++] = temp;                  result[idx++] = temp;
                 result[result_idx] = NULL;                  result[idx] = NULL;
                   if (str[i])
                           i++;
         }          }
   
         return (result);          return (result);
 }  }
   
Line 1013  history_get(int num)
Line 1117  history_get(int num)
 {  {
         static HIST_ENTRY she;          static HIST_ENTRY she;
         HistEvent ev;          HistEvent ev;
         int i = 1, curr_num;          int curr_num;
   
         if (h == NULL || e == NULL)          if (h == NULL || e == NULL)
                 rl_initialize();                  rl_initialize();
   
         /* rewind to beginning */          /* save current position */
         if (history(h, &ev, H_CURR) != 0)          if (history(h, &ev, H_CURR) != 0)
                 return (NULL);                  return (NULL);
         curr_num = ev.num;          curr_num = ev.num;
         if (history(h, &ev, H_LAST) != 0)  
           /* start from most recent */
           if (history(h, &ev, H_FIRST) != 0)
                 return (NULL);  /* error */                  return (NULL);  /* error */
         while (i < num && history(h, &ev, H_PREV) == 0)  
                 i++;          /* look backwards for event matching specified offset */
         if (i != num)          if (history(h, &ev, H_NEXT_EVENT, num))
                 return (NULL);  /* not so many entries */                  return (NULL);
   
         she.line = ev.str;          she.line = ev.str;
         she.data = NULL;          she.data = NULL;
   
         /* rewind history to the same event it was before */          /* restore pointer to where it was */
         (void) history(h, &ev, H_FIRST);          (void)history(h, &ev, H_SET, curr_num);
         (void) history(h, &ev, H_NEXT_EVENT, curr_num);  
   
         return (&she);          return (&she);
 }  }
Line 1051  add_history(const char *line)
Line 1156  add_history(const char *line)
         if (h == NULL || e == NULL)          if (h == NULL || e == NULL)
                 rl_initialize();                  rl_initialize();
   
         (void) history(h, &ev, H_ENTER, line);          (void)history(h, &ev, H_ENTER, line);
         if (history(h, &ev, H_GETSIZE) == 0)          if (history(h, &ev, H_GETSIZE) == 0)
                 history_length = ev.num;                  history_length = ev.num;
   
         return (!(history_length > 0)); /* return 0 if all is okay */          return (!(history_length > 0)); /* return 0 if all is okay */
 }  }
   
   
Line 1137  int
Line 1242  int
 history_set_pos(int pos)  history_set_pos(int pos)
 {  {
         HistEvent ev;          HistEvent ev;
         int off, curr_num;          int curr_num;
   
         if (pos > history_length || pos < 0)          if (pos > history_length || pos < 0)
                 return (-1);                  return (-1);
   
         history(h, &ev, H_CURR);          history(h, &ev, H_CURR);
         curr_num = ev.num;          curr_num = ev.num;
         history(h, &ev, H_FIRST);  
         off = 0;  
         while (off < pos && history(h, &ev, H_NEXT) == 0)  
                 off++;  
   
         if (off != pos) {       /* do a rollback in case of error */          if (history(h, &ev, H_SET, pos)) {
                 history(h, &ev, H_FIRST);                  history(h, &ev, H_SET, curr_num);
                 history(h, &ev, H_NEXT_EVENT, curr_num);                  return(-1);
                 return (-1);  
         }          }
         return (0);          return (0);
 }  }
Line 1181  next_history(void)
Line 1281  next_history(void)
   
   
 /*  /*
  * generic history search function   * searches for first history event containing the str
  */   */
 static int  int
 _history_search_gen(const char *str, int direction, int pos)  history_search(const char *str, int direction)
 {  {
         HistEvent ev;          HistEvent ev;
         const char *strp;          const char *strp;
Line 1195  _history_search_gen(const char *str, int
Line 1295  _history_search_gen(const char *str, int
         curr_num = ev.num;          curr_num = ev.num;
   
         for (;;) {          for (;;) {
                 strp = strstr(ev.str, str);                  if ((strp = strstr(ev.str, str)) != NULL)
                 if (strp && (pos < 0 || &ev.str[pos] == strp))  
                         return (int) (strp - ev.str);                          return (int) (strp - ev.str);
                 if (history(h, &ev, direction < 0 ? H_PREV : H_NEXT) != 0)                  if (history(h, &ev, direction < 0 ? H_NEXT:H_PREV) != 0)
                         break;                          break;
         }          }
           history(h, &ev, H_SET, curr_num);
         history(h, &ev, direction < 0 ? H_NEXT_EVENT : H_PREV_EVENT, curr_num);  
   
         return (-1);          return (-1);
 }  }
   
   
 /*  /*
  * searches for first history event containing the str  
  */  
 int  
 history_search(const char *str, int direction)  
 {  
   
         return (_history_search_gen(str, direction, -1));  
 }  
   
   
 /*  
  * searches for first history event beginning with str   * searches for first history event beginning with str
  */   */
 int  int
 history_search_prefix(const char *str, int direction)  history_search_prefix(const char *str, int direction)
 {  {
           HistEvent ev;
   
         return (_history_search_gen(str, direction, 0));          return (history(h, &ev, direction < 0? H_PREV_STR:H_NEXT_STR, str));
 }  }
   
   
Line 1236  history_search_prefix(const char *str, i
Line 1323  history_search_prefix(const char *str, i
  */   */
 /* ARGSUSED */  /* ARGSUSED */
 int  int
 history_search_pos(const char *str,  history_search_pos(const char *str,
                    int direction __attribute__((__unused__)), int pos)                     int direction __attribute__((__unused__)), int pos)
 {  {
         HistEvent ev;          HistEvent ev;
Line 1268  history_search_pos(const char *str, 
Line 1355  history_search_pos(const char *str, 
   
   
 /********************************/  /********************************/
 /* completion functions */  /* completion functions */
   
 /*  /*
  * does tilde expansion of strings of type ``~user/foo''   * does tilde expansion of strings of type ``~user/foo''
Line 1297  tilde_expand(char *txt)
Line 1384  tilde_expand(char *txt)
                 temp = malloc(len);                  temp = malloc(len);
                 if (temp == NULL)                  if (temp == NULL)
                         return NULL;                          return NULL;
                 (void) strncpy(temp, txt + 1, len - 2);                  (void)strncpy(temp, txt + 1, len - 2);
                 temp[len - 2] = '\0';                  temp[len - 2] = '\0';
         }          }
         pass = getpwnam(temp);          pass = getpwnam(temp);
Line 1312  tilde_expand(char *txt)
Line 1399  tilde_expand(char *txt)
         temp = malloc(strlen(pass->pw_dir) + 1 + strlen(txt) + 1);          temp = malloc(strlen(pass->pw_dir) + 1 + strlen(txt) + 1);
         if (temp == NULL)          if (temp == NULL)
                 return NULL;                  return NULL;
         (void) sprintf(temp, "%s/%s", pass->pw_dir, txt);          (void)sprintf(temp, "%s/%s", pass->pw_dir, txt);
   
         return (temp);          return (temp);
 }  }
Line 1346  filename_completion_function(const char 
Line 1433  filename_completion_function(const char 
                                 return NULL;                                  return NULL;
                         }                          }
                         filename = nptr;                          filename = nptr;
                         (void) strcpy(filename, temp);                          (void)strcpy(filename, temp);
                         len = temp - text;      /* including last slash */                          len = temp - text;      /* including last slash */
                         nptr = realloc(dirname, len + 1);                          nptr = realloc(dirname, len + 1);
                         if (nptr == NULL) {                          if (nptr == NULL) {
Line 1354  filename_completion_function(const char 
Line 1441  filename_completion_function(const char 
                                 return NULL;                                  return NULL;
                         }                          }
                         dirname = nptr;                          dirname = nptr;
                         (void) strncpy(dirname, text, len);                          (void)strncpy(dirname, text, len);
                         dirname[len] = '\0';                          dirname[len] = '\0';
                 } else {                  } else {
                         filename = strdup(text);                          filename = strdup(text);
Line 1375  filename_completion_function(const char 
Line 1462  filename_completion_function(const char 
                                 return NULL;                                  return NULL;
                         }                          }
                         dirname = nptr;                          dirname = nptr;
                         (void) strcpy(dirname, temp);   /* safe */                          (void)strcpy(dirname, temp);    /* safe */
                         free(temp);     /* no longer needed */                          free(temp);     /* no longer needed */
                 }                  }
                 /* will be used in cycle */                  /* will be used in cycle */
Line 1418  filename_completion_function(const char 
Line 1505  filename_completion_function(const char 
                 temp = malloc(len);                  temp = malloc(len);
                 if (temp == NULL)                  if (temp == NULL)
                         return NULL;                          return NULL;
                 (void) sprintf(temp, "%s%s",                  (void)sprintf(temp, "%s%s",
                     dirname ? dirname : "", entry->d_name);     /* safe */                      dirname ? dirname : "", entry->d_name);     /* safe */
   
                 /* test, if it's directory */                  /* test, if it's directory */
Line 1529  completion_matches(const char *text, CPF
Line 1616  completion_matches(const char *text, CPF
                 free(match_list);                  free(match_list);
                 return NULL;                  return NULL;
         }          }
         (void) strncpy(retstr, match_list[1], max_equal);          (void)strncpy(retstr, match_list[1], max_equal);
         retstr[max_equal] = '\0';          retstr[max_equal] = '\0';
         match_list[0] = retstr;          match_list[0] = retstr;
   
Line 1584  rl_display_match_list (matches, len, max
Line 1671  rl_display_match_list (matches, len, max
   
         idx = 1;          idx = 1;
         for(; count > 0; count--) {          for(; count > 0; count--) {
                 for(i=0; i < limit && matches[idx]; i++, idx++)                  for(i = 0; i < limit && matches[idx]; i++, idx++)
                         fprintf(e->el_outfile, "%-*s  ", max, matches[idx]);                          (void)fprintf(e->el_outfile, "%-*s  ", max,
                 fprintf(e->el_outfile, "\n");                              matches[idx]);
                   (void)fprintf(e->el_outfile, "\n");
         }          }
 }  }
   
Line 1625  rl_complete_internal(int what_to_do)
Line 1713  rl_complete_internal(int what_to_do)
         while (ctemp > li->buffer          while (ctemp > li->buffer
             && !strchr(rl_basic_word_break_characters, ctemp[-1])              && !strchr(rl_basic_word_break_characters, ctemp[-1])
             && (!rl_special_prefixes              && (!rl_special_prefixes
                         || !strchr(rl_special_prefixes, ctemp[-1]) ) )                  || !strchr(rl_special_prefixes, ctemp[-1]) ) )
                 ctemp--;                  ctemp--;
   
         len = li->cursor - ctemp;          len = li->cursor - ctemp;
         temp = alloca(len + 1);          temp = alloca(len + 1);
         (void) strncpy(temp, ctemp, len);          (void)strncpy(temp, ctemp, len);
         temp[len] = '\0';          temp[len] = '\0';
   
         /* these can be used by function called in completion_matches() */          /* these can be used by function called in completion_matches() */
Line 1693  rl_complete_internal(int what_to_do)
Line 1781  rl_complete_internal(int what_to_do)
                         matches_num = i - 1;                          matches_num = i - 1;
   
                         /* newline to get on next line from command line */                          /* newline to get on next line from command line */
                         fprintf(e->el_outfile, "\n");                          (void)fprintf(e->el_outfile, "\n");
   
                         /*                          /*
                          * If there are too many items, ask user for display                           * If there are too many items, ask user for display
                          * confirmation.                           * confirmation.
                          */                           */
                         if (matches_num > rl_completion_query_items) {                          if (matches_num > rl_completion_query_items) {
                                 fprintf(e->el_outfile,                                  (void)fprintf(e->el_outfile,
                                 "Display all %d possibilities? (y or n) ",                                      "Display all %d possibilities? (y or n) ",
                                         matches_num);                                      matches_num);
                                 fflush(e->el_outfile);                                  (void)fflush(e->el_outfile);
                                 if (getc(stdin) != 'y')                                  if (getc(stdin) != 'y')
                                         match_display = 0;                                          match_display = 0;
                                 fprintf(e->el_outfile, "\n");                                  (void)fprintf(e->el_outfile, "\n");
                         }                          }
   
                         if (match_display)                          if (match_display)
Line 1982  rl_stuff_char(int c)
Line 2070  rl_stuff_char(int c)
 static int  static int
 _rl_event_read_char(EditLine *el, char *cp)  _rl_event_read_char(EditLine *el, char *cp)
 {  {
         int     n, num_read;          int     n, num_read;
   
         *cp = 0;          *cp = 0;
         while (rl_event_hook) {          while (rl_event_hook) {

Legend:
Removed from v.1.39  
changed lines
  Added in v.1.40

CVSweb <webmaster@jp.NetBSD.org>