Commit 4c835cb9 authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

help: wrap Unicode text correctly (fixes #5417)

parent 02633e29
...@@ -25,6 +25,8 @@ ...@@ -25,6 +25,8 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <wchar.h>
#include <wctype.h>
#include <vlc_common.h> #include <vlc_common.h>
#include <vlc_charset.h> #include <vlc_charset.h>
...@@ -37,6 +39,7 @@ ...@@ -37,6 +39,7 @@
#if defined( _WIN32 ) && !VLC_WINSTORE_APP #if defined( _WIN32 ) && !VLC_WINSTORE_APP
static void ShowConsole (void); static void ShowConsole (void);
static void PauseConsole (void); static void PauseConsole (void);
# define wcwidth(cp) (cp, 1) /* LOL */
#else #else
# define ShowConsole() (void)0 # define ShowConsole() (void)0
# define PauseConsole() (void)0 # define PauseConsole() (void)0
...@@ -249,60 +252,88 @@ static void print_section(const module_t *m, const module_config_t **sect, ...@@ -249,60 +252,88 @@ static void print_section(const module_t *m, const module_config_t **sect,
module_gettext(m, item->psz_longtext)); module_gettext(m, item->psz_longtext));
} }
static void print_desc(/*const XXX*/ char *text, unsigned margin, bool color) static void print_desc(const char *str, unsigned margin, bool color)
{ {
unsigned width = ConsoleWidth() - margin; unsigned width = ConsoleWidth() - margin;
size_t i_cur_width = width;
if (text[0] == '\0') if (color)
strcpy(text, " "); fputs(BLUE, stdout);
while (*text) const char *word = str;
{ int wordlen = 0, wordwidth = 0;
char *psz_parser, *psz_word; unsigned offset = 0;
size_t i_end = strlen(text); bool newline = true;
/* If the remaining text fits in a line, print it. */ while (str[0])
if( i_end <= i_cur_width )
{ {
printf(color ? BLUE"%s\n"GRAY : "%s\n", text); uint32_t cp;
size_t charlen = vlc_towc(str, &cp);
if (unlikely(charlen == (size_t)-1))
break; break;
}
/* Otherwise, eat as many words as possible */ int charwidth = wcwidth(cp);
psz_parser = text; if (charwidth < 0)
do charwidth = 0;
{
psz_word = psz_parser;
psz_parser = strchr( psz_word, ' ' );
/* If no space was found, we reached the end of the text
* block; otherwise, we skip the space we just found. */
psz_parser = psz_parser ? psz_parser + 1 : text + i_end;
} str += charlen;
while( (size_t)(psz_parser - text) <= i_cur_width );
/* We cut a word in one of these cases: if (iswspace(cp))
* - it's the only word in the line and it's too long. {
* - we used less than 80% of the width and the word we are if (!newline)
* going to wrap is longer than 40% of the width, and even
* if the word would have fit in the next line. */
if( psz_word == text
|| ( (size_t)(psz_word - text) < 80 * i_cur_width / 100
&& (size_t)(psz_parser - psz_word) > 40 * i_cur_width / 100 ) )
{ {
char c = text[i_cur_width]; fputc(' ', stdout); /* insert space */
text[i_cur_width] = '\0'; charwidth = 1;
printf(color ? BLUE"%s\n%*s"GRAY : "%s\n%*s", text, margin, ""); }
text += i_cur_width; fwrite(word, 1, wordlen, stdout); /* write complete word */
text[0] = c; word = str;
wordlen = 0;
wordwidth = 0;
newline = false;
} }
else else
{ {
psz_word[-1] = '\0'; wordlen += charlen;
printf(color ? BLUE"%s\n%*s"GRAY : "%s\n%*s", text, margin, ""); wordwidth += charwidth;
text = psz_word; }
offset += charwidth;
if (offset >= width)
{
if (newline)
{ /* overflow (word wider than line) */
fwrite(word, 1, wordlen - charlen, stdout);
word = str - charlen;
wordlen = charlen;
wordwidth = charwidth;
} }
printf("\n%*s", margin, ""); /* new line */
offset = wordwidth;
newline = true;
}
}
if (!newline)
fputc(' ', stdout);
printf(color ? "%s\n"GRAY : "%s\n", word);
}
static int vlc_swidth(const char *str)
{
for (int total = 0;;)
{
uint32_t cp;
size_t charlen = vlc_towc(str, &cp);
if (charlen == 0)
return total;
if (charlen == (size_t)-1)
return -1;
str += charlen;
int w = wcwidth(cp);
if (w == -1)
return -1;
total += w;
} }
} }
...@@ -423,9 +454,9 @@ static void print_item(const module_t *m, const module_config_t *item, ...@@ -423,9 +454,9 @@ static void print_item(const module_t *m, const module_config_t *item,
/* Wrap description */ /* Wrap description */
int offset = PADDING_SPACES - strlen(item->psz_name) int offset = PADDING_SPACES - strlen(item->psz_name)
- strlen(bra) - strlen(type) - strlen(ket) - 1; - strlen(bra) - vlc_swidth(type) - strlen(ket) - 1;
if (CONFIG_CLASS(item->i_type) == CONFIG_ITEM_BOOL) if (CONFIG_CLASS(item->i_type) == CONFIG_ITEM_BOOL)
offset -= strlen(item->psz_name) + strlen(prefix); offset -= strlen(item->psz_name) + vlc_swidth(prefix);
if (offset < 0) if (offset < 0)
{ {
fputc('\n', stdout); fputc('\n', stdout);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment