xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/tui/tui-io.c (revision cef8759bd76c1b621f8eab8faa6f208faabc2e15)
1 /* TUI support I/O functions.
2 
3    Copyright (C) 1998-2017 Free Software Foundation, Inc.
4 
5    Contributed by Hewlett-Packard Company.
6 
7    This file is part of GDB.
8 
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
21 
22 #include "defs.h"
23 #include "target.h"
24 #include "event-loop.h"
25 #include "event-top.h"
26 #include "command.h"
27 #include "top.h"
28 #include "tui/tui.h"
29 #include "tui/tui-data.h"
30 #include "tui/tui-io.h"
31 #include "tui/tui-command.h"
32 #include "tui/tui-win.h"
33 #include "tui/tui-wingeneral.h"
34 #include "tui/tui-file.h"
35 #include "tui/tui-out.h"
36 #include "ui-out.h"
37 #include "cli-out.h"
38 #include <fcntl.h>
39 #include <signal.h>
40 #include "filestuff.h"
41 #include "completer.h"
42 #include "gdb_curses.h"
43 
44 /* This redefines CTRL if it is not already defined, so it must come
45    after terminal state releated include files like <term.h> and
46    "gdb_curses.h".  */
47 #include "readline/readline.h"
48 
49 int
50 key_is_start_sequence (int ch)
51 {
52   return (ch == 27);
53 }
54 
55 int
56 key_is_end_sequence (int ch)
57 {
58   return (ch == 126);
59 }
60 
61 int
62 key_is_backspace (int ch)
63 {
64   return (ch == 8);
65 }
66 
67 /* Use definition from readline 4.3.  */
68 #undef CTRL_CHAR
69 #define CTRL_CHAR(c) \
70      ((c) < control_character_threshold && (((c) & 0x80) == 0))
71 
72 /* This file controls the IO interactions between gdb and curses.
73    When the TUI is enabled, gdb has two modes a curses and a standard
74    mode.
75 
76    In curses mode, the gdb outputs are made in a curses command
77    window.  For this, the gdb_stdout and gdb_stderr are redirected to
78    the specific ui_file implemented by TUI.  The output is handled by
79    tui_puts().  The input is also controlled by curses with
80    tui_getc().  The readline library uses this function to get its
81    input.  Several readline hooks are installed to redirect readline
82    output to the TUI (see also the note below).
83 
84    In normal mode, the gdb outputs are restored to their origin, that
85    is as if TUI is not used.  Readline also uses its original getc()
86    function with stdin.
87 
88    Note SCz/2001-07-21: the current readline is not clean in its
89    management of the output.  Even if we install a redisplay handler,
90    it sometimes writes on a stdout file.  It is important to redirect
91    every output produced by readline, otherwise the curses window will
92    be garbled.  This is implemented with a pipe that TUI reads and
93    readline writes to.  A gdb input handler is created so that reading
94    the pipe is handled automatically.  This will probably not work on
95    non-Unix platforms.  The best fix is to make readline clean enougth
96    so that is never write on stdout.
97 
98    Note SCz/2002-09-01: we now use more readline hooks and it seems
99    that with them we don't need the pipe anymore (verified by creating
100    the pipe and closing its end so that write causes a SIGPIPE).  The
101    old pipe code is still there and can be conditionally removed by
102    #undef TUI_USE_PIPE_FOR_READLINE.  */
103 
104 /* For gdb 5.3, prefer to continue the pipe hack as a backup wheel.  */
105 #ifdef HAVE_PIPE
106 #define TUI_USE_PIPE_FOR_READLINE
107 #endif
108 /* #undef TUI_USE_PIPE_FOR_READLINE */
109 
110 /* TUI output files.  */
111 static struct ui_file *tui_stdout;
112 static struct ui_file *tui_stderr;
113 struct ui_out *tui_out;
114 
115 /* GDB output files in non-curses mode.  */
116 static struct ui_file *tui_old_stdout;
117 static struct ui_file *tui_old_stderr;
118 cli_ui_out *tui_old_uiout;
119 
120 /* Readline previous hooks.  */
121 static rl_getc_func_t *tui_old_rl_getc_function;
122 static rl_voidfunc_t *tui_old_rl_redisplay_function;
123 static rl_vintfunc_t *tui_old_rl_prep_terminal;
124 static rl_voidfunc_t *tui_old_rl_deprep_terminal;
125 static rl_compdisp_func_t *tui_old_rl_display_matches_hook;
126 static int tui_old_rl_echoing_p;
127 
128 /* Readline output stream.
129    Should be removed when readline is clean.  */
130 static FILE *tui_rl_outstream;
131 static FILE *tui_old_rl_outstream;
132 #ifdef TUI_USE_PIPE_FOR_READLINE
133 static int tui_readline_pipe[2];
134 #endif
135 
136 /* The last gdb prompt that was registered in readline.
137    This may be the main gdb prompt or a secondary prompt.  */
138 static char *tui_rl_saved_prompt;
139 
140 /* Print a character in the curses command window.  The output is
141    buffered.  It is up to the caller to refresh the screen if
142    necessary.  */
143 
144 static void
145 do_tui_putc (WINDOW *w, char c)
146 {
147   static int tui_skip_line = -1;
148 
149   /* Catch annotation and discard them.  We need two \032 and discard
150      until a \n is seen.  */
151   if (c == '\032')
152     {
153       tui_skip_line++;
154     }
155   else if (tui_skip_line != 1)
156     {
157       tui_skip_line = -1;
158       /* Expand TABs, since ncurses on MS-Windows doesn't.  */
159       if (c == '\t')
160 	{
161 	  int col;
162 
163 	  col = getcurx (w);
164 	  do
165 	    {
166 	      waddch (w, ' ');
167 	      col++;
168 	    }
169 	  while ((col % 8) != 0);
170 	}
171       else
172 	waddch (w, c);
173     }
174   else if (c == '\n')
175     tui_skip_line = -1;
176 }
177 
178 /* Update the cached value of the command window's start line based on
179    the window's current Y coordinate.  */
180 
181 static void
182 update_cmdwin_start_line ()
183 {
184   TUI_CMD_WIN->detail.command_info.start_line
185     = getcury (TUI_CMD_WIN->generic.handle);
186 }
187 
188 /* Print a character in the curses command window.  The output is
189    buffered.  It is up to the caller to refresh the screen if
190    necessary.  */
191 
192 static void
193 tui_putc (char c)
194 {
195   WINDOW *w = TUI_CMD_WIN->generic.handle;
196 
197   do_tui_putc (w, c);
198   update_cmdwin_start_line ();
199 }
200 
201 /* Print LENGTH characters from the buffer pointed to by BUF to the
202    curses command window.  The output is buffered.  It is up to the
203    caller to refresh the screen if necessary.  */
204 
205 void
206 tui_write (const char *buf, size_t length)
207 {
208   WINDOW *w = TUI_CMD_WIN->generic.handle;
209 
210   for (size_t i = 0; i < length; i++)
211     do_tui_putc (w, buf[i]);
212   update_cmdwin_start_line ();
213 }
214 
215 /* Print a string in the curses command window.  The output is
216    buffered.  It is up to the caller to refresh the screen if
217    necessary.  */
218 
219 void
220 tui_puts (const char *string)
221 {
222   WINDOW *w = TUI_CMD_WIN->generic.handle;
223   char c;
224 
225   while ((c = *string++) != 0)
226     do_tui_putc (w, c);
227   update_cmdwin_start_line ();
228 }
229 
230 /* Readline callback.
231    Redisplay the command line with its prompt after readline has
232    changed the edited text.  */
233 void
234 tui_redisplay_readline (void)
235 {
236   int prev_col;
237   int height;
238   int col;
239   int c_pos;
240   int c_line;
241   int in;
242   WINDOW *w;
243   const char *prompt;
244   int start_line;
245 
246   /* Detect when we temporarily left SingleKey and now the readline
247      edit buffer is empty, automatically restore the SingleKey
248      mode.  The restore must only be done if the command has finished.
249      The command could call prompt_for_continue and we must not
250      restore SingleKey so that the prompt and normal keymap are used.  */
251   if (tui_current_key_mode == TUI_ONE_COMMAND_MODE && rl_end == 0
252       && !gdb_in_secondary_prompt_p (current_ui))
253     tui_set_key_mode (TUI_SINGLE_KEY_MODE);
254 
255   if (tui_current_key_mode == TUI_SINGLE_KEY_MODE)
256     prompt = "";
257   else
258     prompt = tui_rl_saved_prompt;
259 
260   c_pos = -1;
261   c_line = -1;
262   w = TUI_CMD_WIN->generic.handle;
263   start_line = TUI_CMD_WIN->detail.command_info.start_line;
264   wmove (w, start_line, 0);
265   prev_col = 0;
266   height = 1;
267   for (in = 0; prompt && prompt[in]; in++)
268     {
269       waddch (w, prompt[in]);
270       col = getcurx (w);
271       if (col <= prev_col)
272         height++;
273       prev_col = col;
274     }
275   for (in = 0; in <= rl_end; in++)
276     {
277       unsigned char c;
278 
279       if (in == rl_point)
280 	{
281           getyx (w, c_line, c_pos);
282 	}
283 
284       if (in == rl_end)
285         break;
286 
287       c = (unsigned char) rl_line_buffer[in];
288       if (CTRL_CHAR (c) || c == RUBOUT)
289 	{
290           waddch (w, '^');
291           waddch (w, CTRL_CHAR (c) ? UNCTRL (c) : '?');
292 	}
293       else if (c == '\t')
294 	{
295 	  /* Expand TABs, since ncurses on MS-Windows doesn't.  */
296 	  col = getcurx (w);
297 	  do
298 	    {
299 	      waddch (w, ' ');
300 	      col++;
301 	    } while ((col % 8) != 0);
302 	}
303       else
304 	{
305           waddch (w, c);
306 	}
307       if (c == '\n')
308 	TUI_CMD_WIN->detail.command_info.start_line = getcury (w);
309       col = getcurx (w);
310       if (col < prev_col)
311         height++;
312       prev_col = col;
313     }
314   wclrtobot (w);
315   TUI_CMD_WIN->detail.command_info.start_line = getcury (w);
316   if (c_line >= 0)
317     wmove (w, c_line, c_pos);
318   TUI_CMD_WIN->detail.command_info.start_line -= height - 1;
319 
320   wrefresh (w);
321   fflush(stdout);
322 }
323 
324 /* Readline callback to prepare the terminal.  It is called once each
325    time we enter readline.  Terminal is already setup in curses
326    mode.  */
327 static void
328 tui_prep_terminal (int notused1)
329 {
330   /* Save the prompt registered in readline to correctly display it.
331      (we can't use gdb_prompt() due to secondary prompts and can't use
332      rl_prompt because it points to an alloca buffer).  */
333   xfree (tui_rl_saved_prompt);
334   tui_rl_saved_prompt = rl_prompt != NULL ? xstrdup (rl_prompt) : NULL;
335 }
336 
337 /* Readline callback to restore the terminal.  It is called once each
338    time we leave readline.  There is nothing to do in curses mode.  */
339 static void
340 tui_deprep_terminal (void)
341 {
342 }
343 
344 #ifdef TUI_USE_PIPE_FOR_READLINE
345 /* Read readline output pipe and feed the command window with it.
346    Should be removed when readline is clean.  */
347 static void
348 tui_readline_output (int error, gdb_client_data data)
349 {
350   int size;
351   char buf[256];
352 
353   size = read (tui_readline_pipe[0], buf, sizeof (buf) - 1);
354   if (size > 0 && tui_active)
355     {
356       buf[size] = 0;
357       tui_puts (buf);
358     }
359 }
360 #endif
361 
362 /* TUI version of displayer.crlf.  */
363 
364 static void
365 tui_mld_crlf (const struct match_list_displayer *displayer)
366 {
367   tui_putc ('\n');
368 }
369 
370 /* TUI version of displayer.putch.  */
371 
372 static void
373 tui_mld_putch (const struct match_list_displayer *displayer, int ch)
374 {
375   tui_putc (ch);
376 }
377 
378 /* TUI version of displayer.puts.  */
379 
380 static void
381 tui_mld_puts (const struct match_list_displayer *displayer, const char *s)
382 {
383   tui_puts (s);
384 }
385 
386 /* TUI version of displayer.flush.  */
387 
388 static void
389 tui_mld_flush (const struct match_list_displayer *displayer)
390 {
391   wrefresh (TUI_CMD_WIN->generic.handle);
392 }
393 
394 /* TUI version of displayer.erase_entire_line.  */
395 
396 static void
397 tui_mld_erase_entire_line (const struct match_list_displayer *displayer)
398 {
399   WINDOW *w = TUI_CMD_WIN->generic.handle;
400   int cur_y = getcury (w);
401 
402   wmove (w, cur_y, 0);
403   wclrtoeol (w);
404   wmove (w, cur_y, 0);
405 }
406 
407 /* TUI version of displayer.beep.  */
408 
409 static void
410 tui_mld_beep (const struct match_list_displayer *displayer)
411 {
412   beep ();
413 }
414 
415 /* Helper function for tui_mld_read_key.
416    This temporarily replaces tui_getc for use during tab-completion
417    match list display.  */
418 
419 static int
420 tui_mld_getc (FILE *fp)
421 {
422   WINDOW *w = TUI_CMD_WIN->generic.handle;
423   int c = wgetch (w);
424 
425   return c;
426 }
427 
428 /* TUI version of displayer.read_key.  */
429 
430 static int
431 tui_mld_read_key (const struct match_list_displayer *displayer)
432 {
433   rl_getc_func_t *prev = rl_getc_function;
434   int c;
435 
436   /* We can't use tui_getc as we need NEWLINE to not get emitted.  */
437   rl_getc_function = tui_mld_getc;
438   c = rl_read_key ();
439   rl_getc_function = prev;
440   return c;
441 }
442 
443 /* TUI version of rl_completion_display_matches_hook.
444    See gdb_display_match_list for a description of the arguments.  */
445 
446 static void
447 tui_rl_display_match_list (char **matches, int len, int max)
448 {
449   struct match_list_displayer displayer;
450 
451   rl_get_screen_size (&displayer.height, &displayer.width);
452   displayer.crlf = tui_mld_crlf;
453   displayer.putch = tui_mld_putch;
454   displayer.puts = tui_mld_puts;
455   displayer.flush = tui_mld_flush;
456   displayer.erase_entire_line = tui_mld_erase_entire_line;
457   displayer.beep = tui_mld_beep;
458   displayer.read_key = tui_mld_read_key;
459 
460   gdb_display_match_list (matches, len, max, &displayer);
461 }
462 
463 /* Setup the IO for curses or non-curses mode.
464    - In non-curses mode, readline and gdb use the standard input and
465    standard output/error directly.
466    - In curses mode, the standard output/error is controlled by TUI
467    with the tui_stdout and tui_stderr.  The output is redirected in
468    the curses command window.  Several readline callbacks are installed
469    so that readline asks for its input to the curses command window
470    with wgetch().  */
471 void
472 tui_setup_io (int mode)
473 {
474   extern int _rl_echoing_p;
475 
476   if (mode)
477     {
478       /* Redirect readline to TUI.  */
479       tui_old_rl_redisplay_function = rl_redisplay_function;
480       tui_old_rl_deprep_terminal = rl_deprep_term_function;
481       tui_old_rl_prep_terminal = rl_prep_term_function;
482       tui_old_rl_getc_function = rl_getc_function;
483       tui_old_rl_display_matches_hook = rl_completion_display_matches_hook;
484       tui_old_rl_outstream = rl_outstream;
485       tui_old_rl_echoing_p = _rl_echoing_p;
486       rl_redisplay_function = tui_redisplay_readline;
487       rl_deprep_term_function = tui_deprep_terminal;
488       rl_prep_term_function = tui_prep_terminal;
489       rl_getc_function = tui_getc;
490       _rl_echoing_p = 0;
491       rl_outstream = tui_rl_outstream;
492       rl_prompt = 0;
493       rl_completion_display_matches_hook = tui_rl_display_match_list;
494       rl_already_prompted = 0;
495 
496       /* Keep track of previous gdb output.  */
497       tui_old_stdout = gdb_stdout;
498       tui_old_stderr = gdb_stderr;
499       tui_old_uiout = dynamic_cast<cli_ui_out *> (current_uiout);
500       gdb_assert (tui_old_uiout != nullptr);
501 
502       /* Reconfigure gdb output.  */
503       gdb_stdout = tui_stdout;
504       gdb_stderr = tui_stderr;
505       gdb_stdlog = gdb_stdout;	/* for moment */
506       gdb_stdtarg = gdb_stderr;	/* for moment */
507       gdb_stdtargerr = gdb_stderr;	/* for moment */
508       current_uiout = tui_out;
509 
510       /* Save tty for SIGCONT.  */
511       savetty ();
512     }
513   else
514     {
515       /* Restore gdb output.  */
516       gdb_stdout = tui_old_stdout;
517       gdb_stderr = tui_old_stderr;
518       gdb_stdlog = gdb_stdout;	/* for moment */
519       gdb_stdtarg = gdb_stderr;	/* for moment */
520       gdb_stdtargerr = gdb_stderr;	/* for moment */
521       current_uiout = tui_old_uiout;
522 
523       /* Restore readline.  */
524       rl_redisplay_function = tui_old_rl_redisplay_function;
525       rl_deprep_term_function = tui_old_rl_deprep_terminal;
526       rl_prep_term_function = tui_old_rl_prep_terminal;
527       rl_getc_function = tui_old_rl_getc_function;
528       rl_completion_display_matches_hook = tui_old_rl_display_matches_hook;
529       rl_outstream = tui_old_rl_outstream;
530       _rl_echoing_p = tui_old_rl_echoing_p;
531       rl_already_prompted = 0;
532 
533       /* Save tty for SIGCONT.  */
534       savetty ();
535     }
536 }
537 
538 #ifdef SIGCONT
539 /* Catch SIGCONT to restore the terminal and refresh the screen.  */
540 static void
541 tui_cont_sig (int sig)
542 {
543   if (tui_active)
544     {
545       /* Restore the terminal setting because another process (shell)
546          might have changed it.  */
547       resetty ();
548 
549       /* Force a refresh of the screen.  */
550       tui_refresh_all_win ();
551 
552       wrefresh (TUI_CMD_WIN->generic.handle);
553     }
554   signal (sig, tui_cont_sig);
555 }
556 #endif
557 
558 /* Initialize the IO for gdb in curses mode.  */
559 void
560 tui_initialize_io (void)
561 {
562 #ifdef SIGCONT
563   signal (SIGCONT, tui_cont_sig);
564 #endif
565 
566   /* Create tui output streams.  */
567   tui_stdout = new tui_file (stdout);
568   tui_stderr = new tui_file (stderr);
569   tui_out = tui_out_new (tui_stdout);
570 
571   /* Create the default UI.  */
572   tui_old_uiout = cli_out_new (gdb_stdout);
573 
574 #ifdef TUI_USE_PIPE_FOR_READLINE
575   /* Temporary solution for readline writing to stdout: redirect
576      readline output in a pipe, read that pipe and output the content
577      in the curses command window.  */
578   if (gdb_pipe_cloexec (tui_readline_pipe) != 0)
579     error (_("Cannot create pipe for readline"));
580 
581   tui_rl_outstream = fdopen (tui_readline_pipe[1], "w");
582   if (tui_rl_outstream == 0)
583     error (_("Cannot redirect readline output"));
584 
585   setvbuf (tui_rl_outstream, (char*) NULL, _IOLBF, 0);
586 
587 #ifdef O_NONBLOCK
588   (void) fcntl (tui_readline_pipe[0], F_SETFL, O_NONBLOCK);
589 #else
590 #ifdef O_NDELAY
591   (void) fcntl (tui_readline_pipe[0], F_SETFL, O_NDELAY);
592 #endif
593 #endif
594   add_file_handler (tui_readline_pipe[0], tui_readline_output, 0);
595 #else
596   tui_rl_outstream = stdout;
597 #endif
598 }
599 
600 /* Get a character from the command window.  This is called from the
601    readline package.  */
602 int
603 tui_getc (FILE *fp)
604 {
605   int ch;
606   WINDOW *w;
607 
608   w = TUI_CMD_WIN->generic.handle;
609 
610 #ifdef TUI_USE_PIPE_FOR_READLINE
611   /* Flush readline output.  */
612   tui_readline_output (0, 0);
613 #endif
614 
615   ch = wgetch (w);
616 
617   /* The \n must be echoed because it will not be printed by
618      readline.  */
619   if (ch == '\n')
620     {
621       /* When hitting return with an empty input, gdb executes the last
622          command.  If we emit a newline, this fills up the command window
623          with empty lines with gdb prompt at beginning.  Instead of that,
624          stay on the same line but provide a visual effect to show the
625          user we recognized the command.  */
626       if (rl_end == 0 && !gdb_in_secondary_prompt_p (current_ui))
627         {
628 	  wmove (w, getcury (w), 0);
629 
630           /* Clear the line.  This will blink the gdb prompt since
631              it will be redrawn at the same line.  */
632           wclrtoeol (w);
633           wrefresh (w);
634           napms (20);
635         }
636       else
637         {
638 	  /* Move cursor to the end of the command line before emitting the
639 	     newline.  We need to do so because when ncurses outputs a newline
640 	     it truncates any text that appears past the end of the cursor.  */
641 	  int px, py;
642 	  getyx (w, py, px);
643 	  px += rl_end - rl_point;
644 	  py += px / TUI_CMD_WIN->generic.width;
645 	  px %= TUI_CMD_WIN->generic.width;
646 	  wmove (w, py, px);
647 	  tui_putc ('\n');
648         }
649     }
650 
651   /* Handle prev/next/up/down here.  */
652   ch = tui_dispatch_ctrl_char (ch);
653 
654   if (ch == KEY_BACKSPACE)
655     return '\b';
656 
657   if (current_ui->command_editing && key_is_start_sequence (ch))
658     {
659       int ch_pending;
660 
661       nodelay (w, TRUE);
662       ch_pending = wgetch (w);
663       nodelay (w, FALSE);
664 
665       /* If we have pending input following a start sequence, call the stdin
666 	 event handler again because ncurses may have already read and stored
667 	 the input into its internal buffer, meaning that we won't get an stdin
668 	 event for it.  If we don't compensate for this missed stdin event, key
669 	 sequences as Alt_F (^[f) will not behave promptly.
670 
671 	 (We only compensates for the missed 2nd byte of a key sequence because
672 	 2-byte sequences are by far the most commonly used. ncurses may have
673 	 buffered a larger, 3+-byte key sequence though it remains to be seen
674 	 whether it is useful to compensate for all the bytes of such
675 	 sequences.)  */
676       if (ch_pending != ERR)
677 	{
678 	  ungetch (ch_pending);
679 	  call_stdin_event_handler_again_p = 1;
680 	}
681     }
682 
683   return ch;
684 }
685 
686 /* Utility function to expand TABs in a STRING into spaces.  STRING
687    will be displayed starting at column COL, and is assumed to include
688    no newlines.  The returned expanded string is malloc'ed.  */
689 
690 char *
691 tui_expand_tabs (const char *string, int col)
692 {
693   int n_adjust, ncol;
694   const char *s;
695   char *ret, *q;
696 
697   /* 1. How many additional characters do we need?  */
698   for (ncol = col, n_adjust = 0, s = string; s; )
699     {
700       s = strpbrk (s, "\t");
701       if (s)
702 	{
703 	  ncol += (s - string) + n_adjust;
704 	  /* Adjustment for the next tab stop, minus one for the TAB
705 	     we replace with spaces.  */
706 	  n_adjust += 8 - (ncol % 8) - 1;
707 	  s++;
708 	}
709     }
710 
711   /* Allocate the copy.  */
712   ret = q = (char *) xmalloc (strlen (string) + n_adjust + 1);
713 
714   /* 2. Copy the original string while replacing TABs with spaces.  */
715   for (ncol = col, s = string; s; )
716     {
717       const char *s1 = strpbrk (s, "\t");
718       if (s1)
719 	{
720 	  if (s1 > s)
721 	    {
722 	      strncpy (q, s, s1 - s);
723 	      q += s1 - s;
724 	      ncol += s1 - s;
725 	    }
726 	  do {
727 	    *q++ = ' ';
728 	    ncol++;
729 	  } while ((ncol % 8) != 0);
730 	  s1++;
731 	}
732       else
733 	strcpy (q, s);
734       s = s1;
735     }
736 
737   return ret;
738 }
739