#include <stdio.h>
#include <stddef.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdarg.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <unistd.h>
#include "gdb_private_interfaces.h"
#define CTRL(c) ((c) & 0x1F)
#define RUBOUT 0x7F
#define ABORT_CHAR CTRL('G')
#define CTRL_CHAR(c) ((c) < 0x020 && (c) >= 0)
#define UNCTRL(c) (islower(((c)|0x40)) ? toupper(((c)|0x40)) : (((c)|0x40)))
void (*__word__completion_hook)(int save_input_cursor) = NULL;
void (*__word__completion_query_hook)(GDB_FILE *stream, char *format, ...) = NULL;
int (*__word__completion_read_hook)(void) = NULL;
#define rl_outstream NULL
static int _putc(int c, void *stream)
{
char ch = c;
gdb_fprintf(stream == stderr ? gdb_stderr : gdb_stdout, "%c", ch);
}
static int _printf(void *stream, const char *format, ...)
{
char line[1024];
va_list ap;
va_start(ap, format);
vsprintf(line, format, ap);
va_end(ap);
gdb_fprintf(stream == stderr ? gdb_stderr : gdb_stdout, "%s", line);
}
static int _fflush(void *stream)
{
gdb_fflush(stream == stderr ? gdb_stderr : gdb_stdout);
}
static crlf(void)
{
_putc('\n', gdb_stdout);
}
#undef putc
#undef printf
#undef fflush
#define putc _putc
#define printf _printf
#define fflush _fflush
static int get_y_or_n(void)
{
int c;
for (;;) {
if (__word__completion_read_hook)
c = __word__completion_read_hook();
else
c = rl_read_key();
if (c == 'y' || c == 'Y' || c == ' ')
return (1);
if (c == 'n' || c == 'N' || c == RUBOUT)
return (0);
if (c == ABORT_CHAR)
_rl_abort_internal();
rl_ding();
}
}
static int stat_char(char *filename)
{
struct stat finfo;
int character, r;
#if defined(HAVE_LSTAT) && defined(S_ISLNK)
r = lstat(filename, &finfo);
#else
r = stat(filename, &finfo);
#endif
if (r == -1)
return (0);
character = 0;
if (S_ISDIR(finfo.st_mode))
character = '/';
#if defined(S_ISCHR)
else if (S_ISCHR(finfo.st_mode))
character = '%';
#endif
#if defined(S_ISBLK)
else if (S_ISBLK(finfo.st_mode))
character = '#';
#endif
#if defined(S_ISLNK)
else if (S_ISLNK(finfo.st_mode))
character = '@';
#endif
#if defined(S_ISSOCK)
else if (S_ISSOCK(finfo.st_mode))
character = '=';
#endif
#if defined(S_ISFIFO)
else if (S_ISFIFO(finfo.st_mode))
character = '|';
#endif
else if (S_ISREG(finfo.st_mode)) {
if (access(filename, 1) == 0)
character = '*';
}
return (character);
}
static char *printable_part(char *pathname)
{
char *temp = rl_filename_completion_desired ? strrchr(pathname, '/') : (char *)NULL;
return (temp ? ++temp : pathname);
}
static int print_filename(char *to_print, char *full_pathname)
{
int printed_len = 0;
char *s, c, *new_full_pathname;
int extension_char, slen, tlen;
#define PUTX(c) \
do { \
if (CTRL_CHAR(c)) \
{ \
putc('^', stdout); \
putc(UNCTRL(c), stdout); \
printed_len += 2; \
} \
else if (c == RUBOUT) \
{ \
putc('^', stdout); \
putc('?', stdout); \
printed_len += 2; \
} \
else \
{ \
putc(c, stdout); \
printed_len++; \
} \
} while (0)
for (s = to_print; *s; s++)
PUTX(*s);
if (rl_filename_completion_desired && rl_visible_stats) {
if (to_print != full_pathname) {
c = to_print[-1];
to_print[-1] = '\0';
s = tilde_expand(full_pathname);
slen = strlen(s);
tlen = strlen(to_print);
new_full_pathname = xmalloc(slen + tlen + 2);
strcpy(new_full_pathname, s);
new_full_pathname[slen] = '/';
strcpy(new_full_pathname + slen + 1, to_print);
extension_char = stat_char(new_full_pathname);
free(new_full_pathname);
to_print[-1] = c;
} else {
s = tilde_expand(full_pathname);
extension_char = stat_char(s);
}
free(s);
if (extension_char) {
putc(extension_char, stdout);
printed_len++;
}
}
return (printed_len);
}
void __cmd_completion_display_hook(char **matches, int num_matches, int max_length)
{
int count, limit, printed_len;
int len, max, i, j, k, l;
char *temp, prompt[1024];
int screenheight, screenwidth;
if (__word__completion_hook)
__word__completion_hook(1);
else
gdb_fprintf(gdb_default_stderr, "\0337");
for (max = 0, i = 1; matches[i]; i++) {
temp = printable_part(matches[i]);
len = strlen(temp);
if (len > max)
max = len;
}
len = i - 1;
if (len >= rl_completion_query_items) {
if (__word__completion_query_hook)
__word__completion_query_hook(gdb_stdout, "Display all %d possibilities? (y or n) ", len);
else {
crlf();
printf(stdout, "Display all %d possibilities? (y or n) ", len);
}
fflush(stdout);
i = get_y_or_n();
if (i == 0) {
if (__word__completion_hook)
__word__completion_hook(0);
else {
crlf();
gdb_fprintf(gdb_default_stderr, "\0338");
}
return;
}
}
rl_get_screen_size (&screenheight, &screenwidth);
max += 2;
limit = screenwidth / max;
if (limit != 1 && (limit * max == screenwidth))
limit--;
if (limit == 0)
limit = 1;
count = (len + (limit - 1)) / limit;
if (rl_ignore_completion_duplicates == 0)
qsort(matches + 1, len, sizeof(char *), _rl_qsort_string_compare);
crlf();
if (_rl_print_completions_horizontally == 0) {
for (i = 1; i <= count; i++) {
for (j = 0, l = i; j < limit; j++) {
if (l > len || matches[l] == 0)
break;
else {
temp = printable_part(matches[l]);
printed_len = print_filename(temp, matches[l]);
if (j + 1 < limit)
for (k = 0; k < max - printed_len; k++)
putc(' ', rl_outstream);
}
l += count;
}
crlf();
}
} else {
for (i = 1; matches[i]; i++) {
temp = printable_part(matches[i]);
printed_len = print_filename(temp, matches[i]);
if (matches[i+1]) {
if (i && (limit > 1) && (i % limit) == 0)
crlf();
else
for (k = 0; k < max - printed_len; k++)
putc(' ', rl_outstream);
}
}
crlf();
}
gdb_fflush(gdb_current_stdout);
if (__word__completion_hook)
__word__completion_hook(0);
else
gdb_fprintf(gdb_default_stderr, "\0338");
}