[vlc-commits] help: wrap Unicode text correctly (fixes #5417)
Rémi Denis-Courmont
git at videolan.org
Fri Oct 25 22:02:52 CEST 2013
vlc | branch: master | Rémi Denis-Courmont <remi at remlab.net> | Fri Oct 25 22:22:30 2013 +0300| [4c835cb958b6fa4f0d33323ce4ea24d07842bdef] | committer: Rémi Denis-Courmont
help: wrap Unicode text correctly (fixes #5417)
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=4c835cb958b6fa4f0d33323ce4ea24d07842bdef
---
src/config/help.c | 117 +++++++++++++++++++++++++++++++++--------------------
1 file changed, 74 insertions(+), 43 deletions(-)
diff --git a/src/config/help.c b/src/config/help.c
index 45fe798..a36d245 100644
--- a/src/config/help.c
+++ b/src/config/help.c
@@ -25,6 +25,8 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
+#include <wchar.h>
+#include <wctype.h>
#include <vlc_common.h>
#include <vlc_charset.h>
@@ -37,6 +39,7 @@
#if defined( _WIN32 ) && !VLC_WINSTORE_APP
static void ShowConsole (void);
static void PauseConsole (void);
+# define wcwidth(cp) (cp, 1) /* LOL */
#else
# define ShowConsole() (void)0
# define PauseConsole() (void)0
@@ -249,60 +252,88 @@ static void print_section(const module_t *m, const module_config_t **sect,
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;
- size_t i_cur_width = width;
- if (text[0] == '\0')
- strcpy(text, " ");
+ if (color)
+ fputs(BLUE, stdout);
- while (*text)
- {
- char *psz_parser, *psz_word;
- size_t i_end = strlen(text);
+ const char *word = str;
+ int wordlen = 0, wordwidth = 0;
+ unsigned offset = 0;
+ bool newline = true;
- /* If the remaining text fits in a line, print it. */
- if( i_end <= i_cur_width )
- {
- printf(color ? BLUE"%s\n"GRAY : "%s\n", text);
+ while (str[0])
+ {
+ uint32_t cp;
+ size_t charlen = vlc_towc(str, &cp);
+ if (unlikely(charlen == (size_t)-1))
break;
- }
- /* Otherwise, eat as many words as possible */
- psz_parser = text;
- do
- {
- 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;
+ int charwidth = wcwidth(cp);
+ if (charwidth < 0)
+ charwidth = 0;
- }
- while( (size_t)(psz_parser - text) <= i_cur_width );
-
- /* We cut a word in one of these cases:
- * - 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
- * 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 ) )
+ str += charlen;
+
+ if (iswspace(cp))
{
- char c = text[i_cur_width];
- text[i_cur_width] = '\0';
- printf(color ? BLUE"%s\n%*s"GRAY : "%s\n%*s", text, margin, "");
- text += i_cur_width;
- text[0] = c;
+ if (!newline)
+ {
+ fputc(' ', stdout); /* insert space */
+ charwidth = 1;
+ }
+ fwrite(word, 1, wordlen, stdout); /* write complete word */
+ word = str;
+ wordlen = 0;
+ wordwidth = 0;
+ newline = false;
}
else
{
- psz_word[-1] = '\0';
- printf(color ? BLUE"%s\n%*s"GRAY : "%s\n%*s", text, margin, "");
- text = psz_word;
+ wordlen += charlen;
+ wordwidth += charwidth;
}
+
+ 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,
/* Wrap description */
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)
- offset -= strlen(item->psz_name) + strlen(prefix);
+ offset -= strlen(item->psz_name) + vlc_swidth(prefix);
if (offset < 0)
{
fputc('\n', stdout);
More information about the vlc-commits
mailing list