Skip to content

Commit

Permalink
line editors: make putstring functions multibyte aware
Browse files Browse the repository at this point in the history
Symptom on (at least) some Linux systems:

  $ bin/package use
  [blurb skipped]
  «0»37:�/local/src/ksh[dev] $
  «0»37:…/local/src/ksh[dev] $
  «0»37:…/local/src/ksh[dev] $ ▂

If the line editor is emacs, the first prompt is corrupted.
The prompt printed after ^L in emacs is also corrupted.

The cause is the putstring() function in emacs. It calls
ed_putchar() for each byte in the string. This is incorrect for
multibyte characters, as ed_putchar() *is* multibyte aware and
calls mbconv() for each character passed to it.

There is a very similar ed_putstring() function in edit.c that has
the same problem.

There is also a pr_string() function in vi.c that is used for
printing the prompt there; it is not multibyte-aware either, but
the bug is not triggered in vi because pr_string() copies bytes
directly into the output buffer. But it does so without bounds
checking, so a very long prompt could cause a buffer overflow.

src/cmd/ksh93/edit/edit.{c,h}:
- Make ed_putstring() multibyte-aware by using the mbchar macro
  from ast.h. This function is only used for printing the prompt
  and some escape sequences from tput, so also print '?' for
  invalid multibyte characters as this is more useful than just
  copying the invalid byte.
- Make ed_putstring() an extern and declare it in the header.
- While we're here, further cleanup of ed_putchar(). (re: 1eb0b06)

src/cmd/ksh93/edit/{emacs,vi}.c:
- Remove putstring() and pr_string() functions.
- Replace with ed_putstring() calls.
  • Loading branch information
McDutchie committed Mar 7, 2024
1 parent 952cdc5 commit 9ff7f3d
Show file tree
Hide file tree
Showing 6 changed files with 22 additions and 38 deletions.
5 changes: 5 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@ This documents significant changes in the 1.0 branch of ksh 93u+m.
For full details, see the git log at: https://github.com/ksh93/ksh/tree/1.0
Uppercase BUG_* IDs are shell bug IDs as used by the Modernish shell library.

2024-03-07:

- Fixed a bug that caused some systems to corrupt the display of multibyte
characters in the command prompt.

2024-03-05:

- Fixed a regression, introduced on 2021-02-07, that made the common AST
Expand Down
19 changes: 10 additions & 9 deletions src/cmd/ksh93/edit/edit.c
Original file line number Diff line number Diff line change
Expand Up @@ -677,11 +677,12 @@ void ed_setup(Edit_t *ep, int fd, int reedit)
}
}

static void ed_putstring(Edit_t *ep, const char *str)
void ed_putstring(Edit_t *ep, const char *str)
{
int c;
while(c = *str++)
ed_putchar(ep,c);
mbinit();
while (c = mbchar(str))
ed_putchar(ep, c < 0 ? '?' : c);
}

static void ed_nputchar(Edit_t *ep, int n, int c)
Expand Down Expand Up @@ -1019,24 +1020,24 @@ void ed_ungetchar(Edit_t *ep,int c)

void ed_putchar(Edit_t *ep,int c)
{
char buf[8];
char *dp = ep->e_outptr;
int i,size=1;
#if SHOPT_MULTIBYTE
char buf[8];
int size;
#endif /* SHOPT_MULTIBYTE */
if(!dp)
return;
buf[0] = c;
#if SHOPT_MULTIBYTE
/* check for place holder */
if(c == MARKER)
return;
if((size = mbconv(buf, (wchar_t)c)) > 1)
{
for (i = 0; i < (size-1); i++)
int i;
for (i = 0; i < size; i++)
*dp++ = buf[i];
c = buf[i];
}
else
buf[0] = c;
#endif /* SHOPT_MULTIBYTE */
*dp++ = c;
*dp = '\0';
Expand Down
16 changes: 4 additions & 12 deletions src/cmd/ksh93/edit/emacs.c
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ typedef enum

static void draw(Emacs_t*,Draw_t);
static int escape(Emacs_t*,genchar*, int);
static void putstring(Emacs_t*,char*);
static int dosearch(Emacs_t*,genchar*,int);
static void search(Emacs_t*,genchar*,int);
static void setcursor(Emacs_t*,int, int);
static void show_info(Emacs_t*,const char*);
Expand Down Expand Up @@ -599,7 +599,7 @@ int ed_emacsread(void *context, int fd,char *buff,int scend, int reedit)
if (ep->terminal == PAPER)
{
putchar(ep->ed,'\n');
putstring(ep,Prompt);
ed_putstring(ep->ed,Prompt);
}
c = ed_getchar(ep->ed,0);
if (c != usrkill)
Expand All @@ -613,7 +613,7 @@ int ed_emacsread(void *context, int fd,char *buff,int scend, int reedit)
{
ep->terminal = PAPER;
putchar(ep->ed,'\n');
putstring(ep,Prompt);
ed_putstring(ep->ed,Prompt);
}
}
continue;
Expand Down Expand Up @@ -782,14 +782,6 @@ static void show_info(Emacs_t *ep,const char *str)
draw(ep,UPDATE);
}

static void putstring(Emacs_t* ep,char *sp)
{
int c;
while (c= *sp++)
putchar(ep->ed,c);
}


static int escape(Emacs_t* ep,genchar *out,int count)
{
int i,value;
Expand Down Expand Up @@ -1572,7 +1564,7 @@ static void draw(Emacs_t *ep,Draw_t option)
return;
}
*ep->cursor = '\0';
putstring(ep,Prompt); /* start with prompt */
ed_putstring(ep->ed,Prompt); /* start with prompt */
}

/*********************
Expand Down
17 changes: 1 addition & 16 deletions src/cmd/ksh93/edit/vi.c
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,6 @@ static int getcount(Vi_t*,int);
static void getline(Vi_t*,int);
static int getrchar(Vi_t*);
static int mvcursor(Vi_t*,int);
static void pr_string(Vi_t*,const char*);
static void refresh(Vi_t*,int);
static void replace(Vi_t*,int, int);
static void restore_v(Vi_t*);
Expand Down Expand Up @@ -1688,20 +1687,6 @@ static int mvcursor(Vi_t* vp,int motion)
return 1;
}

/*
* print a string
*/

static void pr_string(Vi_t *vp, const char *sp)
{
/*** copy string sp ***/
char *ptr = editb.e_outptr;
while(*sp)
*ptr++ = *sp++;
editb.e_outptr = ptr;
return;
}

/*{ VI_REDRAW( )
*
* Print the prompt and force a total refresh.
Expand All @@ -1714,7 +1699,7 @@ static void pr_string(Vi_t *vp, const char *sp)
void vi_redraw(void *ep)
{
Vi_t *vp = (Vi_t*)ep;
pr_string(vp,Prompt);
ed_putstring(vp->ed,Prompt);
window[0] = '\0';
cur_phys = vp->first_wind;
vp->ofirst_wind = INVALID;
Expand Down
1 change: 1 addition & 0 deletions src/cmd/ksh93/include/edit.h
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ typedef struct edit
#define TCAP_ERASE_EOS "cd"

extern void ed_putchar(Edit_t*, int);
extern void ed_putstring(Edit_t*, const char*);
extern void ed_ringbell(void);
extern void ed_setup(Edit_t*,int, int);
extern void ed_flush(Edit_t*);
Expand Down
2 changes: 1 addition & 1 deletion src/cmd/ksh93/include/version.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

#define SH_RELEASE_FORK "93u+m" /* only change if you develop a new ksh93 fork */
#define SH_RELEASE_SVER "1.0.9-beta" /* semantic version number: https://semver.org */
#define SH_RELEASE_DATE "2024-03-05" /* must be in this format for $((.sh.version)) */
#define SH_RELEASE_DATE "2024-03-07" /* must be in this format for $((.sh.version)) */
#define SH_RELEASE_CPYR "(c) 2020-2024 Contributors to ksh " SH_RELEASE_FORK

/* Scripts sometimes field-split ${.sh.version}, so don't change amount of whitespace. */
Expand Down

0 comments on commit 9ff7f3d

Please sign in to comment.