fixed bash/dash/sh issue (Ubuntu)
[zpugcc/jano.git] / toolchain / gdb / readline / examples / rlfe.c
blobd634d7ce878b5b3016b3cd12911e7e742d4d3d91
1 /* A front-end using readline to "cook" input lines for Kawa.
3 * Copyright (C) 1999 Per Bothner
4 *
5 * This front-end program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as published
7 * by the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
10 * Some code from Johnson & Troan: "Linux Application Development"
11 * (Addison-Wesley, 1998) was used directly or for inspiration.
14 /* PROBLEMS/TODO:
16 * Only tested under Linux; needs to be ported.
18 * When running mc -c under the Linux console, mc does not recognize
19 * mouse clicks, which mc does when not running under fep.
21 * Pasting selected text containing tabs is like hitting the tab character,
22 * which invokes readline completion. We don't want this. I don't know
23 * if this is fixable without integrating fep into a terminal emulator.
25 * Echo suppression is a kludge, but can only be avoided with better kernel
26 * support: We need a tty mode to disable "real" echoing, while still
27 * letting the inferior think its tty driver to doing echoing.
28 * Stevens's book claims SCR$ and BSD4.3+ have TIOCREMOTE.
30 * The latest readline may have some hooks we can use to avoid having
31 * to back up the prompt.
33 * Desirable readline feature: When in cooked no-echo mode (e.g. password),
34 * echo characters are they are types with '*', but remove them when done.
36 * A synchronous output while we're editing an input line should be
37 * inserted in the output view *before* the input line, so that the
38 * lines being edited (with the prompt) float at the end of the input.
40 * A "page mode" option to emulate more/less behavior: At each page of
41 * output, pause for a user command. This required parsing the output
42 * to keep track of line lengths. It also requires remembering the
43 * output, if we want an option to scroll back, which suggests that
44 * this should be integrated with a terminal emulator like xterm.
47 #ifdef HAVE_CONFIG_H
48 # include <config.h>
49 #endif
51 #include <stdio.h>
52 #include <fcntl.h>
53 #include <sys/types.h>
54 #include <sys/socket.h>
55 #include <netinet/in.h>
56 #include <arpa/inet.h>
57 #include <signal.h>
58 #include <netdb.h>
59 #include <stdlib.h>
60 #include <errno.h>
61 #include <grp.h>
62 #include <string.h>
63 #include <sys/stat.h>
64 #include <unistd.h>
65 #include <sys/ioctl.h>
66 #include <termios.h>
67 #include <limits.h>
68 #include <dirent.h>
70 #ifdef READLINE_LIBRARY
71 # include "readline.h"
72 # include "history.h"
73 #else
74 # include <readline/readline.h>
75 # include <readline/history.h>
76 #endif
78 #ifndef COMMAND
79 #define COMMAND "/bin/sh"
80 #endif
81 #ifndef COMMAND_ARGS
82 #define COMMAND_ARGS COMMAND
83 #endif
85 #ifndef HAVE_MEMMOVE
86 #ifndef memmove
87 # if __GNUC__ > 1
88 # define memmove(d, s, n) __builtin_memcpy(d, s, n)
89 # else
90 # define memmove(d, s, n) memcpy(d, s, n)
91 # endif
92 #else
93 # define memmove(d, s, n) memcpy(d, s, n)
94 #endif
95 #endif
97 #define APPLICATION_NAME "Rlfe"
99 #ifndef errno
100 extern int errno;
101 #endif
103 extern int optind;
104 extern char *optarg;
106 static char *progname;
107 static char *progversion;
109 static int in_from_inferior_fd;
110 static int out_to_inferior_fd;
112 /* Unfortunately, we cannot safely display echo from the inferior process.
113 The reason is that the echo bit in the pty is "owned" by the inferior,
114 and if we try to turn it off, we could confuse the inferior.
115 Thus, when echoing, we get echo twice: First readline echoes while
116 we're actually editing. Then we send the line to the inferior, and the
117 terminal driver send back an extra echo.
118 The work-around is to remember the input lines, and when we see that
119 line come back, we supress the output.
120 A better solution (supposedly available on SVR4) would be a smarter
121 terminal driver, with more flags ... */
122 #define ECHO_SUPPRESS_MAX 1024
123 char echo_suppress_buffer[ECHO_SUPPRESS_MAX];
124 int echo_suppress_start = 0;
125 int echo_suppress_limit = 0;
127 /* #define DEBUG */
129 static FILE *logfile = NULL;
131 #ifdef DEBUG
132 FILE *debugfile = NULL;
133 #define DPRINT0(FMT) (fprintf(debugfile, FMT), fflush(debugfile))
134 #define DPRINT1(FMT, V1) (fprintf(debugfile, FMT, V1), fflush(debugfile))
135 #define DPRINT2(FMT, V1, V2) (fprintf(debugfile, FMT, V1, V2), fflush(debugfile))
136 #else
137 #define DPRINT0(FMT) /* Do nothing */
138 #define DPRINT1(FMT, V1) /* Do nothing */
139 #define DPRINT2(FMT, V1, V2) /* Do nothing */
140 #endif
142 struct termios orig_term;
144 static int rlfe_directory_completion_hook __P((char **));
145 static int rlfe_directory_rewrite_hook __P((char **));
146 static char *rlfe_filename_completion_function __P((const char *, int));
148 /* Pid of child process. */
149 static pid_t child = -1;
151 static void
152 sig_child (int signo)
154 int status;
155 wait (&status);
156 DPRINT0 ("(Child process died.)\n");
157 tcsetattr(STDIN_FILENO, TCSANOW, &orig_term);
158 exit (0);
161 volatile int propagate_sigwinch = 0;
163 /* sigwinch_handler
164 * propagate window size changes from input file descriptor to
165 * master side of pty.
167 void sigwinch_handler(int signal) {
168 propagate_sigwinch = 1;
171 /* get_master_pty() takes a double-indirect character pointer in which
172 * to put a slave name, and returns an integer file descriptor.
173 * If it returns < 0, an error has occurred.
174 * Otherwise, it has returned the master pty file descriptor, and fills
175 * in *name with the name of the corresponding slave pty.
176 * Once the slave pty has been opened, you are responsible to free *name.
179 int get_master_pty(char **name) {
180 int i, j;
181 /* default to returning error */
182 int master = -1;
184 /* create a dummy name to fill in */
185 *name = strdup("/dev/ptyXX");
187 /* search for an unused pty */
188 for (i=0; i<16 && master <= 0; i++) {
189 for (j=0; j<16 && master <= 0; j++) {
190 (*name)[5] = 'p';
191 (*name)[8] = "pqrstuvwxyzPQRST"[i];
192 (*name)[9] = "0123456789abcdef"[j];
193 /* open the master pty */
194 if ((master = open(*name, O_RDWR)) < 0) {
195 if (errno == ENOENT) {
196 /* we are out of pty devices */
197 free (*name);
198 return (master);
201 else {
202 /* By substituting a letter, we change the master pty
203 * name into the slave pty name.
205 (*name)[5] = 't';
206 if (access(*name, R_OK|W_OK) != 0)
208 close(master);
209 master = -1;
214 if ((master < 0) && (i == 16) && (j == 16)) {
215 /* must have tried every pty unsuccessfully */
216 free (*name);
217 return (master);
220 (*name)[5] = 't';
222 return (master);
225 /* get_slave_pty() returns an integer file descriptor.
226 * If it returns < 0, an error has occurred.
227 * Otherwise, it has returned the slave file descriptor.
230 int get_slave_pty(char *name) {
231 struct group *gptr;
232 gid_t gid;
233 int slave = -1;
235 /* chown/chmod the corresponding pty, if possible.
236 * This will only work if the process has root permissions.
237 * Alternatively, write and exec a small setuid program that
238 * does just this.
240 if ((gptr = getgrnam("tty")) != 0) {
241 gid = gptr->gr_gid;
242 } else {
243 /* if the tty group does not exist, don't change the
244 * group on the slave pty, only the owner
246 gid = -1;
249 /* Note that we do not check for errors here. If this is code
250 * where these actions are critical, check for errors!
252 chown(name, getuid(), gid);
253 /* This code only makes the slave read/writeable for the user.
254 * If this is for an interactive shell that will want to
255 * receive "write" and "wall" messages, OR S_IWGRP into the
256 * second argument below.
258 chmod(name, S_IRUSR|S_IWUSR);
260 /* open the corresponding slave pty */
261 slave = open(name, O_RDWR);
262 return (slave);
265 /* Certain special characters, such as ctrl/C, we want to pass directly
266 to the inferior, rather than letting readline handle them. */
268 static char special_chars[20];
269 static int special_chars_count;
271 static void
272 add_special_char(int ch)
274 if (ch != 0)
275 special_chars[special_chars_count++] = ch;
278 static int eof_char;
280 static int
281 is_special_char(int ch)
283 int i;
284 #if 0
285 if (ch == eof_char && rl_point == rl_end)
286 return 1;
287 #endif
288 for (i = special_chars_count; --i >= 0; )
289 if (special_chars[i] == ch)
290 return 1;
291 return 0;
294 static char buf[1024];
295 /* buf[0 .. buf_count-1] is the what has been emitted on the current line.
296 It is used as the readline prompt. */
297 static int buf_count = 0;
299 int num_keys = 0;
301 static void
302 null_prep_terminal (int meta)
306 static void
307 null_deprep_terminal ()
311 char pending_special_char;
313 static void
314 line_handler (char *line)
316 if (line == NULL)
318 char buf[1];
319 DPRINT0("saw eof!\n");
320 buf[0] = '\004'; /* ctrl/d */
321 write (out_to_inferior_fd, buf, 1);
323 else
325 static char enter[] = "\r";
326 /* Send line to inferior: */
327 int length = strlen (line);
328 if (length > ECHO_SUPPRESS_MAX-2)
330 echo_suppress_start = 0;
331 echo_suppress_limit = 0;
333 else
335 if (echo_suppress_limit + length > ECHO_SUPPRESS_MAX - 2)
337 if (echo_suppress_limit - echo_suppress_start + length
338 <= ECHO_SUPPRESS_MAX - 2)
340 memmove (echo_suppress_buffer,
341 echo_suppress_buffer + echo_suppress_start,
342 echo_suppress_limit - echo_suppress_start);
343 echo_suppress_limit -= echo_suppress_start;
344 echo_suppress_start = 0;
346 else
348 echo_suppress_limit = 0;
350 echo_suppress_start = 0;
352 memcpy (echo_suppress_buffer + echo_suppress_limit,
353 line, length);
354 echo_suppress_limit += length;
355 echo_suppress_buffer[echo_suppress_limit++] = '\r';
356 echo_suppress_buffer[echo_suppress_limit++] = '\n';
358 write (out_to_inferior_fd, line, length);
359 if (pending_special_char == 0)
361 write (out_to_inferior_fd, enter, sizeof(enter)-1);
362 if (*line)
363 add_history (line);
365 free (line);
367 rl_callback_handler_remove ();
368 buf_count = 0;
369 num_keys = 0;
370 if (pending_special_char != 0)
372 write (out_to_inferior_fd, &pending_special_char, 1);
373 pending_special_char = 0;
377 /* Value of rl_getc_function.
378 Use this because readline should read from stdin, not rl_instream,
379 points to the pty (so readline has monitor its terminal modes). */
382 my_rl_getc (FILE *dummy)
384 int ch = rl_getc (stdin);
385 if (is_special_char (ch))
387 pending_special_char = ch;
388 return '\r';
390 return ch;
393 static void
394 usage()
396 fprintf (stderr, "%s: usage: %s [-l filename] [-a] [-n appname] [-hv] [command [arguments...]]\n",
397 progname, progname);
401 main(int argc, char** argv)
403 char *path;
404 int i, append;
405 int master;
406 char *name, *logfname, *appname;
407 int in_from_tty_fd;
408 struct sigaction act;
409 struct winsize ws;
410 struct termios t;
411 int maxfd;
412 fd_set in_set;
413 static char empty_string[1] = "";
414 char *prompt = empty_string;
415 int ioctl_err = 0;
417 if ((progname = strrchr (argv[0], '/')) == 0)
418 progname = argv[0];
419 else
420 progname++;
421 progversion = RL_LIBRARY_VERSION;
423 append = 0;
424 appname = APPLICATION_NAME;
425 logfname = (char *)NULL;
427 while ((i = getopt (argc, argv, "ahl:n:v")) != EOF)
429 switch (i)
431 case 'l':
432 logfname = optarg;
433 break;
434 case 'n':
435 appname = optarg;
436 break;
437 case 'a':
438 append = 1;
439 break;
440 case 'h':
441 usage ();
442 exit (0);
443 case 'v':
444 fprintf (stderr, "%s version %s\n", progname, progversion);
445 exit (0);
446 default:
447 usage ();
448 exit (2);
452 argc -= optind;
453 argv += optind;
455 if (logfname)
457 logfile = fopen (logfname, append ? "a" : "w");
458 if (logfile == 0)
459 fprintf (stderr, "%s: warning: could not open log file %s: %s\n",
460 progname, logfname, strerror (errno));
463 rl_readline_name = appname;
465 #ifdef DEBUG
466 debugfile = fopen("LOG", "w");
467 #endif
469 if ((master = get_master_pty(&name)) < 0)
471 perror("ptypair: could not open master pty");
472 exit(1);
475 DPRINT1("pty name: '%s'\n", name);
477 /* set up SIGWINCH handler */
478 act.sa_handler = sigwinch_handler;
479 sigemptyset(&(act.sa_mask));
480 act.sa_flags = 0;
481 if (sigaction(SIGWINCH, &act, NULL) < 0)
483 perror("ptypair: could not handle SIGWINCH ");
484 exit(1);
487 if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) < 0)
489 perror("ptypair: could not get window size");
490 exit(1);
493 if ((child = fork()) < 0)
495 perror("cannot fork");
496 exit(1);
499 if (child == 0)
501 int slave; /* file descriptor for slave pty */
503 /* We are in the child process */
504 close(master);
506 #ifdef TIOCSCTTY
507 if ((slave = get_slave_pty(name)) < 0)
509 perror("ptypair: could not open slave pty");
510 exit(1);
512 free(name);
513 #endif
515 /* We need to make this process a session group leader, because
516 * it is on a new PTY, and things like job control simply will
517 * not work correctly unless there is a session group leader
518 * and process group leader (which a session group leader
519 * automatically is). This also disassociates us from our old
520 * controlling tty.
522 if (setsid() < 0)
524 perror("could not set session leader");
527 /* Tie us to our new controlling tty. */
528 #ifdef TIOCSCTTY
529 if (ioctl(slave, TIOCSCTTY, NULL))
531 perror("could not set new controlling tty");
533 #else
534 if ((slave = get_slave_pty(name)) < 0)
536 perror("ptypair: could not open slave pty");
537 exit(1);
539 free(name);
540 #endif
542 /* make slave pty be standard in, out, and error */
543 dup2(slave, STDIN_FILENO);
544 dup2(slave, STDOUT_FILENO);
545 dup2(slave, STDERR_FILENO);
547 /* at this point the slave pty should be standard input */
548 if (slave > 2)
550 close(slave);
553 /* Try to restore window size; failure isn't critical */
554 if (ioctl(STDOUT_FILENO, TIOCSWINSZ, &ws) < 0)
556 perror("could not restore window size");
559 /* now start the shell */
561 static char* command_args[] = { COMMAND_ARGS, NULL };
562 if (argc < 1)
563 execvp(COMMAND, command_args);
564 else
565 execvp(argv[0], &argv[0]);
568 /* should never be reached */
569 exit(1);
572 /* parent */
573 signal (SIGCHLD, sig_child);
574 free(name);
576 /* Note that we only set termios settings for standard input;
577 * the master side of a pty is NOT a tty.
579 tcgetattr(STDIN_FILENO, &orig_term);
581 t = orig_term;
582 eof_char = t.c_cc[VEOF];
583 /* add_special_char(t.c_cc[VEOF]);*/
584 add_special_char(t.c_cc[VINTR]);
585 add_special_char(t.c_cc[VQUIT]);
586 add_special_char(t.c_cc[VSUSP]);
587 #if defined (VDISCARD)
588 add_special_char(t.c_cc[VDISCARD]);
589 #endif
591 #if 0
592 t.c_lflag |= (ICANON | ISIG | ECHO | ECHOCTL | ECHOE | \
593 ECHOK | ECHOKE | ECHONL | ECHOPRT );
594 #else
595 t.c_lflag &= ~(ICANON | ISIG | ECHO | ECHOCTL | ECHOE | \
596 ECHOK | ECHOKE | ECHONL | ECHOPRT );
597 #endif
598 t.c_iflag |= IGNBRK;
599 t.c_cc[VMIN] = 1;
600 t.c_cc[VTIME] = 0;
601 tcsetattr(STDIN_FILENO, TCSANOW, &t);
602 in_from_inferior_fd = master;
603 out_to_inferior_fd = master;
604 rl_instream = fdopen (master, "r");
605 rl_getc_function = my_rl_getc;
607 rl_prep_term_function = null_prep_terminal;
608 rl_deprep_term_function = null_deprep_terminal;
609 rl_callback_handler_install (prompt, line_handler);
611 #if 1
612 rl_directory_completion_hook = rlfe_directory_completion_hook;
613 rl_completion_entry_function = rlfe_filename_completion_function;
614 #else
615 rl_directory_rewrite_hook = rlfe_directory_rewrite_hook;
616 #endif
618 in_from_tty_fd = STDIN_FILENO;
619 FD_ZERO (&in_set);
620 maxfd = in_from_inferior_fd > in_from_tty_fd ? in_from_inferior_fd
621 : in_from_tty_fd;
622 for (;;)
624 int num;
625 FD_SET (in_from_inferior_fd, &in_set);
626 FD_SET (in_from_tty_fd, &in_set);
628 num = select(maxfd+1, &in_set, NULL, NULL, NULL);
630 if (propagate_sigwinch)
632 struct winsize ws;
633 if (ioctl (STDIN_FILENO, TIOCGWINSZ, &ws) >= 0)
635 ioctl (master, TIOCSWINSZ, &ws);
637 propagate_sigwinch = 0;
638 continue;
641 if (num <= 0)
643 perror ("select");
644 exit (-1);
646 if (FD_ISSET (in_from_tty_fd, &in_set))
648 extern int readline_echoing_p;
649 struct termios term_master;
650 int do_canon = 1;
651 int ioctl_ret;
653 DPRINT1("[tty avail num_keys:%d]\n", num_keys);
655 /* If we can't get tty modes for the master side of the pty, we
656 can't handle non-canonical-mode programs. Always assume the
657 master is in canonical echo mode if we can't tell. */
658 ioctl_ret = tcgetattr(master, &term_master);
660 if (ioctl_ret >= 0)
662 DPRINT2 ("echo:%d, canon:%d\n",
663 (term_master.c_lflag & ECHO) != 0,
664 (term_master.c_lflag & ICANON) != 0);
665 do_canon = (term_master.c_lflag & ICANON) != 0;
666 readline_echoing_p = (term_master.c_lflag & ECHO) != 0;
668 else
670 if (ioctl_err == 0)
671 DPRINT1("tcgetattr on master fd failed: errno = %d\n", errno);
672 ioctl_err = 1;
675 if (do_canon == 0 && num_keys == 0)
677 char ch[10];
678 int count = read (STDIN_FILENO, ch, sizeof(ch));
679 write (out_to_inferior_fd, ch, count);
681 else
683 if (num_keys == 0)
685 int i;
686 /* Re-install callback handler for new prompt. */
687 if (prompt != empty_string)
688 free (prompt);
689 prompt = malloc (buf_count + 1);
690 if (prompt == NULL)
691 prompt = empty_string;
692 else
694 memcpy (prompt, buf, buf_count);
695 prompt[buf_count] = '\0';
696 DPRINT1("New prompt '%s'\n", prompt);
697 #if 0 /* ifdef HAVE_RL_ALREADY_PROMPTED -- doesn't work */
698 rl_already_prompted = buf_count > 0;
699 #else
700 if (buf_count > 0)
701 write (1, "\r", 1);
702 #endif
704 rl_callback_handler_install (prompt, line_handler);
706 num_keys++;
707 rl_callback_read_char ();
710 else /* input from inferior. */
712 int i;
713 int count;
714 int old_count;
715 if (buf_count > (sizeof(buf) >> 2))
716 buf_count = 0;
717 count = read (in_from_inferior_fd, buf+buf_count,
718 sizeof(buf) - buf_count);
719 if (count <= 0)
721 DPRINT0 ("(Connection closed by foreign host.)\n");
722 tcsetattr(STDIN_FILENO, TCSANOW, &orig_term);
723 exit (0);
725 old_count = buf_count;
727 /* Do some minimal carriage return translation and backspace
728 processing before logging the input line. */
729 if (logfile)
731 #ifndef __GNUC__
732 char *b;
733 #else
734 char b[count + 1];
735 #endif
736 int i, j;
738 #ifndef __GNUC__
739 b = malloc (count + 1);
740 if (b) {
741 #endif
742 for (i = 0; i < count; i++)
743 b[i] = buf[buf_count + i];
744 b[i] = '\0';
745 for (i = j = 0; i <= count; i++)
747 if (b[i] == '\r')
749 if (b[i+1] != '\n')
750 b[j++] = '\n';
752 else if (b[i] == '\b')
754 if (i)
755 j--;
757 else
758 b[j++] = b[i];
760 fprintf (logfile, "%s", b);
762 #ifndef __GNUC__
763 free (b);
765 #endif
768 /* Look for any pending echo that we need to suppress. */
769 while (echo_suppress_start < echo_suppress_limit
770 && count > 0
771 && buf[buf_count] == echo_suppress_buffer[echo_suppress_start])
773 count--;
774 buf_count++;
775 echo_suppress_start++;
778 /* Write to the terminal anything that was not suppressed. */
779 if (count > 0)
780 write (1, buf + buf_count, count);
782 /* Finally, look for a prompt candidate.
783 * When we get around to going input (from the keyboard),
784 * we will consider the prompt to be anything since the last
785 * line terminator. So we need to save that text in the
786 * initial part of buf. However, anything before the
787 * most recent end-of-line is not interesting. */
788 buf_count += count;
789 #if 1
790 for (i = buf_count; --i >= old_count; )
791 #else
792 for (i = buf_count - 1; i-- >= buf_count - count; )
793 #endif
795 if (buf[i] == '\n' || buf[i] == '\r')
797 i++;
798 memmove (buf, buf+i, buf_count - i);
799 buf_count -= i;
800 break;
803 DPRINT2("-> i: %d, buf_count: %d\n", i, buf_count);
810 * FILENAME COMPLETION FOR RLFE
814 #ifndef PATH_MAX
815 # define PATH_MAX 1024
816 #endif
818 #define DIRSEP '/'
819 #define ISDIRSEP(x) ((x) == '/')
820 #define PATHSEP(x) (ISDIRSEP(x) || (x) == 0)
822 #define DOT_OR_DOTDOT(x) \
823 ((x)[0] == '.' && (PATHSEP((x)[1]) || \
824 ((x)[1] == '.' && PATHSEP((x)[2]))))
826 #define FREE(x) if (x) free(x)
828 #define STRDUP(s, x) do { \
829 s = strdup (x);\
830 if (s == 0) \
831 return ((char *)NULL); \
832 } while (0)
834 static int
835 get_inferior_cwd (path, psize)
836 char *path;
837 size_t psize;
839 int n;
840 static char procfsbuf[PATH_MAX] = { '\0' };
842 if (procfsbuf[0] == '\0')
843 sprintf (procfsbuf, "/proc/%d/cwd", (int)child);
844 n = readlink (procfsbuf, path, psize);
845 if (n < 0)
846 return n;
847 if (n > psize)
848 return -1;
849 path[n] = '\0';
850 return n;
853 static int
854 rlfe_directory_rewrite_hook (dirnamep)
855 char **dirnamep;
857 char *ldirname, cwd[PATH_MAX], *retdir, *ld;
858 int n, ldlen;
860 ldirname = *dirnamep;
862 if (*ldirname == '/')
863 return 0;
865 n = get_inferior_cwd (cwd, sizeof(cwd) - 1);
866 if (n < 0)
867 return 0;
868 if (n == 0) /* current directory */
870 cwd[0] = '.';
871 cwd[1] = '\0';
872 n = 1;
875 /* Minimally canonicalize ldirname by removing leading `./' */
876 for (ld = ldirname; *ld; )
878 if (ISDIRSEP (ld[0]))
879 ld++;
880 else if (ld[0] == '.' && PATHSEP(ld[1]))
881 ld++;
882 else
883 break;
885 ldlen = (ld && *ld) ? strlen (ld) : 0;
887 retdir = (char *)malloc (n + ldlen + 3);
888 if (retdir == 0)
889 return 0;
890 if (ldlen)
891 sprintf (retdir, "%s/%s", cwd, ld);
892 else
893 strcpy (retdir, cwd);
894 free (ldirname);
896 *dirnamep = retdir;
898 DPRINT1("rl_directory_rewrite_hook returns %s\n", retdir);
899 return 1;
902 /* Translate *DIRNAMEP to be relative to the inferior's CWD. Leave a trailing
903 slash on the result. */
904 static int
905 rlfe_directory_completion_hook (dirnamep)
906 char **dirnamep;
908 char *ldirname, *retdir;
909 int n, ldlen;
911 ldirname = *dirnamep;
913 if (*ldirname == '/')
914 return 0;
916 n = rlfe_directory_rewrite_hook (dirnamep);
917 if (n == 0)
918 return 0;
920 ldirname = *dirnamep;
921 ldlen = (ldirname && *ldirname) ? strlen (ldirname) : 0;
923 if (ldlen == 0 || ldirname[ldlen - 1] != '/')
925 retdir = (char *)malloc (ldlen + 3);
926 if (retdir == 0)
927 return 0;
928 if (ldlen)
929 strcpy (retdir, ldirname);
930 else
931 retdir[ldlen++] = '.';
932 retdir[ldlen] = '/';
933 retdir[ldlen+1] = '\0';
934 free (ldirname);
936 *dirnamep = retdir;
939 DPRINT1("rl_directory_completion_hook returns %s\n", retdir);
940 return 1;
943 static char *
944 rlfe_filename_completion_function (text, state)
945 const char *text;
946 int state;
948 static DIR *directory;
949 static char *filename = (char *)NULL;
950 static char *dirname = (char *)NULL, *ud = (char *)NULL;
951 static int flen, udlen;
952 char *temp;
953 struct dirent *dentry;
955 if (state == 0)
957 if (directory)
959 closedir (directory);
960 directory = 0;
962 FREE (dirname);
963 FREE (filename);
964 FREE (ud);
966 if (text && *text)
967 STRDUP (filename, text);
968 else
970 filename = malloc(1);
971 if (filename == 0)
972 return ((char *)NULL);
973 filename[0] = '\0';
975 dirname = (text && *text) ? strdup (text) : strdup (".");
976 if (dirname == 0)
977 return ((char *)NULL);
979 temp = strrchr (dirname, '/');
980 if (temp)
982 strcpy (filename, ++temp);
983 *temp = '\0';
985 else
987 dirname[0] = '.';
988 dirname[1] = '\0';
991 STRDUP (ud, dirname);
992 udlen = strlen (ud);
994 rlfe_directory_completion_hook (&dirname);
996 directory = opendir (dirname);
997 flen = strlen (filename);
999 rl_filename_completion_desired = 1;
1002 dentry = 0;
1003 while (directory && (dentry = readdir (directory)))
1005 if (flen == 0)
1007 if (DOT_OR_DOTDOT(dentry->d_name) == 0)
1008 break;
1010 else
1012 if ((dentry->d_name[0] == filename[0]) &&
1013 (strlen (dentry->d_name) >= flen) &&
1014 (strncmp (filename, dentry->d_name, flen) == 0))
1015 break;
1019 if (dentry == 0)
1021 if (directory)
1023 closedir (directory);
1024 directory = 0;
1026 FREE (dirname);
1027 FREE (filename);
1028 FREE (ud);
1029 dirname = filename = ud = 0;
1030 return ((char *)NULL);
1033 if (ud == 0 || (ud[0] == '.' && ud[1] == '\0'))
1034 temp = strdup (dentry->d_name);
1035 else
1037 temp = malloc (1 + udlen + strlen (dentry->d_name));
1038 strcpy (temp, ud);
1039 strcpy (temp + udlen, dentry->d_name);
1041 return (temp);