sh: Hack to fix display width when prompt contains wide characters

This commit is contained in:
K. Lange 2022-08-21 18:51:50 +09:00
parent 15a586a38e
commit f84466b18f

104
apps/sh.c
View File

@ -11,10 +11,10 @@
* @copyright
* This file is part of ToaruOS and is released under the terms
* of the NCSA / University of Illinois License - see LICENSE.md
* Copyright (C) 2013-2018 K. Lange
* Copyright (C) 2013-2022 K. Lange
*/
#define _XOPEN_SOURCE 500
#define _POSIX_C_SOURCE 200112L
#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <stdint.h>
#include <string.h>
@ -28,6 +28,7 @@
#include <errno.h>
#include <fcntl.h>
#include <ctype.h>
#include <wchar.h>
#include <sys/time.h>
#include <sys/times.h>
@ -174,6 +175,63 @@ void gethost() {
memcpy(_hostname, buf.nodename, len+1);
}
#define UTF8_ACCEPT 0
#define UTF8_REJECT 1
static inline uint32_t decode(uint32_t* state, uint32_t* codep, uint32_t byte) {
static int state_table[32] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xxxxxxx */
1,1,1,1,1,1,1,1, /* 10xxxxxx */
2,2,2,2, /* 110xxxxx */
3,3, /* 1110xxxx */
4, /* 11110xxx */
1 /* 11111xxx */
};
static int mask_bytes[32] = {
0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,0x7F,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x1F,0x1F,0x1F,0x1F,
0x0F,0x0F,
0x07,
0x00
};
static int next[5] = {
0,
1,
0,
2,
3
};
if (*state == UTF8_ACCEPT) {
*codep = byte & mask_bytes[byte >> 3];
*state = state_table[byte >> 3];
} else if (*state > 0) {
*codep = (byte & 0x3F) | (*codep << 6);
*state = next[*state];
}
return *state;
}
int display_width_of_string(const char * str) {
uint8_t * s = (uint8_t *)str;
int out = 0;
uint32_t c, state = 0;
while (*s) {
if (!decode(&state, &c, *s)) {
out += wcwidth(c);
} else if (state == UTF8_REJECT) {
state = 0;
}
s++;
}
return out;
}
void print_extended_ps(char * format, char * buffer, int * display_width) {
/* Get the time */
struct tm * timeinfo;
@ -208,7 +266,8 @@ void print_extended_ps(char * format, char * buffer, int * display_width) {
size_t offset = 0;
int is_visible = 1;
*display_width = 0;
char dispchars[1024] = {0};
char * dispout = dispchars;
while (*format) {
if (*format == '\\') {
@ -216,7 +275,7 @@ void print_extended_ps(char * format, char * buffer, int * display_width) {
switch (*format) {
case '\\':
buffer[offset++] = *format;
(*display_width) += is_visible ? 1 : 0;
if (is_visible) *dispout++ = *format;
format++;
break;
case '[':
@ -249,19 +308,19 @@ void print_extended_ps(char * format, char * buffer, int * display_width) {
}
}
buffer[offset++] = i;
(*display_width) += is_visible ? 1 : 0;
if (is_visible) *dispout++ = i;
}
break;
case 'e':
buffer[offset++] = '\033';
(*display_width) += is_visible ? 1 : 0;
if (is_visible) *dispout++ = '\033';
format++;
break;
case 'd':
{
int size = sprintf(buffer+offset, "%s", date_buffer);
offset += size;
(*display_width) += is_visible ? size : 0;
if (is_visible) { dispout += sprintf(dispout, "%s", date_buffer); }
}
format++;
break;
@ -269,7 +328,7 @@ void print_extended_ps(char * format, char * buffer, int * display_width) {
{
int size = sprintf(buffer+offset, "%s", time_buffer);
offset += size;
(*display_width) += is_visible ? size : 0;
if (is_visible) { dispout += sprintf(dispout, "%s", time_buffer); }
}
format++;
break;
@ -277,7 +336,7 @@ void print_extended_ps(char * format, char * buffer, int * display_width) {
{
int size = sprintf(buffer+offset, "%s", _hostname);
offset += size;
(*display_width) += is_visible ? size : 0;
if (is_visible) { dispout += sprintf(dispout, "%s", _hostname); }
}
format++;
break;
@ -285,7 +344,7 @@ void print_extended_ps(char * format, char * buffer, int * display_width) {
{
int size = sprintf(buffer+offset, "%s", username);
offset += size;
(*display_width) += is_visible ? size : 0;
if (is_visible) { dispout += sprintf(dispout, "%s", username); }
}
format++;
break;
@ -293,13 +352,13 @@ void print_extended_ps(char * format, char * buffer, int * display_width) {
{
int size = sprintf(buffer+offset, "%s", _cwd);
offset += size;
(*display_width) += is_visible ? size : 0;
if (is_visible) { dispout += sprintf(dispout, "%s", _cwd); }
}
format++;
break;
case '$':
buffer[offset++] = (getuid() == 0 ? '#' : '$');
(*display_width) += is_visible ? 1 : 0;
if (is_visible) *dispout++ = (getuid() == 0 ? '#' : '$');
format++;
break;
case 'U': /* prompt color string */
@ -314,7 +373,7 @@ void print_extended_ps(char * format, char * buffer, int * display_width) {
{
int size = sprintf(buffer+offset, "%s", ret);
offset += size;
(*display_width) += is_visible ? size : 0;
if (is_visible) { dispout += sprintf(dispout, "%s", ret); }
}
format++;
break;
@ -322,33 +381,23 @@ void print_extended_ps(char * format, char * buffer, int * display_width) {
{
int size = sprintf(buffer+offset, "\\%c", *format);
offset += size;
(*display_width) += is_visible ? size : 0;
if (is_visible) { dispout += sprintf(dispout, "\\%c", *format); }
}
format++;
break;
}
} else {
buffer[offset++] = *format;
(*display_width) += is_visible ? 1 : 0;
if (is_visible) *dispout++ = *format;
format++;
}
}
*display_width = display_width_of_string(dispchars);
buffer[offset] = '\0';
}
#define FALLBACK_PS1 "\\u@\\h \\w\\$ "
/* Draw the user prompt */
void draw_prompt(void) {
char * ps1 = getenv("PS1");
char buf[1024];
int display_width;
print_extended_ps(ps1 ? ps1 : FALLBACK_PS1, buf, &display_width);
fprintf(stdout, "%s", buf);
fflush(stdout);
}
volatile int break_while = 0;
pid_t suspended_pgid = 0;
hashmap_t * job_hash = NULL;
@ -712,6 +761,7 @@ void add_environment(list_t * env) {
}
}
#define FALLBACK_PS1 "\\u@\\h \\w\\$ "
int read_entry(char * buffer) {
char lprompt[1024], rprompt[1024];
int lwidth, rwidth;