c58d4f7e929bd28d6ed412ded05401d1a594801f
[platform/upstream/bash.git] / lib / readline / display.c
1 /* display.c -- readline redisplay facility. */
2
3 /* Copyright (C) 1987-2009 Free Software Foundation, Inc.
4
5    This file is part of the GNU Readline Library (Readline), a library    
6    for reading lines of text with interactive input and history editing.
7
8    Readline is free software: you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation, either version 3 of the License, or
11    (at your option) any later version.
12
13    Readline is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with Readline.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #define READLINE_LIBRARY
23
24 #if defined (HAVE_CONFIG_H)
25 #  include <config.h>
26 #endif
27
28 #include <sys/types.h>
29
30 #if defined (HAVE_UNISTD_H)
31 #  include <unistd.h>
32 #endif /* HAVE_UNISTD_H */
33
34 #include "posixstat.h"
35
36 #if defined (HAVE_STDLIB_H)
37 #  include <stdlib.h>
38 #else
39 #  include "ansi_stdlib.h"
40 #endif /* HAVE_STDLIB_H */
41
42 #include <stdio.h>
43
44 /* System-specific feature definitions and include files. */
45 #include "rldefs.h"
46 #include "rlmbutil.h"
47
48 /* Termcap library stuff. */
49 #include "tcap.h"
50
51 /* Some standard library routines. */
52 #include "readline.h"
53 #include "history.h"
54
55 #include "rlprivate.h"
56 #include "xmalloc.h"
57
58 #if !defined (strchr) && !defined (__STDC__)
59 extern char *strchr (), *strrchr ();
60 #endif /* !strchr && !__STDC__ */
61
62 static void update_line PARAMS((char *, char *, int, int, int, int));
63 static void space_to_eol PARAMS((int));
64 static void delete_chars PARAMS((int));
65 static void insert_some_chars PARAMS((char *, int, int));
66 static void cr PARAMS((void));
67
68 /* State of visible and invisible lines. */
69 struct line_state
70   {
71     char *line;
72     int *lbreaks;
73     int lbsize;
74 #if defined (HANDLE_MULTIBYTE)
75     int *wrapped_line;
76     int wbsize;
77 #endif
78   };
79
80 /* The line display buffers.  One is the line currently displayed on
81    the screen.  The other is the line about to be displayed. */
82 static struct line_state line_state_array[2];
83 static struct line_state *line_state_visible = &line_state_array[0];
84 static struct line_state *line_state_invisible = &line_state_array[1];
85 static int line_structures_initialized = 0;
86
87 /* Backwards-compatible names. */
88 #define inv_lbreaks     (line_state_invisible->lbreaks)
89 #define inv_lbsize      (line_state_invisible->lbsize)
90 #define vis_lbreaks     (line_state_visible->lbreaks)
91 #define vis_lbsize      (line_state_visible->lbsize)
92
93 #define visible_line    (line_state_visible->line)
94 #define invisible_line  (line_state_invisible->line)
95
96 #if defined (HANDLE_MULTIBYTE)
97 static int _rl_col_width PARAMS((const char *, int, int));
98 #else
99 #  define _rl_col_width(l, s, e)        (((e) <= (s)) ? 0 : (e) - (s))
100 #endif
101
102 /* Heuristic used to decide whether it is faster to move from CUR to NEW
103    by backing up or outputting a carriage return and moving forward.  CUR
104    and NEW are either both buffer positions or absolute screen positions. */
105 #define CR_FASTER(new, cur) (((new) + 1) < ((cur) - (new)))
106
107 /* _rl_last_c_pos is an absolute cursor position in multibyte locales and a
108    buffer index in others.  This macro is used when deciding whether the
109    current cursor position is in the middle of a prompt string containing
110    invisible characters.  XXX - might need to take `modmark' into account. */
111 #define PROMPT_ENDING_INDEX \
112   ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) ? prompt_physical_chars : prompt_last_invisible+1)
113   
114
115 /* **************************************************************** */
116 /*                                                                  */
117 /*                      Display stuff                               */
118 /*                                                                  */
119 /* **************************************************************** */
120
121 /* This is the stuff that is hard for me.  I never seem to write good
122    display routines in C.  Let's see how I do this time. */
123
124 /* (PWP) Well... Good for a simple line updater, but totally ignores
125    the problems of input lines longer than the screen width.
126
127    update_line and the code that calls it makes a multiple line,
128    automatically wrapping line update.  Careful attention needs
129    to be paid to the vertical position variables. */
130
131 /* Keep two buffers; one which reflects the current contents of the
132    screen, and the other to draw what we think the new contents should
133    be.  Then compare the buffers, and make whatever changes to the
134    screen itself that we should.  Finally, make the buffer that we
135    just drew into be the one which reflects the current contents of the
136    screen, and place the cursor where it belongs.
137
138    Commands that want to can fix the display themselves, and then let
139    this function know that the display has been fixed by setting the
140    RL_DISPLAY_FIXED variable.  This is good for efficiency. */
141
142 /* Application-specific redisplay function. */
143 rl_voidfunc_t *rl_redisplay_function = rl_redisplay;
144
145 /* Global variables declared here. */
146 /* What YOU turn on when you have handled all redisplay yourself. */
147 int rl_display_fixed = 0;
148
149 int _rl_suppress_redisplay = 0;
150 int _rl_want_redisplay = 0;
151
152 /* The stuff that gets printed out before the actual text of the line.
153    This is usually pointing to rl_prompt. */
154 char *rl_display_prompt = (char *)NULL;
155
156 /* Pseudo-global variables declared here. */
157
158 /* The visible cursor position.  If you print some text, adjust this. */
159 /* NOTE: _rl_last_c_pos is used as a buffer index when not in a locale
160    supporting multibyte characters, and an absolute cursor position when
161    in such a locale.  This is an artifact of the donated multibyte support.
162    Care must be taken when modifying its value. */
163 int _rl_last_c_pos = 0;
164 int _rl_last_v_pos = 0;
165
166 static int cpos_adjusted;
167 static int cpos_buffer_position;
168 static int prompt_multibyte_chars;
169
170 /* Number of lines currently on screen minus 1. */
171 int _rl_vis_botlin = 0;
172
173 /* Variables used only in this file. */
174 /* The last left edge of text that was displayed.  This is used when
175    doing horizontal scrolling.  It shifts in thirds of a screenwidth. */
176 static int last_lmargin;
177
178 /* A buffer for `modeline' messages. */
179 static char msg_buf[128];
180
181 /* Non-zero forces the redisplay even if we thought it was unnecessary. */
182 static int forced_display;
183
184 /* Default and initial buffer size.  Can grow. */
185 static int line_size = 1024;
186
187 /* Variables to keep track of the expanded prompt string, which may
188    include invisible characters. */
189
190 static char *local_prompt, *local_prompt_prefix;
191 static int local_prompt_len;
192 static int prompt_visible_length, prompt_prefix_length;
193
194 /* The number of invisible characters in the line currently being
195    displayed on the screen. */
196 static int visible_wrap_offset;
197
198 /* The number of invisible characters in the prompt string.  Static so it
199    can be shared between rl_redisplay and update_line */
200 static int wrap_offset;
201
202 /* The index of the last invisible character in the prompt string. */
203 static int prompt_last_invisible;
204
205 /* The length (buffer offset) of the first line of the last (possibly
206    multi-line) buffer displayed on the screen. */
207 static int visible_first_line_len;
208
209 /* Number of invisible characters on the first physical line of the prompt.
210    Only valid when the number of physical characters in the prompt exceeds
211    (or is equal to) _rl_screenwidth. */
212 static int prompt_invis_chars_first_line;
213
214 static int prompt_last_screen_line;
215
216 static int prompt_physical_chars;
217
218 /* set to a non-zero value by rl_redisplay if we are marking modified history
219    lines and the current line is so marked. */
220 static int modmark;
221
222 /* Variables to save and restore prompt and display information. */
223
224 /* These are getting numerous enough that it's time to create a struct. */
225
226 static char *saved_local_prompt;
227 static char *saved_local_prefix;
228 static int saved_last_invisible;
229 static int saved_visible_length;
230 static int saved_prefix_length;
231 static int saved_local_length;
232 static int saved_invis_chars_first_line;
233 static int saved_physical_chars;
234
235 /* Expand the prompt string S and return the number of visible
236    characters in *LP, if LP is not null.  This is currently more-or-less
237    a placeholder for expansion.  LIP, if non-null is a place to store the
238    index of the last invisible character in the returned string. NIFLP,
239    if non-zero, is a place to store the number of invisible characters in
240    the first prompt line.  The previous are used as byte counts -- indexes
241    into a character buffer. */
242
243 /* Current implementation:
244         \001 (^A) start non-visible characters
245         \002 (^B) end non-visible characters
246    all characters except \001 and \002 (following a \001) are copied to
247    the returned string; all characters except those between \001 and
248    \002 are assumed to be `visible'. */ 
249
250 static char *
251 expand_prompt (pmt, lp, lip, niflp, vlp)
252      char *pmt;
253      int *lp, *lip, *niflp, *vlp;
254 {
255   char *r, *ret, *p, *igstart;
256   int l, rl, last, ignoring, ninvis, invfl, invflset, ind, pind, physchars;
257
258   /* Short-circuit if we can. */
259   if ((MB_CUR_MAX <= 1 || rl_byte_oriented) && strchr (pmt, RL_PROMPT_START_IGNORE) == 0)
260     {
261       r = savestring (pmt);
262       if (lp)
263         *lp = strlen (r);
264       if (lip)
265         *lip = 0;
266       if (niflp)
267         *niflp = 0;
268       if (vlp)
269         *vlp = lp ? *lp : strlen (r);
270       return r;
271     }
272
273   l = strlen (pmt);
274   r = ret = (char *)xmalloc (l + 1);
275
276   invfl = 0;    /* invisible chars in first line of prompt */
277   invflset = 0; /* we only want to set invfl once */
278
279   igstart = 0;
280   for (rl = ignoring = last = ninvis = physchars = 0, p = pmt; p && *p; p++)
281     {
282       /* This code strips the invisible character string markers
283          RL_PROMPT_START_IGNORE and RL_PROMPT_END_IGNORE */
284       if (ignoring == 0 && *p == RL_PROMPT_START_IGNORE)                /* XXX - check ignoring? */
285         {
286           ignoring = 1;
287           igstart = p;
288           continue;
289         }
290       else if (ignoring && *p == RL_PROMPT_END_IGNORE)
291         {
292           ignoring = 0;
293           if (p != (igstart + 1))
294             last = r - ret - 1;
295           continue;
296         }
297       else
298         {
299 #if defined (HANDLE_MULTIBYTE)
300           if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
301             {
302               pind = p - pmt;
303               ind = _rl_find_next_mbchar (pmt, pind, 1, MB_FIND_NONZERO);
304               l = ind - pind;
305               while (l--)
306                 *r++ = *p++;
307               if (!ignoring)
308                 {
309                   /* rl ends up being assigned to prompt_visible_length,
310                      which is the number of characters in the buffer that
311                      contribute to characters on the screen, which might
312                      not be the same as the number of physical characters
313                      on the screen in the presence of multibyte characters */
314                   rl += ind - pind;
315                   physchars += _rl_col_width (pmt, pind, ind);
316                 }
317               else
318                 ninvis += ind - pind;
319               p--;                      /* compensate for later increment */
320             }
321           else
322 #endif
323             {
324               *r++ = *p;
325               if (!ignoring)
326                 {
327                   rl++;                 /* visible length byte counter */
328                   physchars++;
329                 }
330               else
331                 ninvis++;               /* invisible chars byte counter */
332             }
333
334           if (invflset == 0 && rl >= _rl_screenwidth)
335             {
336               invfl = ninvis;
337               invflset = 1;
338             }
339         }
340     }
341
342   if (rl < _rl_screenwidth)
343     invfl = ninvis;
344
345   *r = '\0';
346   if (lp)
347     *lp = rl;
348   if (lip)
349     *lip = last;
350   if (niflp)
351     *niflp = invfl;
352   if  (vlp)
353     *vlp = physchars;
354   return ret;
355 }
356
357 /* Just strip out RL_PROMPT_START_IGNORE and RL_PROMPT_END_IGNORE from
358    PMT and return the rest of PMT. */
359 char *
360 _rl_strip_prompt (pmt)
361      char *pmt;
362 {
363   char *ret;
364
365   ret = expand_prompt (pmt, (int *)NULL, (int *)NULL, (int *)NULL, (int *)NULL);
366   return ret;
367 }
368
369 /*
370  * Expand the prompt string into the various display components, if
371  * necessary.
372  *
373  * local_prompt = expanded last line of string in rl_display_prompt
374  *                (portion after the final newline)
375  * local_prompt_prefix = portion before last newline of rl_display_prompt,
376  *                       expanded via expand_prompt
377  * prompt_visible_length = number of visible characters in local_prompt
378  * prompt_prefix_length = number of visible characters in local_prompt_prefix
379  *
380  * This function is called once per call to readline().  It may also be
381  * called arbitrarily to expand the primary prompt.
382  *
383  * The return value is the number of visible characters on the last line
384  * of the (possibly multi-line) prompt.
385  */
386 int
387 rl_expand_prompt (prompt)
388      char *prompt;
389 {
390   char *p, *t;
391   int c;
392
393   /* Clear out any saved values. */
394   FREE (local_prompt);
395   FREE (local_prompt_prefix);
396
397   local_prompt = local_prompt_prefix = (char *)0;
398   local_prompt_len = 0;
399   prompt_last_invisible = prompt_invis_chars_first_line = 0;
400   prompt_visible_length = prompt_physical_chars = 0;
401
402   if (prompt == 0 || *prompt == 0)
403     return (0);
404
405   p = strrchr (prompt, '\n');
406   if (!p)
407     {
408       /* The prompt is only one logical line, though it might wrap. */
409       local_prompt = expand_prompt (prompt, &prompt_visible_length,
410                                             &prompt_last_invisible,
411                                             &prompt_invis_chars_first_line,
412                                             &prompt_physical_chars);
413       local_prompt_prefix = (char *)0;
414       local_prompt_len = local_prompt ? strlen (local_prompt) : 0;
415       return (prompt_visible_length);
416     }
417   else
418     {
419       /* The prompt spans multiple lines. */
420       t = ++p;
421       local_prompt = expand_prompt (p, &prompt_visible_length,
422                                        &prompt_last_invisible,
423                                        &prompt_invis_chars_first_line,
424                                        &prompt_physical_chars);
425       c = *t; *t = '\0';
426       /* The portion of the prompt string up to and including the
427          final newline is now null-terminated. */
428       local_prompt_prefix = expand_prompt (prompt, &prompt_prefix_length,
429                                                    (int *)NULL,
430                                                    (int *)NULL,
431                                                    (int *)NULL);
432       *t = c;
433       local_prompt_len = local_prompt ? strlen (local_prompt) : 0;
434       return (prompt_prefix_length);
435     }
436 }
437
438 /* Initialize the VISIBLE_LINE and INVISIBLE_LINE arrays, and their associated
439    arrays of line break markers.  MINSIZE is the minimum size of VISIBLE_LINE
440    and INVISIBLE_LINE; if it is greater than LINE_SIZE, LINE_SIZE is
441    increased.  If the lines have already been allocated, this ensures that
442    they can hold at least MINSIZE characters. */
443 static void
444 init_line_structures (minsize)
445       int minsize;
446 {
447   register int n;
448
449   if (invisible_line == 0)      /* initialize it */
450     {
451       if (line_size < minsize)
452         line_size = minsize;
453       visible_line = (char *)xmalloc (line_size);
454       invisible_line = (char *)xmalloc (line_size);
455     }
456   else if (line_size < minsize) /* ensure it can hold MINSIZE chars */
457     {
458       line_size *= 2;
459       if (line_size < minsize)
460         line_size = minsize;
461       visible_line = (char *)xrealloc (visible_line, line_size);
462       invisible_line = (char *)xrealloc (invisible_line, line_size);
463     }
464
465   for (n = minsize; n < line_size; n++)
466     {
467       visible_line[n] = 0;
468       invisible_line[n] = 1;
469     }
470
471   if (vis_lbreaks == 0)
472     {
473       /* should be enough. */
474       inv_lbsize = vis_lbsize = 256;
475
476 #if defined (HANDLE_MULTIBYTE)
477       line_state_visible->wbsize = vis_lbsize;
478       line_state_visible->wrapped_line = (int *)xmalloc (line_state_visible->wbsize * sizeof (int));
479
480       line_state_invisible->wbsize = inv_lbsize;
481       line_state_invisible->wrapped_line = (int *)xmalloc (line_state_invisible->wbsize * sizeof (int));
482 #endif
483
484       inv_lbreaks = (int *)xmalloc (inv_lbsize * sizeof (int));
485       vis_lbreaks = (int *)xmalloc (vis_lbsize * sizeof (int));
486       inv_lbreaks[0] = vis_lbreaks[0] = 0;
487     }
488
489   line_structures_initialized = 1;
490 }
491   
492 /* Basic redisplay algorithm. */
493 void
494 rl_redisplay ()
495 {
496   register int in, out, c, linenum, cursor_linenum;
497   register char *line;
498   int inv_botlin, lb_botlin, lb_linenum, o_cpos;
499   int newlines, lpos, temp, n0, num, prompt_lines_estimate;
500   char *prompt_this_line;
501 #if defined (HANDLE_MULTIBYTE)
502   wchar_t wc;
503   size_t wc_bytes;
504   int wc_width;
505   mbstate_t ps;
506   int _rl_wrapped_multicolumn = 0;
507 #endif
508
509   if (_rl_echoing_p == 0)
510     return;
511
512   /* Block keyboard interrupts because this function manipulates global
513      data structures. */
514   _rl_block_sigint ();  
515   RL_SETSTATE (RL_STATE_REDISPLAYING);
516
517   if (!rl_display_prompt)
518     rl_display_prompt = "";
519
520   if (line_structures_initialized == 0)
521     {
522       init_line_structures (0);
523       rl_on_new_line ();
524     }
525
526   /* Draw the line into the buffer. */
527   cpos_buffer_position = -1;
528
529   prompt_multibyte_chars = prompt_visible_length - prompt_physical_chars;
530
531   line = invisible_line;
532   out = inv_botlin = 0;
533
534   /* Mark the line as modified or not.  We only do this for history
535      lines. */
536   modmark = 0;
537   if (_rl_mark_modified_lines && current_history () && rl_undo_list)
538     {
539       line[out++] = '*';
540       line[out] = '\0';
541       modmark = 1;
542     }
543
544   /* If someone thought that the redisplay was handled, but the currently
545      visible line has a different modification state than the one about
546      to become visible, then correct the caller's misconception. */
547   if (visible_line[0] != invisible_line[0])
548     rl_display_fixed = 0;
549
550   /* If the prompt to be displayed is the `primary' readline prompt (the
551      one passed to readline()), use the values we have already expanded.
552      If not, use what's already in rl_display_prompt.  WRAP_OFFSET is the
553      number of non-visible characters in the prompt string. */
554   if (rl_display_prompt == rl_prompt || local_prompt)
555     {
556       if (local_prompt_prefix && forced_display)
557         _rl_output_some_chars (local_prompt_prefix, strlen (local_prompt_prefix));
558
559       if (local_prompt_len > 0)
560         {
561           temp = local_prompt_len + out + 2;
562           if (temp >= line_size)
563             {
564               line_size = (temp + 1024) - (temp % 1024);
565               visible_line = (char *)xrealloc (visible_line, line_size);
566               line = invisible_line = (char *)xrealloc (invisible_line, line_size);
567             }
568           strncpy (line + out, local_prompt, local_prompt_len);
569           out += local_prompt_len;
570         }
571       line[out] = '\0';
572       wrap_offset = local_prompt_len - prompt_visible_length;
573     }
574   else
575     {
576       int pmtlen;
577       prompt_this_line = strrchr (rl_display_prompt, '\n');
578       if (!prompt_this_line)
579         prompt_this_line = rl_display_prompt;
580       else
581         {
582           prompt_this_line++;
583           pmtlen = prompt_this_line - rl_display_prompt;        /* temp var */
584           if (forced_display)
585             {
586               _rl_output_some_chars (rl_display_prompt, pmtlen);
587               /* Make sure we are at column zero even after a newline,
588                  regardless of the state of terminal output processing. */
589               if (pmtlen < 2 || prompt_this_line[-2] != '\r')
590                 cr ();
591             }
592         }
593
594       prompt_physical_chars = pmtlen = strlen (prompt_this_line);
595       temp = pmtlen + out + 2;
596       if (temp >= line_size)
597         {
598           line_size = (temp + 1024) - (temp % 1024);
599           visible_line = (char *)xrealloc (visible_line, line_size);
600           line = invisible_line = (char *)xrealloc (invisible_line, line_size);
601         }
602       strncpy (line + out,  prompt_this_line, pmtlen);
603       out += pmtlen;
604       line[out] = '\0';
605       wrap_offset = prompt_invis_chars_first_line = 0;
606     }
607
608 #define CHECK_INV_LBREAKS() \
609       do { \
610         if (newlines >= (inv_lbsize - 2)) \
611           { \
612             inv_lbsize *= 2; \
613             inv_lbreaks = (int *)xrealloc (inv_lbreaks, inv_lbsize * sizeof (int)); \
614           } \
615       } while (0)
616
617 #if defined (HANDLE_MULTIBYTE)    
618 #define CHECK_LPOS() \
619       do { \
620         lpos++; \
621         if (lpos >= _rl_screenwidth) \
622           { \
623             if (newlines >= (inv_lbsize - 2)) \
624               { \
625                 inv_lbsize *= 2; \
626                 inv_lbreaks = (int *)xrealloc (inv_lbreaks, inv_lbsize * sizeof (int)); \
627               } \
628             inv_lbreaks[++newlines] = out; \
629             if (newlines >= (line_state_invisible->wbsize - 1)) \
630               { \
631                 line_state_invisible->wbsize *= 2; \
632                 line_state_invisible->wrapped_line = (int *)xrealloc (line_state_invisible->wrapped_line, line_state_invisible->wbsize * sizeof(int)); \
633               } \
634             line_state_invisible->wrapped_line[newlines] = _rl_wrapped_multicolumn; \
635             lpos = 0; \
636           } \
637       } while (0)
638 #else
639 #define CHECK_LPOS() \
640       do { \
641         lpos++; \
642         if (lpos >= _rl_screenwidth) \
643           { \
644             if (newlines >= (inv_lbsize - 2)) \
645               { \
646                 inv_lbsize *= 2; \
647                 inv_lbreaks = (int *)xrealloc (inv_lbreaks, inv_lbsize * sizeof (int)); \
648               } \
649             inv_lbreaks[++newlines] = out; \
650             lpos = 0; \
651           } \
652       } while (0)
653 #endif
654
655   /* inv_lbreaks[i] is where line i starts in the buffer. */
656   inv_lbreaks[newlines = 0] = 0;
657   lpos = prompt_physical_chars + modmark;
658
659 #if defined (HANDLE_MULTIBYTE)
660   memset (line_state_invisible->wrapped_line, 0, line_state_invisible->wbsize * sizeof (int));
661   num = 0;
662 #endif
663
664   /* prompt_invis_chars_first_line is the number of invisible characters in
665      the first physical line of the prompt.
666      wrap_offset - prompt_invis_chars_first_line is the number of invis
667      chars on the second (or, more generally, last) line. */
668
669   /* This is zero-based, used to set the newlines */
670   prompt_lines_estimate = lpos / _rl_screenwidth;
671
672   /* what if lpos is already >= _rl_screenwidth before we start drawing the
673      contents of the command line? */
674   while (lpos >= _rl_screenwidth)
675     {
676       int z;
677       /* fix from Darin Johnson <darin@acuson.com> for prompt string with
678          invisible characters that is longer than the screen width.  The
679          prompt_invis_chars_first_line variable could be made into an array
680          saying how many invisible characters there are per line, but that's
681          probably too much work for the benefit gained.  How many people have
682          prompts that exceed two physical lines?
683          Additional logic fix from Edward Catmur <ed@catmur.co.uk> */
684 #if defined (HANDLE_MULTIBYTE)
685       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0 && prompt_multibyte_chars > 0)
686         {
687           n0 = num;
688           temp = local_prompt_len;
689           while (num < temp)
690             {
691               z = _rl_col_width  (local_prompt, n0, num);
692               if (z > _rl_screenwidth)
693                 {
694                   num = _rl_find_prev_mbchar (local_prompt, num, MB_FIND_ANY);
695                   break;
696                 }
697               else if (z == _rl_screenwidth)
698                 break;
699               num++;
700             }
701           temp = num;
702         }
703       else
704 #endif /* !HANDLE_MULTIBYTE */
705         temp = ((newlines + 1) * _rl_screenwidth);
706
707       /* Now account for invisible characters in the current line. */
708       /* XXX - this assumes that the invisible characters may be split, but only
709          between the first and the last lines. */
710       temp += ((local_prompt_prefix == 0) ? ((newlines == 0) ? prompt_invis_chars_first_line
711                                                              : ((newlines == prompt_lines_estimate) ? wrap_offset : prompt_invis_chars_first_line))
712                                           : ((newlines == 0) ? wrap_offset : 0));
713              
714       inv_lbreaks[++newlines] = temp;
715 #if defined (HANDLE_MULTIBYTE)
716       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0 && prompt_multibyte_chars > 0)
717         lpos -= _rl_col_width (local_prompt, n0, num);
718       else
719 #endif
720         lpos -= _rl_screenwidth;
721     }
722
723   prompt_last_screen_line = newlines;
724
725   /* Draw the rest of the line (after the prompt) into invisible_line, keeping
726      track of where the cursor is (cpos_buffer_position), the number of the line containing
727      the cursor (lb_linenum), the last line number (lb_botlin and inv_botlin).
728      It maintains an array of line breaks for display (inv_lbreaks).
729      This handles expanding tabs for display and displaying meta characters. */
730   lb_linenum = 0;
731 #if defined (HANDLE_MULTIBYTE)
732   in = 0;
733   if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
734     {
735       memset (&ps, 0, sizeof (mbstate_t));
736       wc_bytes = mbrtowc (&wc, rl_line_buffer, rl_end, &ps);
737     }
738   else
739     wc_bytes = 1;
740   while (in < rl_end)
741 #else
742   for (in = 0; in < rl_end; in++)
743 #endif
744     {
745       c = (unsigned char)rl_line_buffer[in];
746
747 #if defined (HANDLE_MULTIBYTE)
748       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
749         {
750           if (MB_INVALIDCH (wc_bytes))
751             {
752               /* Byte sequence is invalid or shortened.  Assume that the
753                  first byte represents a character. */
754               wc_bytes = 1;
755               /* Assume that a character occupies a single column. */
756               wc_width = 1;
757               memset (&ps, 0, sizeof (mbstate_t));
758             }
759           else if (MB_NULLWCH (wc_bytes))
760             break;                      /* Found '\0' */
761           else
762             {
763               temp = wcwidth (wc);
764               wc_width = (temp >= 0) ? temp : 1;
765             }
766         }
767 #endif
768
769       if (out + 8 >= line_size)         /* XXX - 8 for \t */
770         {
771           line_size *= 2;
772           visible_line = (char *)xrealloc (visible_line, line_size);
773           invisible_line = (char *)xrealloc (invisible_line, line_size);
774           line = invisible_line;
775         }
776
777       if (in == rl_point)
778         {
779           cpos_buffer_position = out;
780           lb_linenum = newlines;
781         }
782
783 #if defined (HANDLE_MULTIBYTE)
784       if (META_CHAR (c) && _rl_output_meta_chars == 0)  /* XXX - clean up */
785 #else
786       if (META_CHAR (c))
787 #endif
788         {
789           if (_rl_output_meta_chars == 0)
790             {
791               sprintf (line + out, "\\%o", c);
792
793               if (lpos + 4 >= _rl_screenwidth)
794                 {
795                   temp = _rl_screenwidth - lpos;
796                   CHECK_INV_LBREAKS ();
797                   inv_lbreaks[++newlines] = out + temp;
798                   lpos = 4 - temp;
799                 }
800               else
801                 lpos += 4;
802
803               out += 4;
804             }
805           else
806             {
807               line[out++] = c;
808               CHECK_LPOS();
809             }
810         }
811 #if defined (DISPLAY_TABS)
812       else if (c == '\t')
813         {
814           register int newout;
815
816 #if 0
817           newout = (out | (int)7) + 1;
818 #else
819           newout = out + 8 - lpos % 8;
820 #endif
821           temp = newout - out;
822           if (lpos + temp >= _rl_screenwidth)
823             {
824               register int temp2;
825               temp2 = _rl_screenwidth - lpos;
826               CHECK_INV_LBREAKS ();
827               inv_lbreaks[++newlines] = out + temp2;
828               lpos = temp - temp2;
829               while (out < newout)
830                 line[out++] = ' ';
831             }
832           else
833             {
834               while (out < newout)
835                 line[out++] = ' ';
836               lpos += temp;
837             }
838         }
839 #endif
840       else if (c == '\n' && _rl_horizontal_scroll_mode == 0 && _rl_term_up && *_rl_term_up)
841         {
842           line[out++] = '\0';   /* XXX - sentinel */
843           CHECK_INV_LBREAKS ();
844           inv_lbreaks[++newlines] = out;
845           lpos = 0;
846         }
847       else if (CTRL_CHAR (c) || c == RUBOUT)
848         {
849           line[out++] = '^';
850           CHECK_LPOS();
851           line[out++] = CTRL_CHAR (c) ? UNCTRL (c) : '?';
852           CHECK_LPOS();
853         }
854       else
855         {
856 #if defined (HANDLE_MULTIBYTE)
857           if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
858             {
859               register int i;
860
861               _rl_wrapped_multicolumn = 0;
862
863               if (_rl_screenwidth < lpos + wc_width)
864                 for (i = lpos; i < _rl_screenwidth; i++)
865                   {
866                     /* The space will be removed in update_line() */
867                     line[out++] = ' ';
868                     _rl_wrapped_multicolumn++;
869                     CHECK_LPOS();
870                   }
871               if (in == rl_point)
872                 {
873                   cpos_buffer_position = out;
874                   lb_linenum = newlines;
875                 }
876               for (i = in; i < in+wc_bytes; i++)
877                 line[out++] = rl_line_buffer[i];
878               for (i = 0; i < wc_width; i++)
879                 CHECK_LPOS();
880             }
881           else
882             {
883               line[out++] = c;
884               CHECK_LPOS();
885             }
886 #else
887           line[out++] = c;
888           CHECK_LPOS();
889 #endif
890         }
891
892 #if defined (HANDLE_MULTIBYTE)
893       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
894         {
895           in += wc_bytes;
896           wc_bytes = mbrtowc (&wc, rl_line_buffer + in, rl_end - in, &ps);
897         }
898       else
899         in++;
900 #endif
901
902     }
903   line[out] = '\0';
904   if (cpos_buffer_position < 0)
905     {
906       cpos_buffer_position = out;
907       lb_linenum = newlines;
908     }
909
910   inv_botlin = lb_botlin = newlines;
911   CHECK_INV_LBREAKS ();
912   inv_lbreaks[newlines+1] = out;
913   cursor_linenum = lb_linenum;
914
915   /* CPOS_BUFFER_POSITION == position in buffer where cursor should be placed.
916      CURSOR_LINENUM == line number where the cursor should be placed. */
917
918   /* PWP: now is when things get a bit hairy.  The visible and invisible
919      line buffers are really multiple lines, which would wrap every
920      (screenwidth - 1) characters.  Go through each in turn, finding
921      the changed region and updating it.  The line order is top to bottom. */
922
923   /* If we can move the cursor up and down, then use multiple lines,
924      otherwise, let long lines display in a single terminal line, and
925      horizontally scroll it. */
926
927   if (_rl_horizontal_scroll_mode == 0 && _rl_term_up && *_rl_term_up)
928     {
929       int nleft, pos, changed_screen_line, tx;
930
931       if (!rl_display_fixed || forced_display)
932         {
933           forced_display = 0;
934
935           /* If we have more than a screenful of material to display, then
936              only display a screenful.  We should display the last screen,
937              not the first.  */
938           if (out >= _rl_screenchars)
939             {
940               if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
941                 out = _rl_find_prev_mbchar (line, _rl_screenchars, MB_FIND_ANY);
942               else
943                 out = _rl_screenchars - 1;
944             }
945
946           /* The first line is at character position 0 in the buffer.  The
947              second and subsequent lines start at inv_lbreaks[N], offset by
948              OFFSET (which has already been calculated above).  */
949
950 #define INVIS_FIRST()   (prompt_physical_chars > _rl_screenwidth ? prompt_invis_chars_first_line : wrap_offset)
951 #define WRAP_OFFSET(line, offset)  ((line == 0) \
952                                         ? (offset ? INVIS_FIRST() : 0) \
953                                         : ((line == prompt_last_screen_line) ? wrap_offset-prompt_invis_chars_first_line : 0))
954 #define W_OFFSET(line, offset) ((line) == 0 ? offset : 0)
955 #define VIS_LLEN(l)     ((l) > _rl_vis_botlin ? 0 : (vis_lbreaks[l+1] - vis_lbreaks[l]))
956 #define INV_LLEN(l)     (inv_lbreaks[l+1] - inv_lbreaks[l])
957 #define VIS_CHARS(line) (visible_line + vis_lbreaks[line])
958 #define VIS_LINE(line) ((line) > _rl_vis_botlin) ? "" : VIS_CHARS(line)
959 #define INV_LINE(line) (invisible_line + inv_lbreaks[line])
960
961           /* For each line in the buffer, do the updating display. */
962           for (linenum = 0; linenum <= inv_botlin; linenum++)
963             {
964               /* This can lead us astray if we execute a program that changes
965                  the locale from a non-multibyte to a multibyte one. */
966               o_cpos = _rl_last_c_pos;
967               cpos_adjusted = 0;
968               update_line (VIS_LINE(linenum), INV_LINE(linenum), linenum,
969                            VIS_LLEN(linenum), INV_LLEN(linenum), inv_botlin);
970
971               /* update_line potentially changes _rl_last_c_pos, but doesn't
972                  take invisible characters into account, since _rl_last_c_pos
973                  is an absolute cursor position in a multibyte locale.  See
974                  if compensating here is the right thing, or if we have to
975                  change update_line itself.  There are several cases in which
976                  update_line adjusts _rl_last_c_pos itself (so it can pass
977                  _rl_move_cursor_relative accurate values); it communicates
978                  this back by setting cpos_adjusted.  If we assume that
979                  _rl_last_c_pos is correct (an absolute cursor position) each
980                  time update_line is called, then we can assume in our
981                  calculations that o_cpos does not need to be adjusted by
982                  wrap_offset. */
983               if (linenum == 0 && (MB_CUR_MAX > 1 && rl_byte_oriented == 0) &&
984                   cpos_adjusted == 0 &&
985                   _rl_last_c_pos != o_cpos &&
986                   _rl_last_c_pos > wrap_offset &&
987                   o_cpos < prompt_last_invisible)
988                 _rl_last_c_pos -= prompt_invis_chars_first_line;        /* XXX - was wrap_offset */
989               else if (linenum == prompt_last_screen_line && prompt_physical_chars > _rl_screenwidth &&
990                         (MB_CUR_MAX > 1 && rl_byte_oriented == 0) &&
991                         cpos_adjusted == 0 &&
992                         _rl_last_c_pos != o_cpos &&
993                         _rl_last_c_pos > (prompt_last_invisible - _rl_screenwidth - prompt_invis_chars_first_line))
994                 _rl_last_c_pos -= (wrap_offset-prompt_invis_chars_first_line);
995                   
996               /* If this is the line with the prompt, we might need to
997                  compensate for invisible characters in the new line. Do
998                  this only if there is not more than one new line (which
999                  implies that we completely overwrite the old visible line)
1000                  and the new line is shorter than the old.  Make sure we are
1001                  at the end of the new line before clearing. */
1002               if (linenum == 0 &&
1003                   inv_botlin == 0 && _rl_last_c_pos == out &&
1004                   (wrap_offset > visible_wrap_offset) &&
1005                   (_rl_last_c_pos < visible_first_line_len))
1006                 {
1007                   if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1008                     nleft = _rl_screenwidth - _rl_last_c_pos;
1009                   else
1010                     nleft = _rl_screenwidth + wrap_offset - _rl_last_c_pos;
1011                   if (nleft)
1012                     _rl_clear_to_eol (nleft);
1013                 }
1014 #if 0
1015               /* This segment is intended to handle the case where the prompt
1016                  has invisible characters on the second line and the new line
1017                  to be displayed needs to clear the rest of the old characters
1018                  out (e.g., when printing the i-search prompt).  In general,
1019                  the case of the new line being shorter than the old.
1020                  Incomplete */
1021               else if (linenum == prompt_last_screen_line &&
1022                        prompt_physical_chars > _rl_screenwidth &&
1023                        wrap_offset != prompt_invis_chars_first_line &&
1024                        _rl_last_c_pos == out &&
1025 #endif
1026
1027
1028               /* Since the new first line is now visible, save its length. */
1029               if (linenum == 0)
1030                 visible_first_line_len = (inv_botlin > 0) ? inv_lbreaks[1] : out - wrap_offset;
1031             }
1032
1033           /* We may have deleted some lines.  If so, clear the left over
1034              blank ones at the bottom out. */
1035           if (_rl_vis_botlin > inv_botlin)
1036             {
1037               char *tt;
1038               for (; linenum <= _rl_vis_botlin; linenum++)
1039                 {
1040                   tt = VIS_CHARS (linenum);
1041                   _rl_move_vert (linenum);
1042                   _rl_move_cursor_relative (0, tt);
1043                   _rl_clear_to_eol
1044                     ((linenum == _rl_vis_botlin) ? strlen (tt) : _rl_screenwidth);
1045                 }
1046             }
1047           _rl_vis_botlin = inv_botlin;
1048
1049           /* CHANGED_SCREEN_LINE is set to 1 if we have moved to a
1050              different screen line during this redisplay. */
1051           changed_screen_line = _rl_last_v_pos != cursor_linenum;
1052           if (changed_screen_line)
1053             {
1054               _rl_move_vert (cursor_linenum);
1055               /* If we moved up to the line with the prompt using _rl_term_up,
1056                  the physical cursor position on the screen stays the same,
1057                  but the buffer position needs to be adjusted to account
1058                  for invisible characters. */
1059               if ((MB_CUR_MAX == 1 || rl_byte_oriented) && cursor_linenum == 0 && wrap_offset)
1060                 _rl_last_c_pos += wrap_offset;
1061             }
1062
1063           /* We have to reprint the prompt if it contains invisible
1064              characters, since it's not generally OK to just reprint
1065              the characters from the current cursor position.  But we
1066              only need to reprint it if the cursor is before the last
1067              invisible character in the prompt string. */
1068           nleft = prompt_visible_length + wrap_offset;
1069           if (cursor_linenum == 0 && wrap_offset > 0 && _rl_last_c_pos > 0 &&
1070 #if 0
1071               _rl_last_c_pos <= PROMPT_ENDING_INDEX && local_prompt)
1072 #else
1073               _rl_last_c_pos < PROMPT_ENDING_INDEX && local_prompt)
1074 #endif
1075             {
1076 #if defined (__MSDOS__)
1077               putc ('\r', rl_outstream);
1078 #else
1079               if (_rl_term_cr)
1080                 tputs (_rl_term_cr, 1, _rl_output_character_function);
1081 #endif
1082               if (modmark)
1083                 _rl_output_some_chars ("*", 1);
1084
1085               _rl_output_some_chars (local_prompt, nleft);
1086               if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1087                 _rl_last_c_pos = _rl_col_width (local_prompt, 0, nleft) - wrap_offset + modmark;
1088               else
1089                 _rl_last_c_pos = nleft + modmark;
1090             }
1091
1092           /* Where on that line?  And where does that line start
1093              in the buffer? */
1094           pos = inv_lbreaks[cursor_linenum];
1095           /* nleft == number of characters in the line buffer between the
1096              start of the line and the desired cursor position. */
1097           nleft = cpos_buffer_position - pos;
1098
1099           /* NLEFT is now a number of characters in a buffer.  When in a
1100              multibyte locale, however, _rl_last_c_pos is an absolute cursor
1101              position that doesn't take invisible characters in the prompt
1102              into account.  We use a fudge factor to compensate. */
1103
1104           /* Since _rl_backspace() doesn't know about invisible characters in the
1105              prompt, and there's no good way to tell it, we compensate for
1106              those characters here and call _rl_backspace() directly. */
1107           if (wrap_offset && cursor_linenum == 0 && nleft < _rl_last_c_pos)
1108             {
1109               /* TX == new physical cursor position in multibyte locale. */
1110               if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1111                 tx = _rl_col_width (&visible_line[pos], 0, nleft) - visible_wrap_offset;
1112               else
1113                 tx = nleft;
1114               if (tx >= 0 && _rl_last_c_pos > tx)
1115                 {
1116                   _rl_backspace (_rl_last_c_pos - tx);  /* XXX */
1117                   _rl_last_c_pos = tx;
1118                 }
1119             }
1120
1121           /* We need to note that in a multibyte locale we are dealing with
1122              _rl_last_c_pos as an absolute cursor position, but moving to a
1123              point specified by a buffer position (NLEFT) that doesn't take
1124              invisible characters into account. */
1125           if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1126             _rl_move_cursor_relative (nleft, &invisible_line[pos]);
1127           else if (nleft != _rl_last_c_pos)
1128             _rl_move_cursor_relative (nleft, &invisible_line[pos]);
1129         }
1130     }
1131   else                          /* Do horizontal scrolling. */
1132     {
1133 #define M_OFFSET(margin, offset) ((margin) == 0 ? offset : 0)
1134       int lmargin, ndisp, nleft, phys_c_pos, t;
1135
1136       /* Always at top line. */
1137       _rl_last_v_pos = 0;
1138
1139       /* Compute where in the buffer the displayed line should start.  This
1140          will be LMARGIN. */
1141
1142       /* The number of characters that will be displayed before the cursor. */
1143       ndisp = cpos_buffer_position - wrap_offset;
1144       nleft  = prompt_visible_length + wrap_offset;
1145       /* Where the new cursor position will be on the screen.  This can be
1146          longer than SCREENWIDTH; if it is, lmargin will be adjusted. */
1147       phys_c_pos = cpos_buffer_position - (last_lmargin ? last_lmargin : wrap_offset);
1148       t = _rl_screenwidth / 3;
1149
1150       /* If the number of characters had already exceeded the screenwidth,
1151          last_lmargin will be > 0. */
1152
1153       /* If the number of characters to be displayed is more than the screen
1154          width, compute the starting offset so that the cursor is about
1155          two-thirds of the way across the screen. */
1156       if (phys_c_pos > _rl_screenwidth - 2)
1157         {
1158           lmargin = cpos_buffer_position - (2 * t);
1159           if (lmargin < 0)
1160             lmargin = 0;
1161           /* If the left margin would be in the middle of a prompt with
1162              invisible characters, don't display the prompt at all. */
1163           if (wrap_offset && lmargin > 0 && lmargin < nleft)
1164             lmargin = nleft;
1165         }
1166       else if (ndisp < _rl_screenwidth - 2)             /* XXX - was -1 */
1167         lmargin = 0;
1168       else if (phys_c_pos < 1)
1169         {
1170           /* If we are moving back towards the beginning of the line and
1171              the last margin is no longer correct, compute a new one. */
1172           lmargin = ((cpos_buffer_position - 1) / t) * t;       /* XXX */
1173           if (wrap_offset && lmargin > 0 && lmargin < nleft)
1174             lmargin = nleft;
1175         }
1176       else
1177         lmargin = last_lmargin;
1178
1179       /* If the first character on the screen isn't the first character
1180          in the display line, indicate this with a special character. */
1181       if (lmargin > 0)
1182         line[lmargin] = '<';
1183
1184       /* If SCREENWIDTH characters starting at LMARGIN do not encompass
1185          the whole line, indicate that with a special character at the
1186          right edge of the screen.  If LMARGIN is 0, we need to take the
1187          wrap offset into account. */
1188       t = lmargin + M_OFFSET (lmargin, wrap_offset) + _rl_screenwidth;
1189       if (t < out)
1190         line[t - 1] = '>';
1191
1192       if (rl_display_fixed == 0 || forced_display || lmargin != last_lmargin)
1193         {
1194           forced_display = 0;
1195           o_cpos = _rl_last_c_pos;
1196           cpos_adjusted = 0;
1197           update_line (&visible_line[last_lmargin],
1198                        &invisible_line[lmargin],
1199                        0,
1200                        _rl_screenwidth + visible_wrap_offset,
1201                        _rl_screenwidth + (lmargin ? 0 : wrap_offset),
1202                        0);
1203
1204           if ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) &&
1205               cpos_adjusted == 0 &&
1206               _rl_last_c_pos != o_cpos &&
1207               _rl_last_c_pos > wrap_offset &&
1208               o_cpos < prompt_last_invisible)
1209                 _rl_last_c_pos -= prompt_invis_chars_first_line;        /* XXX - was wrap_offset */
1210
1211           /* If the visible new line is shorter than the old, but the number
1212              of invisible characters is greater, and we are at the end of
1213              the new line, we need to clear to eol. */
1214           t = _rl_last_c_pos - M_OFFSET (lmargin, wrap_offset);
1215           if ((M_OFFSET (lmargin, wrap_offset) > visible_wrap_offset) &&
1216               (_rl_last_c_pos == out) &&
1217               t < visible_first_line_len)
1218             {
1219               nleft = _rl_screenwidth - t;
1220               _rl_clear_to_eol (nleft);
1221             }
1222           visible_first_line_len = out - lmargin - M_OFFSET (lmargin, wrap_offset);
1223           if (visible_first_line_len > _rl_screenwidth)
1224             visible_first_line_len = _rl_screenwidth;
1225
1226           _rl_move_cursor_relative (cpos_buffer_position - lmargin, &invisible_line[lmargin]);
1227           last_lmargin = lmargin;
1228         }
1229     }
1230   fflush (rl_outstream);
1231
1232   /* Swap visible and non-visible lines. */
1233   {
1234     struct line_state *vtemp = line_state_visible;
1235
1236     line_state_visible = line_state_invisible;
1237     line_state_invisible = vtemp;
1238
1239     rl_display_fixed = 0;
1240     /* If we are displaying on a single line, and last_lmargin is > 0, we
1241        are not displaying any invisible characters, so set visible_wrap_offset
1242        to 0. */
1243     if (_rl_horizontal_scroll_mode && last_lmargin)
1244       visible_wrap_offset = 0;
1245     else
1246       visible_wrap_offset = wrap_offset;
1247   }
1248
1249   RL_UNSETSTATE (RL_STATE_REDISPLAYING);
1250   _rl_release_sigint ();
1251 }
1252
1253 /* PWP: update_line() is based on finding the middle difference of each
1254    line on the screen; vis:
1255
1256                              /old first difference
1257         /beginning of line   |        /old last same       /old EOL
1258         v                    v        v             v
1259 old:    eddie> Oh, my little gruntle-buggy is to me, as lurgid as
1260 new:    eddie> Oh, my little buggy says to me, as lurgid as
1261         ^                    ^  ^                          ^
1262         \beginning of line   |  \new last same     \new end of line
1263                              \new first difference
1264
1265    All are character pointers for the sake of speed.  Special cases for
1266    no differences, as well as for end of line additions must be handled.
1267
1268    Could be made even smarter, but this works well enough */
1269 static void
1270 update_line (old, new, current_line, omax, nmax, inv_botlin)
1271      register char *old, *new;
1272      int current_line, omax, nmax, inv_botlin;
1273 {
1274   register char *ofd, *ols, *oe, *nfd, *nls, *ne;
1275   int temp, lendiff, wsatend, od, nd, twidth, o_cpos;
1276   int current_invis_chars;
1277   int col_lendiff, col_temp;
1278 #if defined (HANDLE_MULTIBYTE)
1279   mbstate_t ps_new, ps_old;
1280   int new_offset, old_offset;
1281 #endif
1282
1283   /* If we're at the right edge of a terminal that supports xn, we're
1284      ready to wrap around, so do so.  This fixes problems with knowing
1285      the exact cursor position and cut-and-paste with certain terminal
1286      emulators.  In this calculation, TEMP is the physical screen
1287      position of the cursor. */
1288   if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1289     temp = _rl_last_c_pos;
1290   else
1291     temp = _rl_last_c_pos - WRAP_OFFSET (_rl_last_v_pos, visible_wrap_offset);
1292   if (temp == _rl_screenwidth && _rl_term_autowrap && !_rl_horizontal_scroll_mode
1293         && _rl_last_v_pos == current_line - 1)
1294     {
1295 #if defined (HANDLE_MULTIBYTE)
1296       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1297         {
1298           wchar_t wc;
1299           mbstate_t ps;
1300           int tempwidth, bytes;
1301           size_t ret;
1302
1303           /* This fixes only double-column characters, but if the wrapped
1304              character comsumes more than three columns, spaces will be
1305              inserted in the string buffer. */
1306           if (current_line < line_state_visible->wbsize && line_state_visible->wrapped_line[current_line] > 0)
1307             _rl_clear_to_eol (line_state_visible->wrapped_line[current_line]);
1308
1309           memset (&ps, 0, sizeof (mbstate_t));
1310           ret = mbrtowc (&wc, new, MB_CUR_MAX, &ps);
1311           if (MB_INVALIDCH (ret))
1312             {
1313               tempwidth = 1;
1314               ret = 1;
1315             }
1316           else if (MB_NULLWCH (ret))
1317             tempwidth = 0;
1318           else
1319             tempwidth = wcwidth (wc);
1320
1321           if (tempwidth > 0)
1322             {
1323               int count;
1324               bytes = ret;
1325               for (count = 0; count < bytes; count++)
1326                 putc (new[count], rl_outstream);
1327               _rl_last_c_pos = tempwidth;
1328               _rl_last_v_pos++;
1329               memset (&ps, 0, sizeof (mbstate_t));
1330               ret = mbrtowc (&wc, old, MB_CUR_MAX, &ps);
1331               if (ret != 0 && bytes != 0)
1332                 {
1333                   if (MB_INVALIDCH (ret))
1334                     memmove (old+bytes, old+1, strlen (old+1));
1335                   else
1336                     memmove (old+bytes, old+ret, strlen (old+ret));
1337                   memcpy (old, new, bytes);
1338                 }
1339             }
1340           else
1341             {
1342               putc (' ', rl_outstream);
1343               _rl_last_c_pos = 1;
1344               _rl_last_v_pos++;
1345               if (old[0] && new[0])
1346                 old[0] = new[0];
1347             }
1348         }
1349       else
1350 #endif
1351         {
1352           if (new[0])
1353             putc (new[0], rl_outstream);
1354           else
1355             putc (' ', rl_outstream);
1356           _rl_last_c_pos = 1;
1357           _rl_last_v_pos++;
1358           if (old[0] && new[0])
1359             old[0] = new[0];
1360         }
1361     }
1362
1363       
1364   /* Find first difference. */
1365 #if defined (HANDLE_MULTIBYTE)
1366   if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1367     {
1368       /* See if the old line is a subset of the new line, so that the
1369          only change is adding characters. */
1370       temp = (omax < nmax) ? omax : nmax;
1371       if (memcmp (old, new, temp) == 0)         /* adding at the end */
1372         {
1373           ofd = old + temp;
1374           nfd = new + temp;
1375         }
1376       else
1377         {      
1378           memset (&ps_new, 0, sizeof(mbstate_t));
1379           memset (&ps_old, 0, sizeof(mbstate_t));
1380
1381           if (omax == nmax && STREQN (new, old, omax))
1382             {
1383               ofd = old + omax;
1384               nfd = new + nmax;
1385             }
1386           else
1387             {
1388               new_offset = old_offset = 0;
1389               for (ofd = old, nfd = new;
1390                     (ofd - old < omax) && *ofd &&
1391                     _rl_compare_chars(old, old_offset, &ps_old, new, new_offset, &ps_new); )
1392                 {
1393                   old_offset = _rl_find_next_mbchar (old, old_offset, 1, MB_FIND_ANY);
1394                   new_offset = _rl_find_next_mbchar (new, new_offset, 1, MB_FIND_ANY);
1395                   ofd = old + old_offset;
1396                   nfd = new + new_offset;
1397                 }
1398             }
1399         }
1400     }
1401   else
1402 #endif
1403   for (ofd = old, nfd = new;
1404        (ofd - old < omax) && *ofd && (*ofd == *nfd);
1405        ofd++, nfd++)
1406     ;
1407
1408   /* Move to the end of the screen line.  ND and OD are used to keep track
1409      of the distance between ne and new and oe and old, respectively, to
1410      move a subtraction out of each loop. */
1411   for (od = ofd - old, oe = ofd; od < omax && *oe; oe++, od++);
1412   for (nd = nfd - new, ne = nfd; nd < nmax && *ne; ne++, nd++);
1413
1414   /* If no difference, continue to next line. */
1415   if (ofd == oe && nfd == ne)
1416     return;
1417
1418   wsatend = 1;                  /* flag for trailing whitespace */
1419
1420 #if defined (HANDLE_MULTIBYTE)
1421   if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1422     {
1423       ols = old + _rl_find_prev_mbchar (old, oe - old, MB_FIND_ANY);
1424       nls = new + _rl_find_prev_mbchar (new, ne - new, MB_FIND_ANY);
1425       while ((ols > ofd) && (nls > nfd))
1426         {
1427           memset (&ps_old, 0, sizeof (mbstate_t));
1428           memset (&ps_new, 0, sizeof (mbstate_t));
1429
1430 #if 0
1431           /* On advice from jir@yamato.ibm.com */
1432           _rl_adjust_point (old, ols - old, &ps_old);
1433           _rl_adjust_point (new, nls - new, &ps_new);
1434 #endif
1435
1436           if (_rl_compare_chars (old, ols - old, &ps_old, new, nls - new, &ps_new) == 0)
1437             break;
1438
1439           if (*ols == ' ')
1440             wsatend = 0;
1441
1442           ols = old + _rl_find_prev_mbchar (old, ols - old, MB_FIND_ANY);
1443           nls = new + _rl_find_prev_mbchar (new, nls - new, MB_FIND_ANY);
1444         }
1445     }
1446   else
1447     {
1448 #endif /* HANDLE_MULTIBYTE */
1449   ols = oe - 1;                 /* find last same */
1450   nls = ne - 1;
1451   while ((ols > ofd) && (nls > nfd) && (*ols == *nls))
1452     {
1453       if (*ols != ' ')
1454         wsatend = 0;
1455       ols--;
1456       nls--;
1457     }
1458 #if defined (HANDLE_MULTIBYTE)
1459     }
1460 #endif
1461
1462   if (wsatend)
1463     {
1464       ols = oe;
1465       nls = ne;
1466     }
1467 #if defined (HANDLE_MULTIBYTE)
1468   /* This may not work for stateful encoding, but who cares?  To handle
1469      stateful encoding properly, we have to scan each string from the
1470      beginning and compare. */
1471   else if (_rl_compare_chars (ols, 0, NULL, nls, 0, NULL) == 0)
1472 #else
1473   else if (*ols != *nls)
1474 #endif
1475     {
1476       if (*ols)                 /* don't step past the NUL */
1477         {
1478           if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1479             ols = old + _rl_find_next_mbchar (old, ols - old, 1, MB_FIND_ANY);
1480           else
1481             ols++;
1482         }
1483       if (*nls)
1484         {
1485           if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1486             nls = new + _rl_find_next_mbchar (new, nls - new, 1, MB_FIND_ANY);
1487           else
1488             nls++;
1489         }
1490     }
1491
1492   /* count of invisible characters in the current invisible line. */
1493   current_invis_chars = W_OFFSET (current_line, wrap_offset);
1494   if (_rl_last_v_pos != current_line)
1495     {
1496       _rl_move_vert (current_line);
1497       if ((MB_CUR_MAX == 1 || rl_byte_oriented) && current_line == 0 && visible_wrap_offset)
1498         _rl_last_c_pos += visible_wrap_offset;
1499     }
1500
1501   /* If this is the first line and there are invisible characters in the
1502      prompt string, and the prompt string has not changed, and the current
1503      cursor position is before the last invisible character in the prompt,
1504      and the index of the character to move to is past the end of the prompt
1505      string, then redraw the entire prompt string.  We can only do this
1506      reliably if the terminal supports a `cr' capability.
1507
1508      This is not an efficiency hack -- there is a problem with redrawing
1509      portions of the prompt string if they contain terminal escape
1510      sequences (like drawing the `unbold' sequence without a corresponding
1511      `bold') that manifests itself on certain terminals. */
1512
1513   lendiff = local_prompt_len;
1514   od = ofd - old;       /* index of first difference in visible line */
1515   if (current_line == 0 && !_rl_horizontal_scroll_mode &&
1516       _rl_term_cr && lendiff > prompt_visible_length && _rl_last_c_pos > 0 &&
1517       od >= lendiff && _rl_last_c_pos < PROMPT_ENDING_INDEX)
1518     {
1519 #if defined (__MSDOS__)
1520       putc ('\r', rl_outstream);
1521 #else
1522       tputs (_rl_term_cr, 1, _rl_output_character_function);
1523 #endif
1524       if (modmark)
1525         _rl_output_some_chars ("*", 1);
1526       _rl_output_some_chars (local_prompt, lendiff);
1527       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1528         {
1529           /* We take wrap_offset into account here so we can pass correct
1530              information to _rl_move_cursor_relative. */
1531           _rl_last_c_pos = _rl_col_width (local_prompt, 0, lendiff) - wrap_offset + modmark;
1532           cpos_adjusted = 1;
1533         }
1534       else
1535         _rl_last_c_pos = lendiff + modmark;
1536     }
1537
1538   o_cpos = _rl_last_c_pos;
1539
1540   /* When this function returns, _rl_last_c_pos is correct, and an absolute
1541      cursor postion in multibyte mode, but a buffer index when not in a
1542      multibyte locale. */
1543   _rl_move_cursor_relative (od, old);
1544 #if 1
1545 #if defined (HANDLE_MULTIBYTE)
1546   /* We need to indicate that the cursor position is correct in the presence of
1547      invisible characters in the prompt string.  Let's see if setting this when
1548      we make sure we're at the end of the drawn prompt string works. */
1549   if (current_line == 0 && MB_CUR_MAX > 1 && rl_byte_oriented == 0 &&
1550       (_rl_last_c_pos > 0 || o_cpos > 0) &&
1551       _rl_last_c_pos == prompt_physical_chars)
1552     cpos_adjusted = 1;
1553 #endif
1554 #endif
1555
1556   /* if (len (new) > len (old))
1557      lendiff == difference in buffer
1558      col_lendiff == difference on screen
1559      When not using multibyte characters, these are equal */
1560   lendiff = (nls - nfd) - (ols - ofd);
1561   if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1562     col_lendiff = _rl_col_width (new, nfd - new, nls - new) - _rl_col_width (old, ofd - old, ols - old);
1563   else
1564     col_lendiff = lendiff;
1565
1566   /* If we are changing the number of invisible characters in a line, and
1567      the spot of first difference is before the end of the invisible chars,
1568      lendiff needs to be adjusted. */
1569   if (current_line == 0 && !_rl_horizontal_scroll_mode &&
1570       current_invis_chars != visible_wrap_offset)
1571     {
1572       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1573         {
1574           lendiff += visible_wrap_offset - current_invis_chars;
1575           col_lendiff += visible_wrap_offset - current_invis_chars;
1576         }
1577       else
1578         {
1579           lendiff += visible_wrap_offset - current_invis_chars;
1580           col_lendiff = lendiff;
1581         }
1582     }
1583
1584   /* Insert (diff (len (old), len (new)) ch. */
1585   temp = ne - nfd;
1586   if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1587     col_temp = _rl_col_width (new, nfd - new, ne - new);
1588   else
1589     col_temp = temp;
1590
1591   if (col_lendiff > 0)  /* XXX - was lendiff */
1592     {
1593       /* Non-zero if we're increasing the number of lines. */
1594       int gl = current_line >= _rl_vis_botlin && inv_botlin > _rl_vis_botlin;
1595       /* If col_lendiff is > 0, implying that the new string takes up more
1596          screen real estate than the old, but lendiff is < 0, meaning that it
1597          takes fewer bytes, we need to just output the characters starting
1598          from the first difference.  These will overwrite what is on the
1599          display, so there's no reason to do a smart update.  This can really
1600          only happen in a multibyte environment. */
1601       if (lendiff < 0)
1602         {
1603           _rl_output_some_chars (nfd, temp);
1604           _rl_last_c_pos += _rl_col_width (nfd, 0, temp);
1605           /* If nfd begins before any invisible characters in the prompt,
1606              adjust _rl_last_c_pos to account for wrap_offset and set
1607              cpos_adjusted to let the caller know. */
1608           if (current_line == 0 && wrap_offset && ((nfd - new) <= prompt_last_invisible))
1609             {
1610               _rl_last_c_pos -= wrap_offset;
1611               cpos_adjusted = 1;
1612             }
1613           return;
1614         }
1615       /* Sometimes it is cheaper to print the characters rather than
1616          use the terminal's capabilities.  If we're growing the number
1617          of lines, make sure we actually cause the new line to wrap
1618          around on auto-wrapping terminals. */
1619       else if (_rl_terminal_can_insert && ((2 * col_temp) >= col_lendiff || _rl_term_IC) && (!_rl_term_autowrap || !gl))
1620         {
1621           /* If lendiff > prompt_visible_length and _rl_last_c_pos == 0 and
1622              _rl_horizontal_scroll_mode == 1, inserting the characters with
1623              _rl_term_IC or _rl_term_ic will screw up the screen because of the
1624              invisible characters.  We need to just draw them. */
1625           /* The same thing happens if we're trying to draw before the last
1626              invisible character in the prompt string or we're increasing the
1627              number of invisible characters in the line and we're not drawing
1628              the entire prompt string. */
1629           if (*ols && ((_rl_horizontal_scroll_mode &&
1630                         _rl_last_c_pos == 0 &&
1631                         lendiff > prompt_visible_length &&
1632                         current_invis_chars > 0) == 0) &&
1633                       (((MB_CUR_MAX > 1 && rl_byte_oriented == 0) &&
1634                         current_line == 0 && wrap_offset &&
1635                         ((nfd - new) <= prompt_last_invisible) &&
1636                         (col_lendiff < prompt_visible_length)) == 0) &&
1637                       (visible_wrap_offset >= current_invis_chars))
1638             {
1639               insert_some_chars (nfd, lendiff, col_lendiff);
1640               _rl_last_c_pos += col_lendiff;
1641             }
1642 #if 0           /* XXX - for now */
1643           else if ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) && _rl_last_c_pos == 0 && wrap_offset && (nfd-new) <= prompt_last_invisible && col_lendiff < prompt_visible_length && visible_wrap_offset >= current_invis_chars)
1644             {
1645               _rl_output_some_chars (nfd, lendiff);
1646               _rl_last_c_pos += col_lendiff;
1647             }
1648 #endif
1649           else if ((MB_CUR_MAX == 1 || rl_byte_oriented != 0) && *ols == 0 && lendiff > 0)
1650             {
1651               /* At the end of a line the characters do not have to
1652                  be "inserted".  They can just be placed on the screen. */
1653               /* However, this screws up the rest of this block, which
1654                  assumes you've done the insert because you can. */
1655               _rl_output_some_chars (nfd, lendiff);
1656               _rl_last_c_pos += col_lendiff;
1657             }
1658           else
1659             {
1660               _rl_output_some_chars (nfd, temp);
1661               _rl_last_c_pos += col_temp;
1662               /* If nfd begins before the last invisible character in the
1663                  prompt, adjust _rl_last_c_pos to account for wrap_offset
1664                  and set cpos_adjusted to let the caller know. */
1665               if ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) && current_line == 0 && wrap_offset && ((nfd - new) <= prompt_last_invisible))
1666                 {
1667                   _rl_last_c_pos -= wrap_offset;
1668                   cpos_adjusted = 1;
1669                 }
1670               return;
1671             }
1672           /* Copy (new) chars to screen from first diff to last match. */
1673           temp = nls - nfd;
1674           if ((temp - lendiff) > 0)
1675             {
1676               _rl_output_some_chars (nfd + lendiff, temp - lendiff);
1677              /* XXX -- this bears closer inspection.  Fixes a redisplay bug
1678                 reported against bash-3.0-alpha by Andreas Schwab involving
1679                 multibyte characters and prompt strings with invisible
1680                 characters, but was previously disabled. */
1681               if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1682                 twidth = _rl_col_width (nfd+lendiff, 0, temp-col_lendiff);
1683               else
1684                 twidth = temp - lendiff;
1685               _rl_last_c_pos += twidth;
1686               /* If nfd begins before the last invisible character in the
1687                  prompt, adjust _rl_last_c_pos to account for wrap_offset
1688                  and set cpos_adjusted to let the caller know. */
1689               if ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) && current_line == 0 && wrap_offset && ((nfd - new) <= prompt_last_invisible))
1690                 {
1691                   _rl_last_c_pos -= wrap_offset;
1692                   cpos_adjusted = 1;
1693                 }
1694             }
1695         }
1696       else
1697         {
1698           /* cannot insert chars, write to EOL */
1699           _rl_output_some_chars (nfd, temp);
1700           _rl_last_c_pos += col_temp;
1701           /* If we're in a multibyte locale and were before the last invisible
1702              char in the current line (which implies we just output some invisible
1703              characters) we need to adjust _rl_last_c_pos, since it represents
1704              a physical character position. */
1705           if ((MB_CUR_MAX > 1 && rl_byte_oriented == 0) &&
1706                 current_line == prompt_last_screen_line && wrap_offset &&
1707                 wrap_offset != prompt_invis_chars_first_line &&
1708                 ((nfd-new) < (prompt_last_invisible-(current_line*_rl_screenwidth))))
1709             {
1710               _rl_last_c_pos -= wrap_offset - prompt_invis_chars_first_line;
1711               cpos_adjusted = 1;
1712             }
1713         }
1714     }
1715   else                          /* Delete characters from line. */
1716     {
1717       /* If possible and inexpensive to use terminal deletion, then do so. */
1718       if (_rl_term_dc && (2 * col_temp) >= -col_lendiff)
1719         {
1720           /* If all we're doing is erasing the invisible characters in the
1721              prompt string, don't bother.  It screws up the assumptions
1722              about what's on the screen. */
1723           if (_rl_horizontal_scroll_mode && _rl_last_c_pos == 0 &&
1724               -lendiff == visible_wrap_offset)
1725             col_lendiff = 0;
1726
1727           if (col_lendiff)
1728             delete_chars (-col_lendiff); /* delete (diff) characters */
1729
1730           /* Copy (new) chars to screen from first diff to last match */
1731           temp = nls - nfd;
1732           if (temp > 0)
1733             {
1734               /* If nfd begins at the prompt, or before the invisible
1735                  characters in the prompt, we need to adjust _rl_last_c_pos
1736                  in a multibyte locale to account for the wrap offset and
1737                  set cpos_adjusted accordingly. */
1738               _rl_output_some_chars (nfd, temp);
1739               if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1740                 {
1741                   _rl_last_c_pos += _rl_col_width (nfd, 0, temp);
1742                   if (current_line == 0 && wrap_offset &&  ((nfd - new) <= prompt_last_invisible))
1743                     {
1744                       _rl_last_c_pos -= wrap_offset;
1745                       cpos_adjusted = 1;
1746                     }
1747                 }
1748               else
1749                 _rl_last_c_pos += temp;
1750             }
1751         }
1752       /* Otherwise, print over the existing material. */
1753       else
1754         {
1755           if (temp > 0)
1756             {
1757               /* If nfd begins at the prompt, or before the invisible
1758                  characters in the prompt, we need to adjust _rl_last_c_pos
1759                  in a multibyte locale to account for the wrap offset and
1760                  set cpos_adjusted accordingly. */
1761               _rl_output_some_chars (nfd, temp);
1762               _rl_last_c_pos += col_temp;               /* XXX */
1763               if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1764                 {
1765                   if (current_line == 0 && wrap_offset &&  ((nfd - new) <= prompt_last_invisible))
1766                     {
1767                       _rl_last_c_pos -= wrap_offset;
1768                       cpos_adjusted = 1;
1769                     }
1770                 }
1771             }
1772           lendiff = (oe - old) - (ne - new);
1773           if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1774             col_lendiff = _rl_col_width (old, 0, oe - old) - _rl_col_width (new, 0, ne - new);
1775           else
1776             col_lendiff = lendiff;
1777
1778 #if 0
1779           if (col_lendiff)
1780 #else
1781           /* If we've already printed over the entire width of the screen,
1782              including the old material, then col_lendiff doesn't matter and
1783              space_to_eol will insert too many spaces.  XXX - maybe we should
1784              adjust col_lendiff based on the difference between _rl_last_c_pos
1785              and _rl_screenwidth */
1786           if (col_lendiff && ((MB_CUR_MAX == 1 || rl_byte_oriented) || (_rl_last_c_pos < _rl_screenwidth)))
1787 #endif
1788             {     
1789               if (_rl_term_autowrap && current_line < inv_botlin)
1790                 space_to_eol (col_lendiff);
1791               else
1792                 _rl_clear_to_eol (col_lendiff);
1793             }
1794         }
1795     }
1796 }
1797
1798 /* Tell the update routines that we have moved onto a new (empty) line. */
1799 int
1800 rl_on_new_line ()
1801 {
1802   if (visible_line)
1803     visible_line[0] = '\0';
1804
1805   _rl_last_c_pos = _rl_last_v_pos = 0;
1806   _rl_vis_botlin = last_lmargin = 0;
1807   if (vis_lbreaks)
1808     vis_lbreaks[0] = vis_lbreaks[1] = 0;
1809   visible_wrap_offset = 0;
1810   return 0;
1811 }
1812
1813 /* Tell the update routines that we have moved onto a new line with the
1814    prompt already displayed.  Code originally from the version of readline
1815    distributed with CLISP.  rl_expand_prompt must have already been called
1816    (explicitly or implicitly).  This still doesn't work exactly right. */
1817 int
1818 rl_on_new_line_with_prompt ()
1819 {
1820   int prompt_size, i, l, real_screenwidth, newlines;
1821   char *prompt_last_line, *lprompt;
1822
1823   /* Initialize visible_line and invisible_line to ensure that they can hold
1824      the already-displayed prompt. */
1825   prompt_size = strlen (rl_prompt) + 1;
1826   init_line_structures (prompt_size);
1827
1828   /* Make sure the line structures hold the already-displayed prompt for
1829      redisplay. */
1830   lprompt = local_prompt ? local_prompt : rl_prompt;
1831   strcpy (visible_line, lprompt);
1832   strcpy (invisible_line, lprompt);
1833
1834   /* If the prompt contains newlines, take the last tail. */
1835   prompt_last_line = strrchr (rl_prompt, '\n');
1836   if (!prompt_last_line)
1837     prompt_last_line = rl_prompt;
1838
1839   l = strlen (prompt_last_line);
1840   if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1841     _rl_last_c_pos = _rl_col_width (prompt_last_line, 0, l);    /* XXX */
1842   else
1843     _rl_last_c_pos = l;
1844
1845   /* Dissect prompt_last_line into screen lines. Note that here we have
1846      to use the real screenwidth. Readline's notion of screenwidth might be
1847      one less, see terminal.c. */
1848   real_screenwidth = _rl_screenwidth + (_rl_term_autowrap ? 0 : 1);
1849   _rl_last_v_pos = l / real_screenwidth;
1850   /* If the prompt length is a multiple of real_screenwidth, we don't know
1851      whether the cursor is at the end of the last line, or already at the
1852      beginning of the next line. Output a newline just to be safe. */
1853   if (l > 0 && (l % real_screenwidth) == 0)
1854     _rl_output_some_chars ("\n", 1);
1855   last_lmargin = 0;
1856
1857   newlines = 0; i = 0;
1858   while (i <= l)
1859     {
1860       _rl_vis_botlin = newlines;
1861       vis_lbreaks[newlines++] = i;
1862       i += real_screenwidth;
1863     }
1864   vis_lbreaks[newlines] = l;
1865   visible_wrap_offset = 0;
1866
1867   rl_display_prompt = rl_prompt;        /* XXX - make sure it's set */
1868
1869   return 0;
1870 }
1871
1872 /* Actually update the display, period. */
1873 int
1874 rl_forced_update_display ()
1875 {
1876   register char *temp;
1877
1878   if (visible_line)
1879     {
1880       temp = visible_line;
1881       while (*temp)
1882         *temp++ = '\0';
1883     }
1884   rl_on_new_line ();
1885   forced_display++;
1886   (*rl_redisplay_function) ();
1887   return 0;
1888 }
1889
1890 /* Move the cursor from _rl_last_c_pos to NEW, which are buffer indices.
1891    (Well, when we don't have multibyte characters, _rl_last_c_pos is a
1892    buffer index.)
1893    DATA is the contents of the screen line of interest; i.e., where
1894    the movement is being done. */
1895 void
1896 _rl_move_cursor_relative (new, data)
1897      int new;
1898      const char *data;
1899 {
1900   register int i;
1901   int woff;                     /* number of invisible chars on current line */
1902   int cpos, dpos;               /* current and desired cursor positions */
1903
1904   woff = WRAP_OFFSET (_rl_last_v_pos, wrap_offset);
1905   cpos = _rl_last_c_pos;
1906
1907   if (cpos == 0 && cpos == new)
1908     return;
1909
1910 #if defined (HANDLE_MULTIBYTE)
1911   /* If we have multibyte characters, NEW is indexed by the buffer point in
1912      a multibyte string, but _rl_last_c_pos is the display position.  In
1913      this case, NEW's display position is not obvious and must be
1914      calculated.  We need to account for invisible characters in this line,
1915      as long as we are past them and they are counted by _rl_col_width. */
1916   if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1917     {
1918       dpos = _rl_col_width (data, 0, new);
1919       /* Use NEW when comparing against the last invisible character in the
1920          prompt string, since they're both buffer indices and DPOS is a
1921          desired display position. */
1922       if ((new > prompt_last_invisible) ||              /* XXX - don't use woff here */
1923           (prompt_physical_chars >= _rl_screenwidth &&
1924            _rl_last_v_pos == prompt_last_screen_line &&
1925            wrap_offset >= woff && dpos >= woff &&
1926            new > (prompt_last_invisible-(_rl_screenwidth*_rl_last_v_pos)-wrap_offset)))
1927            /* XXX last comparison might need to be >= */
1928         {
1929           dpos -= woff;
1930           /* Since this will be assigned to _rl_last_c_pos at the end (more
1931              precisely, _rl_last_c_pos == dpos when this function returns),
1932              let the caller know. */
1933           cpos_adjusted = 1;
1934         }
1935     }
1936   else
1937 #endif
1938     dpos = new;
1939
1940   /* If we don't have to do anything, then return. */
1941   if (cpos == dpos)
1942     return;
1943
1944   /* It may be faster to output a CR, and then move forwards instead
1945      of moving backwards. */
1946   /* i == current physical cursor position. */
1947 #if defined (HANDLE_MULTIBYTE)
1948   if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1949     i = _rl_last_c_pos;
1950   else
1951 #endif
1952   i = _rl_last_c_pos - woff;
1953   if (dpos == 0 || CR_FASTER (dpos, _rl_last_c_pos) ||
1954       (_rl_term_autowrap && i == _rl_screenwidth))
1955     {
1956 #if defined (__MSDOS__)
1957       putc ('\r', rl_outstream);
1958 #else
1959       tputs (_rl_term_cr, 1, _rl_output_character_function);
1960 #endif /* !__MSDOS__ */
1961       cpos = _rl_last_c_pos = 0;
1962     }
1963
1964   if (cpos < dpos)
1965     {
1966       /* Move the cursor forward.  We do it by printing the command
1967          to move the cursor forward if there is one, else print that
1968          portion of the output buffer again.  Which is cheaper? */
1969
1970       /* The above comment is left here for posterity.  It is faster
1971          to print one character (non-control) than to print a control
1972          sequence telling the terminal to move forward one character.
1973          That kind of control is for people who don't know what the
1974          data is underneath the cursor. */
1975
1976       /* However, we need a handle on where the current display position is
1977          in the buffer for the immediately preceding comment to be true.
1978          In multibyte locales, we don't currently have that info available.
1979          Without it, we don't know where the data we have to display begins
1980          in the buffer and we have to go back to the beginning of the screen
1981          line.  In this case, we can use the terminal sequence to move forward
1982          if it's available. */
1983       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
1984         {
1985           if (_rl_term_forward_char)
1986             {
1987               for (i = cpos; i < dpos; i++)
1988                 tputs (_rl_term_forward_char, 1, _rl_output_character_function);
1989             }
1990           else
1991             {
1992               tputs (_rl_term_cr, 1, _rl_output_character_function);
1993               for (i = 0; i < new; i++)
1994                 putc (data[i], rl_outstream);
1995             }
1996         }
1997       else
1998         for (i = cpos; i < new; i++)
1999           putc (data[i], rl_outstream);
2000     }
2001
2002 #if defined (HANDLE_MULTIBYTE)
2003   /* NEW points to the buffer point, but _rl_last_c_pos is the display point.
2004      The byte length of the string is probably bigger than the column width
2005      of the string, which means that if NEW == _rl_last_c_pos, then NEW's
2006      display point is less than _rl_last_c_pos. */
2007 #endif
2008   else if (cpos > dpos)
2009     _rl_backspace (cpos - dpos);
2010
2011   _rl_last_c_pos = dpos;
2012 }
2013
2014 /* PWP: move the cursor up or down. */
2015 void
2016 _rl_move_vert (to)
2017      int to;
2018 {
2019   register int delta, i;
2020
2021   if (_rl_last_v_pos == to || to > _rl_screenheight)
2022     return;
2023
2024   if ((delta = to - _rl_last_v_pos) > 0)
2025     {
2026       for (i = 0; i < delta; i++)
2027         putc ('\n', rl_outstream);
2028 #if defined (__MSDOS__)
2029       putc ('\r', rl_outstream);
2030 #else
2031       tputs (_rl_term_cr, 1, _rl_output_character_function);
2032 #endif
2033       _rl_last_c_pos = 0;
2034     }
2035   else
2036     {                   /* delta < 0 */
2037       if (_rl_term_up && *_rl_term_up)
2038         for (i = 0; i < -delta; i++)
2039           tputs (_rl_term_up, 1, _rl_output_character_function);
2040     }
2041
2042   _rl_last_v_pos = to;          /* Now TO is here */
2043 }
2044
2045 /* Physically print C on rl_outstream.  This is for functions which know
2046    how to optimize the display.  Return the number of characters output. */
2047 int
2048 rl_show_char (c)
2049      int c;
2050 {
2051   int n = 1;
2052   if (META_CHAR (c) && (_rl_output_meta_chars == 0))
2053     {
2054       fprintf (rl_outstream, "M-");
2055       n += 2;
2056       c = UNMETA (c);
2057     }
2058
2059 #if defined (DISPLAY_TABS)
2060   if ((CTRL_CHAR (c) && c != '\t') || c == RUBOUT)
2061 #else
2062   if (CTRL_CHAR (c) || c == RUBOUT)
2063 #endif /* !DISPLAY_TABS */
2064     {
2065       fprintf (rl_outstream, "C-");
2066       n += 2;
2067       c = CTRL_CHAR (c) ? UNCTRL (c) : '?';
2068     }
2069
2070   putc (c, rl_outstream);
2071   fflush (rl_outstream);
2072   return n;
2073 }
2074
2075 int
2076 rl_character_len (c, pos)
2077      register int c, pos;
2078 {
2079   unsigned char uc;
2080
2081   uc = (unsigned char)c;
2082
2083   if (META_CHAR (uc))
2084     return ((_rl_output_meta_chars == 0) ? 4 : 1);
2085
2086   if (uc == '\t')
2087     {
2088 #if defined (DISPLAY_TABS)
2089       return (((pos | 7) + 1) - pos);
2090 #else
2091       return (2);
2092 #endif /* !DISPLAY_TABS */
2093     }
2094
2095   if (CTRL_CHAR (c) || c == RUBOUT)
2096     return (2);
2097
2098   return ((ISPRINT (uc)) ? 1 : 2);
2099 }
2100 /* How to print things in the "echo-area".  The prompt is treated as a
2101    mini-modeline. */
2102 static int msg_saved_prompt = 0;
2103
2104 #if defined (USE_VARARGS)
2105 int
2106 #if defined (PREFER_STDARG)
2107 rl_message (const char *format, ...)
2108 #else
2109 rl_message (va_alist)
2110      va_dcl
2111 #endif
2112 {
2113   va_list args;
2114 #if defined (PREFER_VARARGS)
2115   char *format;
2116 #endif
2117
2118 #if defined (PREFER_STDARG)
2119   va_start (args, format);
2120 #else
2121   va_start (args);
2122   format = va_arg (args, char *);
2123 #endif
2124
2125 #if defined (HAVE_VSNPRINTF)
2126   vsnprintf (msg_buf, sizeof (msg_buf) - 1, format, args);
2127 #else
2128   vsprintf (msg_buf, format, args);
2129   msg_buf[sizeof(msg_buf) - 1] = '\0';  /* overflow? */
2130 #endif
2131   va_end (args);
2132
2133   if (saved_local_prompt == 0)
2134     {
2135       rl_save_prompt ();
2136       msg_saved_prompt = 1;
2137     }
2138   rl_display_prompt = msg_buf;
2139   local_prompt = expand_prompt (msg_buf, &prompt_visible_length,
2140                                          &prompt_last_invisible,
2141                                          &prompt_invis_chars_first_line,
2142                                          &prompt_physical_chars);
2143   local_prompt_prefix = (char *)NULL;
2144   local_prompt_len = local_prompt ? strlen (local_prompt) : 0;
2145   (*rl_redisplay_function) ();
2146
2147   return 0;
2148 }
2149 #else /* !USE_VARARGS */
2150 int
2151 rl_message (format, arg1, arg2)
2152      char *format;
2153 {
2154   sprintf (msg_buf, format, arg1, arg2);
2155   msg_buf[sizeof(msg_buf) - 1] = '\0';  /* overflow? */
2156
2157   rl_display_prompt = msg_buf;
2158   if (saved_local_prompt == 0)
2159     {
2160       rl_save_prompt ();
2161       msg_saved_prompt = 1;
2162     }
2163   local_prompt = expand_prompt (msg_buf, &prompt_visible_length,
2164                                          &prompt_last_invisible,
2165                                          &prompt_invis_chars_first_line,
2166                                          &prompt_physical_chars);
2167   local_prompt_prefix = (char *)NULL;
2168   local_prompt_len = local_prompt ? strlen (local_prompt) : 0;
2169   (*rl_redisplay_function) ();
2170       
2171   return 0;
2172 }
2173 #endif /* !USE_VARARGS */
2174
2175 /* How to clear things from the "echo-area". */
2176 int
2177 rl_clear_message ()
2178 {
2179   rl_display_prompt = rl_prompt;
2180   if (msg_saved_prompt)
2181     {
2182       rl_restore_prompt ();
2183       msg_saved_prompt = 0;
2184     }
2185   (*rl_redisplay_function) ();
2186   return 0;
2187 }
2188
2189 int
2190 rl_reset_line_state ()
2191 {
2192   rl_on_new_line ();
2193
2194   rl_display_prompt = rl_prompt ? rl_prompt : "";
2195   forced_display = 1;
2196   return 0;
2197 }
2198
2199 void
2200 rl_save_prompt ()
2201 {
2202   saved_local_prompt = local_prompt;
2203   saved_local_prefix = local_prompt_prefix;
2204   saved_prefix_length = prompt_prefix_length;
2205   saved_local_length = local_prompt_len;
2206   saved_last_invisible = prompt_last_invisible;
2207   saved_visible_length = prompt_visible_length;
2208   saved_invis_chars_first_line = prompt_invis_chars_first_line;
2209   saved_physical_chars = prompt_physical_chars;
2210
2211   local_prompt = local_prompt_prefix = (char *)0;
2212   local_prompt_len = 0;
2213   prompt_last_invisible = prompt_visible_length = prompt_prefix_length = 0;
2214   prompt_invis_chars_first_line = prompt_physical_chars = 0;
2215 }
2216
2217 void
2218 rl_restore_prompt ()
2219 {
2220   FREE (local_prompt);
2221   FREE (local_prompt_prefix);
2222
2223   local_prompt = saved_local_prompt;
2224   local_prompt_prefix = saved_local_prefix;
2225   local_prompt_len = saved_local_length;
2226   prompt_prefix_length = saved_prefix_length;
2227   prompt_last_invisible = saved_last_invisible;
2228   prompt_visible_length = saved_visible_length;
2229   prompt_invis_chars_first_line = saved_invis_chars_first_line;
2230   prompt_physical_chars = saved_physical_chars;
2231
2232   /* can test saved_local_prompt to see if prompt info has been saved. */
2233   saved_local_prompt = saved_local_prefix = (char *)0;
2234   saved_local_length = 0;
2235   saved_last_invisible = saved_visible_length = saved_prefix_length = 0;
2236   saved_invis_chars_first_line = saved_physical_chars = 0;
2237 }
2238
2239 char *
2240 _rl_make_prompt_for_search (pchar)
2241      int pchar;
2242 {
2243   int len;
2244   char *pmt, *p;
2245
2246   rl_save_prompt ();
2247
2248   /* We've saved the prompt, and can do anything with the various prompt
2249      strings we need before they're restored.  We want the unexpanded
2250      portion of the prompt string after any final newline. */
2251   p = rl_prompt ? strrchr (rl_prompt, '\n') : 0;
2252   if (p == 0)
2253     {
2254       len = (rl_prompt && *rl_prompt) ? strlen (rl_prompt) : 0;
2255       pmt = (char *)xmalloc (len + 2);
2256       if (len)
2257         strcpy (pmt, rl_prompt);
2258       pmt[len] = pchar;
2259       pmt[len+1] = '\0';
2260     }
2261   else
2262     {
2263       p++;
2264       len = strlen (p);
2265       pmt = (char *)xmalloc (len + 2);
2266       if (len)
2267         strcpy (pmt, p);
2268       pmt[len] = pchar;
2269       pmt[len+1] = '\0';
2270     }  
2271
2272   /* will be overwritten by expand_prompt, called from rl_message */
2273   prompt_physical_chars = saved_physical_chars + 1;
2274   return pmt;
2275 }
2276
2277 /* Quick redisplay hack when erasing characters at the end of the line. */
2278 void
2279 _rl_erase_at_end_of_line (l)
2280      int l;
2281 {
2282   register int i;
2283
2284   _rl_backspace (l);
2285   for (i = 0; i < l; i++)
2286     putc (' ', rl_outstream);
2287   _rl_backspace (l);
2288   for (i = 0; i < l; i++)
2289     visible_line[--_rl_last_c_pos] = '\0';
2290   rl_display_fixed++;
2291 }
2292
2293 /* Clear to the end of the line.  COUNT is the minimum
2294    number of character spaces to clear, */
2295 void
2296 _rl_clear_to_eol (count)
2297      int count;
2298 {
2299   if (_rl_term_clreol)
2300     tputs (_rl_term_clreol, 1, _rl_output_character_function);
2301   else if (count)
2302     space_to_eol (count);
2303 }
2304
2305 /* Clear to the end of the line using spaces.  COUNT is the minimum
2306    number of character spaces to clear, */
2307 static void
2308 space_to_eol (count)
2309      int count;
2310 {
2311   register int i;
2312
2313   for (i = 0; i < count; i++)
2314    putc (' ', rl_outstream);
2315
2316   _rl_last_c_pos += count;
2317 }
2318
2319 void
2320 _rl_clear_screen ()
2321 {
2322   if (_rl_term_clrpag)
2323     tputs (_rl_term_clrpag, 1, _rl_output_character_function);
2324   else
2325     rl_crlf ();
2326 }
2327
2328 /* Insert COUNT characters from STRING to the output stream at column COL. */
2329 static void
2330 insert_some_chars (string, count, col)
2331      char *string;
2332      int count, col;
2333 {
2334 #if defined (__MSDOS__) || defined (__MINGW32__)
2335   _rl_output_some_chars (string, count);
2336 #else
2337   /* DEBUGGING */
2338   if (MB_CUR_MAX == 1 || rl_byte_oriented)
2339     if (count != col)
2340       _rl_ttymsg ("debug: insert_some_chars: count (%d) != col (%d)", count, col);
2341
2342   /* If IC is defined, then we do not have to "enter" insert mode. */
2343   if (_rl_term_IC)
2344     {
2345       char *buffer;
2346
2347       buffer = tgoto (_rl_term_IC, 0, col);
2348       tputs (buffer, 1, _rl_output_character_function);
2349       _rl_output_some_chars (string, count);
2350     }
2351   else
2352     {
2353       register int i;
2354
2355       /* If we have to turn on insert-mode, then do so. */
2356       if (_rl_term_im && *_rl_term_im)
2357         tputs (_rl_term_im, 1, _rl_output_character_function);
2358
2359       /* If there is a special command for inserting characters, then
2360          use that first to open up the space. */
2361       if (_rl_term_ic && *_rl_term_ic)
2362         {
2363           for (i = col; i--; )
2364             tputs (_rl_term_ic, 1, _rl_output_character_function);
2365         }
2366
2367       /* Print the text. */
2368       _rl_output_some_chars (string, count);
2369
2370       /* If there is a string to turn off insert mode, we had best use
2371          it now. */
2372       if (_rl_term_ei && *_rl_term_ei)
2373         tputs (_rl_term_ei, 1, _rl_output_character_function);
2374     }
2375 #endif /* __MSDOS__ || __MINGW32__ */
2376 }
2377
2378 /* Delete COUNT characters from the display line. */
2379 static void
2380 delete_chars (count)
2381      int count;
2382 {
2383   if (count > _rl_screenwidth)  /* XXX */
2384     return;
2385
2386 #if !defined (__MSDOS__) && !defined (__MINGW32__)
2387   if (_rl_term_DC && *_rl_term_DC)
2388     {
2389       char *buffer;
2390       buffer = tgoto (_rl_term_DC, count, count);
2391       tputs (buffer, count, _rl_output_character_function);
2392     }
2393   else
2394     {
2395       if (_rl_term_dc && *_rl_term_dc)
2396         while (count--)
2397           tputs (_rl_term_dc, 1, _rl_output_character_function);
2398     }
2399 #endif /* !__MSDOS__ && !__MINGW32__ */
2400 }
2401
2402 void
2403 _rl_update_final ()
2404 {
2405   int full_lines;
2406
2407   full_lines = 0;
2408   /* If the cursor is the only thing on an otherwise-blank last line,
2409      compensate so we don't print an extra CRLF. */
2410   if (_rl_vis_botlin && _rl_last_c_pos == 0 &&
2411         visible_line[vis_lbreaks[_rl_vis_botlin]] == 0)
2412     {
2413       _rl_vis_botlin--;
2414       full_lines = 1;
2415     }
2416   _rl_move_vert (_rl_vis_botlin);
2417   /* If we've wrapped lines, remove the final xterm line-wrap flag. */
2418   if (full_lines && _rl_term_autowrap && (VIS_LLEN(_rl_vis_botlin) == _rl_screenwidth))
2419     {
2420       char *last_line;
2421
2422       last_line = &visible_line[vis_lbreaks[_rl_vis_botlin]];
2423       cpos_buffer_position = -1;        /* don't know where we are in buffer */
2424       _rl_move_cursor_relative (_rl_screenwidth - 1, last_line);        /* XXX */
2425       _rl_clear_to_eol (0);
2426       putc (last_line[_rl_screenwidth - 1], rl_outstream);
2427     }
2428   _rl_vis_botlin = 0;
2429   rl_crlf ();
2430   fflush (rl_outstream);
2431   rl_display_fixed++;
2432 }
2433
2434 /* Move to the start of the current line. */
2435 static void
2436 cr ()
2437 {
2438   if (_rl_term_cr)
2439     {
2440 #if defined (__MSDOS__)
2441       putc ('\r', rl_outstream);
2442 #else
2443       tputs (_rl_term_cr, 1, _rl_output_character_function);
2444 #endif
2445       _rl_last_c_pos = 0;
2446     }
2447 }
2448
2449 /* Redraw the last line of a multi-line prompt that may possibly contain
2450    terminal escape sequences.  Called with the cursor at column 0 of the
2451    line to draw the prompt on. */
2452 static void
2453 redraw_prompt (t)
2454      char *t;
2455 {
2456   char *oldp;
2457
2458   oldp = rl_display_prompt;
2459   rl_save_prompt ();
2460
2461   rl_display_prompt = t;
2462   local_prompt = expand_prompt (t, &prompt_visible_length,
2463                                    &prompt_last_invisible,
2464                                    &prompt_invis_chars_first_line,
2465                                    &prompt_physical_chars);
2466   local_prompt_prefix = (char *)NULL;
2467   local_prompt_len = local_prompt ? strlen (local_prompt) : 0;
2468
2469   rl_forced_update_display ();
2470
2471   rl_display_prompt = oldp;
2472   rl_restore_prompt();
2473 }
2474       
2475 /* Redisplay the current line after a SIGWINCH is received. */
2476 void
2477 _rl_redisplay_after_sigwinch ()
2478 {
2479   char *t;
2480
2481   /* Clear the last line (assuming that the screen size change will result in
2482      either more or fewer characters on that line only) and put the cursor at
2483      column 0.  Make sure the right thing happens if we have wrapped to a new
2484      screen line. */
2485   if (_rl_term_cr)
2486     {
2487       _rl_move_vert (_rl_vis_botlin);
2488
2489 #if defined (__MSDOS__)
2490       putc ('\r', rl_outstream);
2491 #else
2492       tputs (_rl_term_cr, 1, _rl_output_character_function);
2493 #endif
2494       _rl_last_c_pos = 0;
2495 #if defined (__MSDOS__)
2496       space_to_eol (_rl_screenwidth);
2497       putc ('\r', rl_outstream);
2498 #else
2499       if (_rl_term_clreol)
2500         tputs (_rl_term_clreol, 1, _rl_output_character_function);
2501       else
2502         {
2503           space_to_eol (_rl_screenwidth);
2504           tputs (_rl_term_cr, 1, _rl_output_character_function);
2505         }
2506 #endif
2507       if (_rl_last_v_pos > 0)
2508         _rl_move_vert (0);
2509     }
2510   else
2511     rl_crlf ();
2512
2513   /* Redraw only the last line of a multi-line prompt. */
2514   t = strrchr (rl_display_prompt, '\n');
2515   if (t)
2516     redraw_prompt (++t);
2517   else
2518     rl_forced_update_display ();
2519 }
2520
2521 void
2522 _rl_clean_up_for_exit ()
2523 {
2524   if (_rl_echoing_p)
2525     {
2526       _rl_move_vert (_rl_vis_botlin);
2527       _rl_vis_botlin = 0;
2528       fflush (rl_outstream);
2529       rl_restart_output (1, 0);
2530     }
2531 }
2532
2533 void
2534 _rl_erase_entire_line ()
2535 {
2536   cr ();
2537   _rl_clear_to_eol (0);
2538   cr ();
2539   fflush (rl_outstream);
2540 }
2541
2542 /* return the `current display line' of the cursor -- the number of lines to
2543    move up to get to the first screen line of the current readline line. */
2544 int
2545 _rl_current_display_line ()
2546 {
2547   int ret, nleft;
2548
2549   /* Find out whether or not there might be invisible characters in the
2550      editing buffer. */
2551   if (rl_display_prompt == rl_prompt)
2552     nleft = _rl_last_c_pos - _rl_screenwidth - rl_visible_prompt_length;
2553   else
2554     nleft = _rl_last_c_pos - _rl_screenwidth;
2555
2556   if (nleft > 0)
2557     ret = 1 + nleft / _rl_screenwidth;
2558   else
2559     ret = 0;
2560
2561   return ret;
2562 }
2563
2564 #if defined (HANDLE_MULTIBYTE)
2565 /* Calculate the number of screen columns occupied by STR from START to END.
2566    In the case of multibyte characters with stateful encoding, we have to
2567    scan from the beginning of the string to take the state into account. */
2568 static int
2569 _rl_col_width (str, start, end)
2570      const char *str;
2571      int start, end;
2572 {
2573   wchar_t wc;
2574   mbstate_t ps;
2575   int tmp, point, width, max;
2576
2577   if (end <= start)
2578     return 0;
2579   if (MB_CUR_MAX == 1 || rl_byte_oriented)
2580 {
2581 _rl_ttymsg ("_rl_col_width: called with MB_CUR_MAX == 1");
2582     return (end - start);
2583 }
2584
2585   memset (&ps, 0, sizeof (mbstate_t));
2586
2587   point = 0;
2588   max = end;
2589
2590   while (point < start)
2591     {
2592       tmp = mbrlen (str + point, max, &ps);
2593       if (MB_INVALIDCH ((size_t)tmp))
2594         {
2595           /* In this case, the bytes are invalid or too short to compose a
2596              multibyte character, so we assume that the first byte represents
2597              a single character. */
2598           point++;
2599           max--;
2600
2601           /* Clear the state of the byte sequence, because in this case the
2602              effect of mbstate is undefined. */
2603           memset (&ps, 0, sizeof (mbstate_t));
2604         }
2605       else if (MB_NULLWCH (tmp))
2606         break;          /* Found '\0' */
2607       else
2608         {
2609           point += tmp;
2610           max -= tmp;
2611         }
2612     }
2613
2614   /* If START is not a byte that starts a character, then POINT will be
2615      greater than START.  In this case, assume that (POINT - START) gives
2616      a byte count that is the number of columns of difference. */
2617   width = point - start;
2618
2619   while (point < end)
2620     {
2621       tmp = mbrtowc (&wc, str + point, max, &ps);
2622       if (MB_INVALIDCH ((size_t)tmp))
2623         {
2624           /* In this case, the bytes are invalid or too short to compose a
2625              multibyte character, so we assume that the first byte represents
2626              a single character. */
2627           point++;
2628           max--;
2629
2630           /* and assume that the byte occupies a single column. */
2631           width++;
2632
2633           /* Clear the state of the byte sequence, because in this case the
2634              effect of mbstate is undefined. */
2635           memset (&ps, 0, sizeof (mbstate_t));
2636         }
2637       else if (MB_NULLWCH (tmp))
2638         break;                  /* Found '\0' */
2639       else
2640         {
2641           point += tmp;
2642           max -= tmp;
2643           tmp = wcwidth(wc);
2644           width += (tmp >= 0) ? tmp : 1;
2645         }
2646     }
2647
2648   width += point - end;
2649
2650   return width;
2651 }
2652 #endif /* HANDLE_MULTIBYTE */