[PATCH] Better subshell prompt handling



Hello,

I am posting this patch to the list since I'd like to hear your opinions on it. The patch is not trivial.

As part of its dialog loop MC watches certain file descriptors and invokes callback functions if there is data pending on those descriptors. This mechanism is employed to retrieve the subshell prompt. At startup MC install a callback for data coming from the pseudo terminal device to which the subshell is attached. Any data coming from that device while the callback is active is considered part of the prompt. While in most cases this is true there are same situations in which data is coming but it is not the prompt - consider a SIGWINCH being sent to the pseudo terminal device.

After looking the code for a while I came to the conclusion that the current setup is not as good as it could be. This patch is an attempt to simplify/fix/improve the prompt handling a bit. It does several things:

* move subshell prompt retrieval from the dialog loop to the subshell (feed_subshell). most of the code dealing with the prompt is in
subshell.c and it is not visible to other modules.

* split the prompt retrieval from displaying of the prompt

* keep two prompts - the raw prompt that is to be displayed when the panels are off and the stripped prompt which is displayed in the
command prompt widget. now one can have a colored prompt in the subshell
for example.

* some smaller fixes including a fix for:

   http://mail.gnome.org/archives/mc-devel/2004-November/msg00031.htmland

* code simplification (IMHO)

If this patch is accepted, either as is or with fixes suggested by anyone on the list I, I am going to commit some patches which depend on that one.

Thanks!

Pavel "The Prick" Tsekov
Index: src/command.c
===================================================================
RCS file: /cvsroot/mc/mc/src/command.c,v
retrieving revision 1.33
diff -u -p -r1.33 command.c
--- src/command.c	7 Jun 2005 14:16:19 -0000	1.33
+++ src/command.c	15 May 2006 15:09:09 -0000
@@ -255,8 +255,6 @@ enter (WInput *cmdline)
 	    quiet_quit_cmd ();
 	    return MSG_HANDLED;
 	}
-	if (use_subshell)
-	    load_prompt (0, 0);
 #endif
     }
     return MSG_HANDLED;
Index: src/dialog.c
===================================================================
RCS file: /cvsroot/mc/mc/src/dialog.c,v
retrieving revision 1.34
diff -u -p -r1.34 dialog.c
--- src/dialog.c	5 Sep 2005 03:20:27 -0000	1.34
+++ src/dialog.c	15 May 2006 15:09:09 -0000
@@ -36,7 +38,6 @@
 #define waddc(w,y1,x1,c) move (w->y+y1, w->x+x1); addch (c)
 
 /* Primitive way to check if the the current dialog is our dialog */
-/* This is needed by async routines like load_prompt */
 Dlg_head *current_dlg = 0;
 
 /* A hook list for idle events */
@@ -45,6 +46,8 @@ Hook *idle_hook = 0;
 static void dlg_broadcast_msg_to (Dlg_head * h, widget_msg_t message,
 				  int reverse, int flags);
 
+static void update_cursor (Dlg_head *h);
+
 static void slow_box (Dlg_head *h, int y, int x, int ys, int xs)
 {
     move (h->y+y, h->x+x);
@@ -488,7 +491,8 @@ dlg_one_down (Dlg_head *h)
 }
 
 
-void update_cursor (Dlg_head *h)
+static void
+update_cursor (Dlg_head *h)
 {
     if (!h->current)
          return;
Index: src/dialog.h
===================================================================
RCS file: /cvsroot/mc/mc/src/dialog.h,v
retrieving revision 1.25
diff -u -p -r1.25 dialog.h
--- src/dialog.h	15 Aug 2005 20:30:55 -0000	1.25
+++ src/dialog.h	15 May 2006 15:09:09 -0000
@@ -233,7 +233,4 @@ void do_refresh (void);
 #define widget_want_cursor(w,i) widget_option(w, W_WANT_CURSOR, i)
 #define widget_want_hotkey(w,i) widget_option(w, W_WANT_HOTKEY, i)
 
-/* Used in load_prompt() */
-void update_cursor (Dlg_head *h);
-
 #endif
Index: src/execute.c
===================================================================
RCS file: /cvsroot/mc/mc/src/execute.c,v
retrieving revision 1.13
diff -u -p -r1.13 execute.c
--- src/execute.c	17 Sep 2005 12:08:19 -0000	1.13
+++ src/execute.c	15 May 2006 15:09:09 -0000
@@ -113,8 +113,6 @@ do_execute (const char *shell, const cha
     }
 #ifdef HAVE_SUBSHELL_SUPPORT
     if (use_subshell && !(flags & EXECUTE_INTERNAL)) {
-	do_update_prompt ();
-
 	/* We don't care if it died, higher level takes care of this */
 #ifdef USE_VFS
 	invoke_subshell (command, VISIBLY, old_vfs_dir ? 0 : &new_dir);
@@ -156,6 +154,8 @@ do_execute (const char *shell, const cha
     if (new_dir)
 	do_possible_cd (new_dir);
 
+    load_prompt ();
+
 #endif				/* HAVE_SUBSHELL_SUPPORT */
 
 #ifdef USE_VFS
@@ -271,9 +271,9 @@ toggle_panels (void)
 
 #ifdef HAVE_SUBSHELL_SUPPORT
     if (use_subshell) {
-	load_prompt (0, 0);
 	if (new_dir)
 	    do_possible_cd (new_dir);
+	load_prompt ();
 	if (console_flag && output_lines)
 	    show_console_contents (output_start_y,
 				   LINES - keybar_visible - output_lines -
Index: src/subshell.c
===================================================================
RCS file: /cvsroot/mc/mc/src/subshell.c,v
retrieving revision 1.92
diff -u -p -r1.92 subshell.c
--- src/subshell.c	8 May 2006 14:38:36 -0000	1.92
+++ src/subshell.c	15 May 2006 15:09:10 -0000
@@ -47,7 +47,7 @@
 #include "tty.h"	/* LINES */
 #include "panel.h"	/* current_panel */
 #include "wtools.h"	/* query_dialog() */
-#include "main.h"	/* do_update_prompt() */
+#include "main.h"
 #include "cons.saver.h"	/* handle_console() */
 #include "key.h"	/* XCTRL */
 #include "subshell.h"
@@ -70,6 +70,8 @@ static void synchronize (void);
 static int pty_open_master (char *pty_name);
 static int pty_open_slave (const char *pty_name);
 static int resize_tty (int fd);
+static int read_subshell_prompt (void);
+static void do_update_prompt (void);
 
 #ifndef STDIN_FILENO
 #    define STDIN_FILENO 0
@@ -92,7 +94,7 @@ TRUE;
 #endif
 
 /* File descriptor of the pseudoterminal used by the subshell */
-int subshell_pty = 0;
+static int subshell_pty = 0;
 
 /* The key for switching back to MC from the subshell */
 static const char subshell_switch_key = XCTRL('o') & 255;
@@ -106,6 +108,8 @@ enum subshell_state_enum subshell_state;
 /* Holds the latest prompt captured from the subshell */
 char *subshell_prompt = NULL;
 
+int subshell_prompt_length;
+
 /* Initial length of the buffer for the subshell's prompt */
 #define INITIAL_PROMPT_SIZE 10
 
@@ -144,10 +148,12 @@ static struct termios shell_mode;
 /* are delivered to the shell pty */
 static struct termios raw_mode;
 
-/* This counter indicates how many characters of prompt we have read */
-/* FIXME: try to figure out why this had to become global */
-static int prompt_pos;
+/* This variable holds the control sequence (if any) which instructs the
+   terminal to clear the current line starting at the cursor position to
+   the end of the line. */
+static const char *clr_eol_sequence;
 
+static int clr_eol_sequence_length;
 
 /*
  *  Write all data, even if the write() call is interrupted.
@@ -372,6 +378,10 @@ init_subshell (void)
     char precmd[BUF_SMALL];
     int pty_slave = -1;
 
+    clr_eol_sequence = tty_tgetstr ("ce");
+    if (clr_eol_sequence != NULL)
+	clr_eol_sequence_length = strlen (clr_eol_sequence);
+
 #ifdef HAVE_GETSID
     switch (check_sid ()) {
     case 1:
@@ -545,11 +555,14 @@ int invoke_subshell (const char *command
 {
     /* Make the MC terminal transparent */
     tcsetattr (STDOUT_FILENO, TCSANOW, &raw_mode);
-    
+
     /* Make the subshell change to MC's working directory */
     if (new_dir)
-	do_subshell_chdir (current_panel->cwd, TRUE, 1);
-    
+	do_subshell_chdir (current_panel->cwd);
+
+    if (how == VISIBLY)
+	do_update_prompt ();
+   
     if (command == NULL)  /* The user has done "C-o" from MC */
     {
 	if (subshell_state == INACTIVE)
@@ -580,17 +593,16 @@ int invoke_subshell (const char *command
     while (!subshell_alive && !quit && use_subshell)
 	init_subshell ();
 
-    prompt_pos = 0;
-
     return quit;
 }
 
 
-int
+static int
 read_subshell_prompt (void)
 {
     static int prompt_size = INITIAL_PROMPT_SIZE;
-    int bytes = 0, i, rc = 0;
+    int bytes = 0, rc = 0;
+    int prompt_pos = 0;
     struct timeval timeleft = { 0, 0 };
 
     fd_set tmp;
@@ -599,8 +611,6 @@ read_subshell_prompt (void)
 
     if (subshell_prompt == NULL) {	/* First time through */
 	subshell_prompt = g_malloc (prompt_size);
-	*subshell_prompt = '\0';
-	prompt_pos = 0;
     }
 
     while (subshell_alive
@@ -617,25 +627,15 @@ read_subshell_prompt (void)
 	    }
 	}
 
-	bytes = read (subshell_pty, pty_buffer, pty_buffer_size);
-
-	/* Extract the prompt from the shell output */
-
-	for (i = 0; i < bytes; ++i)
-	    if (pty_buffer[i] == '\n' || pty_buffer[i] == '\r') {
-		prompt_pos = 0;
-	    } else {
-		if (!pty_buffer[i])
-		    continue;
-
-		subshell_prompt[prompt_pos++] = pty_buffer[i];
-		if (prompt_pos == prompt_size)
-		    subshell_prompt =
-			g_realloc (subshell_prompt, prompt_size *= 2);
-	    }
-
-	subshell_prompt[prompt_pos] = '\0';
+	bytes = read (subshell_pty, &subshell_prompt[prompt_pos],
+			prompt_size - prompt_pos);
+	prompt_pos += bytes;
+
+	if (prompt_pos == prompt_size)
+	    subshell_prompt =
+		g_realloc (subshell_prompt, prompt_size *= 2);
     }
+    subshell_prompt_length = prompt_pos;
     if (rc == 0 && bytes == 0)
 	return FALSE;
     return TRUE;
@@ -778,17 +778,11 @@ subshell_name_quote (const char *s)
 
 /* If it actually changed the directory it returns true */
 void
-do_subshell_chdir (const char *directory, int do_update, int reset_prompt)
+do_subshell_chdir (const char *directory)
 {
     if (!
 	(subshell_state == INACTIVE
 	 && strcmp (subshell_cwd, current_panel->cwd))) {
-	/* We have to repaint the subshell prompt if we read it from
-	 * the main program.  Please note that in the code after this
-	 * if, the cd command that is sent will make the subshell
-	 * repaint the prompt, so we don't have to paint it. */
-	if (do_update)
-	    do_update_prompt ();
 	return;
     }
 
@@ -839,9 +833,6 @@ do_subshell_chdir (const char *directory
 	}
     }
 
-    if (reset_prompt)
-	prompt_pos = 0;
-    update_prompt = FALSE;
     /* Make sure that MC never stores the CWD in a silly format */
     /* like /usr////lib/../bin, or the strcmp() above will fail */
 }
@@ -924,10 +915,13 @@ feed_subshell (int how, int fail_on_erro
     int maxfdp;
     int bytes;			/* For the return value from `read' */
     int i;			/* Loop counter */
+    int wait_prompt;
 
     struct timeval wtime;	/* Maximum time we wait for the subshell */
     struct timeval *wptr;
 
+    wait_prompt = 0;
+
     /* we wait up to 10 seconds if fail_on_error, forever otherwise */
     wtime.tv_sec = 10;
     wtime.tv_usec = 0;
@@ -941,11 +935,14 @@ feed_subshell (int how, int fail_on_erro
 
 	FD_ZERO (&read_set);
 	FD_SET (subshell_pty, &read_set);
-	FD_SET (subshell_pipe[READ], &read_set);
-	maxfdp = max (subshell_pty, subshell_pipe[READ]);
-	if (how == VISIBLY) {
-	    FD_SET (STDIN_FILENO, &read_set);
-	    maxfdp = max (maxfdp, STDIN_FILENO);
+	maxfdp = subshell_pty;
+	if (wait_prompt == 0) {
+	    FD_SET (subshell_pipe[READ], &read_set);
+	    maxfdp = max (subshell_pty, subshell_pipe[READ]);
+	    if (how == VISIBLY) {
+		FD_SET (STDIN_FILENO, &read_set);
+		maxfdp = max (maxfdp, STDIN_FILENO);
+	    }
 	}
 
 	if (select (maxfdp + 1, &read_set, NULL, NULL, wptr) == -1) {
@@ -962,11 +959,20 @@ feed_subshell (int how, int fail_on_erro
 	if (FD_ISSET (subshell_pty, &read_set))
 	    /* Read from the subshell, write to stdout */
 
-	    /* This loop improves performance by reducing context switches
-	       by a factor of 20 or so... unfortunately, it also hangs MC
-	       randomly, because of an apparent Linux bug.  Investigate. */
-	    /* for (i=0; i<5; ++i)  * FIXME -- experimental */
 	{
+	    if (wait_prompt != 0) {
+		if (read_subshell_prompt () == 0)
+		    continue;
+
+		wait_prompt = 0;
+
+		if (subshell_state == ACTIVE) {
+		    do_update_prompt ();
+		    continue;
+		}
+		return 1;
+	    }
+
 	    bytes = read (subshell_pty, pty_buffer, pty_buffer_size);
 
 	    /* The subshell has died */
@@ -1002,10 +1008,11 @@ feed_subshell (int how, int fail_on_erro
 
 	    synchronize ();
 
+	    wait_prompt = 1;
 	    subshell_ready = TRUE;
 	    if (subshell_state == RUNNING_COMMAND) {
 		subshell_state = INACTIVE;
-		return 1;
+		continue;
 	    }
 	}
 
@@ -1207,4 +1214,14 @@ pty_open_slave (const char *pty_name)
 }
 
 #endif /* !HAVE_GRANTPT */
+
+static void
+do_update_prompt (void)
+{
+    write (STDOUT_FILENO, "\r", 1);
+    if (clr_eol_sequence != NULL)
+	write_all (STDOUT_FILENO, clr_eol_sequence, clr_eol_sequence_length);
+    write_all (STDOUT_FILENO, subshell_prompt, subshell_prompt_length);
+}
+
 #endif /* HAVE_SUBSHELL_SUPPORT */
Index: src/subshell.h
===================================================================
RCS file: /cvsroot/mc/mc/src/subshell.h,v
retrieving revision 1.8
diff -u -p -r1.8 subshell.h
--- src/subshell.h	3 Dec 2004 19:17:47 -0000	1.8
+++ src/subshell.h	15 May 2006 15:09:10 -0000
@@ -10,9 +10,6 @@
 /* If using a subshell for evaluating commands this is true */
 extern int use_subshell;
 
-/* File descriptor of the pseudoterminal used by the subshell */
-extern int subshell_pty;
-
 /* State of the subshell; see subshell.c for an explanation */
 enum subshell_state_enum {INACTIVE, ACTIVE, RUNNING_COMMAND};
 extern enum subshell_state_enum subshell_state;
@@ -20,16 +17,17 @@ extern enum subshell_state_enum subshell
 /* Holds the latest prompt captured from the subshell */
 extern char *subshell_prompt;
 
+extern int subshell_prompt_length;
+
 /* For the `how' argument to various functions */
 enum {QUIETLY, VISIBLY};
 
 /* Exported functions */
 void init_subshell (void);
 int invoke_subshell (const char *command, int how, char **new_dir);
-int read_subshell_prompt (void);
 void resize_subshell (void);
 int exit_subshell (void);
-void do_subshell_chdir (const char *directory, int update_prompt, int reset_prompt);
+void do_subshell_chdir (const char *directory);
 void subshell_get_console_attributes (void);
 void sigchld_handler (int sig);
 
Index: src/main.c
===================================================================
RCS file: /cvsroot/mc/mc/src/main.c,v
retrieving revision 1.367
diff -u -p -r1.367 main.c
--- src/main.c	15 May 2006 13:26:18 -0000	1.367
+++ src/main.c	15 May 2006 15:09:10 -0000
@@ -175,7 +175,7 @@ int force_ugly_line_drawing = 0;
 int reset_hp_softkeys = 0;
 
 /* The prompt */
-const char *prompt = NULL;
+char *prompt = NULL;
 
 /* The widget where we draw the prompt */
 WLabel *the_prompt;
@@ -226,10 +226,6 @@ int drop_menus = 0;
 /* The dialog handle for the main program */
 Dlg_head *midnight_dlg;
 
-/* Subshell: if set, then the prompt was not saved on CONSOLE_SAVE */
-/* We need to paint it after CONSOLE_RESTORE, see: load_prompt */
-int update_prompt = 0;
-
 /* The home directory */
 const char *home_dir = NULL;
 
@@ -430,16 +426,6 @@ do_possible_cd (const char *new_dir)
 		   " deleted your working directory, or given yourself \n"
 		   " extra access permissions with the \"su\" command? "));
 }
-
-void
-do_update_prompt (void)
-{
-    if (update_prompt) {
-	printf ("%s", subshell_prompt);
-	fflush (stdout);
-	update_prompt = 0;
-    }
-}
 #endif				/* HAVE_SUBSHELL_SUPPORT */
 
 void
@@ -520,8 +506,11 @@ subshell_chdir (const char *directory)
 {
 #ifdef HAVE_SUBSHELL_SUPPORT
     if (use_subshell) {
-	if (vfs_current_is_local ())
-	    do_subshell_chdir (directory, 0, 1);
+	if (vfs_current_is_local ()) {
+	    do_subshell_chdir (directory);
+
+	    load_prompt ();
+	}
     }
 #endif				/* HAVE_SUBSHELL_SUPPORT */
 }
@@ -689,21 +678,29 @@ directory_history_list (WPanel *panel)
 }
 
 #ifdef HAVE_SUBSHELL_SUPPORT
-int
-load_prompt (int fd, void *unused)
+void
+load_prompt (void)
 {
-    (void) fd;
-    (void) unused;
+	char *tmp_prompt, *prompt_end;
+	char *dst_prompt;
+	int prompt_len;
 
-    if (!read_subshell_prompt ())
-	return 0;
+	prompt_end = subshell_prompt + subshell_prompt_length;
+	for (tmp_prompt = prompt_end - 1; tmp_prompt > subshell_prompt; tmp_prompt--) {
+	    if (*tmp_prompt == '\n' || *tmp_prompt == '\r') {
+		tmp_prompt++;
+		break;
+	    }
+	}
 
-    /* Don't actually change the prompt if it's invisible */
-    if (current_dlg == midnight_dlg && command_prompt) {
-	char *tmp_prompt;
-	int prompt_len;
+	if (tmp_prompt == prompt_end)
+	    return;
+
+	prompt_len = prompt_end - tmp_prompt;
+	dst_prompt = g_malloc (prompt_len + 1);
+	memcpy (dst_prompt, tmp_prompt, prompt_len);
 
-	tmp_prompt = strip_ctrl_codes (subshell_prompt);
+	tmp_prompt = strip_ctrl_codes (dst_prompt, prompt_len);
 	prompt_len = strlen (tmp_prompt);
 
 	/* Check for prompts too big */
@@ -711,20 +708,17 @@ load_prompt (int fd, void *unused)
 	    tmp_prompt[COLS - 8] = '\0';
 	    prompt_len = COLS - 8;
 	}
+	g_free (prompt);
 	prompt = tmp_prompt;
+
+    /* Don't actually change the prompt if it's invisible */
+    if (midnight_dlg == NULL)
+	return;
+    if (current_dlg == midnight_dlg && command_prompt) {
 	label_set_text (the_prompt, prompt);
 	winput_set_origin ((WInput *) cmdline, prompt_len,
 			   COLS - prompt_len);
-
-	/* since the prompt has changed, and we are called from one of the 
-	 * get_event channels, the prompt updating does not take place
-	 * automatically: force a cursor update and a screen refresh
-	 */
-	update_cursor (midnight_dlg);
-	mc_refresh ();
     }
-    update_prompt = 1;
-    return 0;
 }
 #endif				/* HAVE_SUBSHELL_SUPPORT */
 
@@ -1392,11 +1386,6 @@ setup_mc (void)
     create_panels ();
     setup_panels ();
 
-#ifdef HAVE_SUBSHELL_SUPPORT
-    if (use_subshell)
-	add_select_channel (subshell_pty, load_prompt, 0);
-#endif				/* !HAVE_SUBSHELL_SUPPORT */
-
     setup_sigwinch ();
 
     if (baudrate () < 9600 || slow_terminal) {
@@ -2231,12 +2220,10 @@ main (int argc, char *argv[])
     }
 #ifdef HAVE_SUBSHELL_SUPPORT
     if (use_subshell) {
-	prompt = strip_ctrl_codes (subshell_prompt);
-	if (!prompt)
-	    prompt = "";
+	load_prompt ();
     } else
 #endif				/* HAVE_SUBSHELL_SUPPORT */
-	prompt = (geteuid () == 0) ? "# " : "$ ";
+	prompt = g_strdup ((geteuid () == 0) ? "# " : "$ ");
 
     /* Program main loop */
     if (!midnight_shutdown)
@@ -2286,6 +2273,7 @@ main (int argc, char *argv[])
 #endif
     g_free (this_dir);
     g_free (other_dir);
+    g_free (prompt);
 
     return 0;
 }
Index: src/main.h
===================================================================
RCS file: /cvsroot/mc/mc/src/main.h,v
retrieving revision 1.64
diff -u -p -r1.64 main.h
--- src/main.h	3 Feb 2006 17:07:39 -0000	1.64
+++ src/main.h	15 May 2006 15:09:10 -0000
@@ -54,7 +54,6 @@ extern int drop_menus;
 extern int cd_symlinks;
 extern int show_all_if_ambiguous;
 extern int slow_terminal;
-extern int update_prompt;	/* To comunicate with subshell */
 extern int safe_delete;
 extern int confirm_delete;
 extern int confirm_directory_hotlist_delete;
@@ -71,6 +70,9 @@ extern int output_starts_shell;
 extern int midnight_shutdown;
 extern char cmd_buf [512];
 extern const char *shell;
+#ifdef HAVE_TEXTMODE_X11_SUPPORT
+extern int ignore_window_system;
+#endif
 
 /* Ugly hack in order to distinguish between left and right panel in menubar */
 extern int is_right;		/* If the selected menu was the right */
@@ -88,7 +90,6 @@ typedef struct {
 
 void update_panels (int force_update, const char *current_file);
 void repaint_screen (void);
-void do_update_prompt (void);
 
 enum cd_enum {
     cd_parse_command,
@@ -97,7 +98,7 @@ enum cd_enum {
 
 int do_cd           (const char *new_dir, enum cd_enum cd_type); /* For find.c */
 void change_panel   (void);
-int load_prompt     (int, void *);
+void load_prompt     (void);
 void save_cwds_stat (void);
 void quiet_quit_cmd (void);	/* For cmd.c and command.c */
 
@@ -108,7 +109,7 @@ void load_hint      (int force);
 void print_vfs_message(const char *msg, ...)
     __attribute__ ((format (__printf__, 1, 2)));
 
-extern const char *prompt;
+extern char *prompt;
 extern const char *edit_one_file;
 extern char *mc_home;
 char *get_mc_lib_dir (void);
Index: src/util.c
===================================================================
RCS file: /cvsroot/mc/mc/src/util.c,v
retrieving revision 1.138
diff -u -p -r1.138 util.c
--- src/util.c	3 Nov 2005 02:18:38 -0000	1.138
+++ src/util.c	15 May 2006 15:09:10 -0000
@@ -876,15 +876,16 @@ skip_numbers (const char *s)
  */
 
 char *
-strip_ctrl_codes (char *s)
+strip_ctrl_codes (char *s, int len)
 {
     char *w; /* Current position where the stripped data is written */
     char *r; /* Current position where the original data is read */
+    const char * const ends = s + len;
 
     if (!s)
 	return 0;
 
-    for (w = s, r = s; *r; ) {
+    for (w = s, r = s; r < ends; ) {
 	if (*r == ESC_CHAR) {
 	    /* Skip the control sequence's arguments */ ;
 	    if (*(++r) == '[') {
Index: src/util.h
===================================================================
RCS file: /cvsroot/mc/mc/src/util.h,v
retrieving revision 1.78
diff -u -p -r1.78 util.h
--- src/util.h	3 Feb 2006 17:04:17 -0000	1.78
+++ src/util.h	15 May 2006 15:09:10 -0000
@@ -70,7 +70,7 @@ char *concat_dir_and_file (const char *d
 const char *unix_error_string (int error_num);
 const char *skip_separators (const char *s);
 const char *skip_numbers (const char *s);
-char *strip_ctrl_codes (char *s);
+char *strip_ctrl_codes (char *s, int len);
 
 /* Replaces "\\E" and "\\e" with "\033". Replaces "^" + [a-z] with
  * ((char) 1 + (c - 'a')). The same goes for "^" + [A-Z].


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]