diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2005-02-28 21:22:05 +0000 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2005-02-28 21:22:05 +0000 |
commit | 0575858a61c4ffcdb4fad7bae6853992e3d43913 (patch) | |
tree | 63751a7026f5d1c041b6820b09828b80196698b1 /frm | |
parent | 8206377e1bf56a5a86ec18e16e226d808d6123b8 (diff) | |
download | mailutils-0575858a61c4ffcdb4fad7bae6853992e3d43913.tar.gz mailutils-0575858a61c4ffcdb4fad7bae6853992e3d43913.tar.bz2 |
Rewritten output routines using FriBidi. Arabic
subject lines look almost OK, except that all characters are
displayed in isolated variant.
Diffstat (limited to 'frm')
-rw-r--r-- | frm/frm.c | 469 |
1 files changed, 307 insertions, 162 deletions
@@ -42,6 +42,10 @@ #include <mbswidth.h> #include <xalloc.h> +#ifdef HAVE_FRIBIDI_FRIBIDI_H +# include <fribidi/fribidi.h> +#endif + #include <mailutils/address.h> #include <mailutils/argp.h> #include <mailutils/attribute.h> @@ -80,6 +84,7 @@ static int select_attribute; static int selected; static int action (observer_t, size_t); +void init_output (size_t s); const char *program_version = "frm (" PACKAGE_STRING ")"; static char doc[] = N_("GNU frm -- display From: lines"); @@ -182,6 +187,36 @@ decode_attr (char *arg) +/* Get the number of columns on the screen + First try an ioctl() call, not all shells set the COLUMNS environ. + If ioctl does not succeed on stdout, try it on /dev/tty, as we + may work via a pipe. + + This function was taken from mail/util.c. It should probably reside + in the library */ +int +util_getcols (void) +{ + struct winsize ws; + + ws.ws_col = ws.ws_row = 0; + if (ioctl (1, TIOCGWINSZ, (char *) &ws) < 0) + { + int fd = open ("/dev/tty", O_RDWR); + ioctl (fd, TIOCGWINSZ, (char *) &ws); + close (fd); + } + if (ws.ws_row == 0) + { + const char *columns = getenv ("COLUMNS"); + if (columns) + ws.ws_col = strtol (columns, NULL, 10); + } + return ws.ws_col; +} + + + static struct argp_option options[] = { {"debug", 'd', NULL, 0, N_("Enable debugging output"), 0}, {"field", 'f', N_("NAME"), 0, N_("Header field to display"), 0}, @@ -195,6 +230,237 @@ static struct argp_option options[] = { {0, 0, 0, 0} }; +static error_t +parse_opt (int key, char *arg, struct argp_state *state) +{ + switch (key) + { + case 'd': + dbug++; + break; + + case 'f': + show_field = arg; + align = 0; + break; + + case 'l': + show_to = 1; + break; + + case 'n': + show_number = 1; + break; + + case 'Q': + /* Very silent. */ + be_quiet += 2; + break; + + case 'q': + be_quiet++; + show_query = 1; + break; + + case 'S': + show_summary = 1; + break; + + case 's': + select_attribute = decode_attr (arg); + break; + + case 't': + align = 1; + break; + + case ARGP_KEY_FINI: + { + size_t s; + if (align && (s = util_getcols ())) + init_output (s); + else + init_output (0); + } + break; + + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +static struct argp argp = { + options, + parse_opt, + N_("[URL ...]"), + doc, + NULL, + NULL, NULL +}; + +static const char *frm_argp_capa[] = { + "common", + "license", + "mailbox", +#ifdef WITH_TLS + "tls", +#endif + NULL +}; + + +/* Charset magic */ +static char *output_charset = NULL; + +const char * +get_charset () +{ + char *tmp; + + if (!output_charset) + { + char locale[32]; + + memset (locale, 0, sizeof (locale)); + + /* Try to deduce the charset from LC_ALL or LANG variables */ + + tmp = getenv ("LC_ALL"); + if (!tmp) + tmp = getenv ("LANG"); + + if (tmp) + { + char *sp = NULL; + char *lang; + char *terr; + + strncpy (locale, tmp, sizeof (locale) - 1); + + lang = strtok_r (locale, "_", &sp); + terr = strtok_r (NULL, ".", &sp); + output_charset = strtok_r (NULL, "@", &sp); + + if (output_charset) + output_charset = xstrdup (output_charset); + else + output_charset = mu_charset_lookup (lang, terr); + + if (!output_charset) + output_charset = "ASCII"; + } + } + return output_charset; +} + + +/* BIDI support (will be moved to lib when it's ready) */ +#ifdef HAVE_LIBFRIBIDI + +static int fb_charset_num = -1; +FriBidiChar *logical; +char *outstring; +size_t logical_size; + +void +alloc_logical (size_t size) +{ + logical = xmalloc (size * sizeof (logical[0])); + logical_size = size; + outstring = xmalloc (size); +} + +void +puts_bidi (char *string) +{ + if (fb_charset_num == -1) + { + fb_charset_num = fribidi_parse_charset (get_charset ()); + if (fb_charset_num && dbug) + mu_error (_("fribidi failed to recognize charset `%s'"), + get_charset ()); + } + + if (fb_charset_num == 0) + puts (string); + else + { + FriBidiStrIndex len; + FriBidiCharType base = FRIBIDI_TYPE_ON; + fribidi_boolean log2vis; + + static FriBidiChar *visual; + static size_t visual_size; + + + len = fribidi_charset_to_unicode (fb_charset_num, + string, strlen (string), + logical); + + if (len + 1 > visual_size) + { + visual_size = len + 1; + visual = xrealloc (visual, visual_size * sizeof *visual); + } + + /* Create a bidi string. */ + log2vis = fribidi_log2vis (logical, len, &base, + /* output */ + visual, NULL, NULL, NULL); + + if (log2vis) + { + FriBidiStrIndex idx, st; + FriBidiStrIndex new_len; + + for (idx = 0; idx < len;) + { + FriBidiStrIndex wid, inlen; + + wid = 3 * logical_size; + st = idx; + + if (fb_charset_num != FRIBIDI_CHARSET_CAP_RTL) + { + while (wid > 0 && idx < len) + wid -= fribidi_wcwidth (visual[idx++]); + } + else + { + while (wid > 0 && idx < len) + { + wid--; + idx++; + } + } + + if (wid < 0 && idx > st + 1) + idx--; + inlen = idx - st; + + new_len = fribidi_unicode_to_charset (fb_charset_num, + visual + st, inlen, + outstring); + printf ("%s", outstring); + } + putchar ('\n'); + } + else + { + /* Print the string as is */ + puts (string); + } + } +} +#else +# define alloc_logical(s) +# define puts_bidi puts +#endif + + +/* Output functions */ + /* Number of columns in output: Maximum 4 message number, to, from, subject -ln @@ -220,23 +486,24 @@ print_line () { if (linebuf) { - puts (linebuf); + puts_bidi (linebuf); linebuf[0] = 0; linepos = 0; curcol = nextstart = 0; - curfield = 0; } else putchar ('\n'); + curfield = 0; } void format_field_simple (const char *fmt, ...) { va_list ap; + if (curfield++) + putchar ('\t'); va_start (ap, fmt); vprintf (fmt, ap); - putchar (' '); va_end (ap); } @@ -253,7 +520,7 @@ format_field_align (const char *fmt, ...) { if (curfield == numfields - 1) { - puts (linebuf); + puts_bidi (linebuf); linepos = 0; printf ("%*s", nextstart, ""); } @@ -298,137 +565,47 @@ format_field_align (const char *fmt, ...) nextstart += fieldwidth[curfield++]; } -/* - * Get the number of columns on the screen - * First try an ioctl() call not all shells set the COLUMNS environ. - * This function was taken from mail/util.c. - */ -int -util_getcols (void) +void +init_output (size_t s) { - struct winsize ws; - - ws.ws_col = ws.ws_row = 0; - if (ioctl (1, TIOCGWINSZ, (char *) &ws) < 0) - { - int fd = open ("/dev/tty", O_RDWR); - ioctl (fd, TIOCGWINSZ, (char *) &ws); - close (fd); - } - if (ws.ws_row == 0) - { - const char *columns = getenv ("COLUMNS"); - if (columns) - ws.ws_col = strtol (columns, NULL, 10); - } - return ws.ws_col; -} + int i; + size_t width = 0; -static error_t -parse_opt (int key, char *arg, struct argp_state *state) -{ - switch (key) + if (s == 0) { - case 'd': - dbug++; - break; - - case 'f': - show_field = arg; - align = 0; - break; - - case 'l': - show_to = 1; - break; - - case 'n': - show_number = 1; - break; - - case 'Q': - /* Very silent. */ - be_quiet += 2; - break; - - case 'q': - be_quiet++; - show_query = 1; - break; - - case 'S': - show_summary = 1; - break; - - case 's': - select_attribute = decode_attr (arg); - break; - - case 't': - align = 1; - break; - - case ARGP_KEY_FINI: - if (align && (linemax = util_getcols ())) - { - int i; - size_t width = 0; - - format_field = format_field_align; - - /* Allocate the line buffer */ - linemax = linemax * MB_LEN_MAX + 1; - linebuf = xmalloc (linemax); - - /* Set up column widths */ - if (show_number) - fieldwidth[numfields++] = 5; - - if (show_to) - fieldwidth[numfields++] = 20; - - if (show_field) - fieldwidth[numfields++] = 0; - else - { - fieldwidth[numfields++] = 20; - fieldwidth[numfields++] = 0; - } + format_field = format_field_simple; + return; + } + + format_field = format_field_align; - for (i = 0; i < numfields; i++) - width += fieldwidth[i]; + /* Allocate the line buffer */ + linemax = s * MB_LEN_MAX + 1; + linebuf = xmalloc (linemax); + alloc_logical (s); - fieldwidth[numfields-1] = util_getcols () - width; - } - else - format_field = format_field_simple; - break; - - default: - return ARGP_ERR_UNKNOWN; + /* Set up column widths */ + if (show_number) + fieldwidth[numfields++] = 5; + + if (show_to) + fieldwidth[numfields++] = 20; + + if (show_field) + fieldwidth[numfields++] = 0; + else + { + fieldwidth[numfields++] = 20; + fieldwidth[numfields++] = 0; } - return 0; + + for (i = 0; i < numfields; i++) + width += fieldwidth[i]; + + fieldwidth[numfields-1] = util_getcols () - width; } -static struct argp argp = { - options, - parse_opt, - N_("[URL ...]"), - doc, - NULL, - NULL, NULL -}; - -static const char *frm_argp_capa[] = { - "common", - "license", - "mailbox", -#ifdef WITH_TLS - "tls", -#endif - NULL -}; - + /* FIXME: Generalize this function and move it to `mailbox/locale.c'. Do the same with the one @@ -439,39 +616,7 @@ rfc2047_decode_wrapper (char *buf, size_t buflen) { int rc; char *tmp; - static char *charset = NULL; - - if (!charset) - { - char locale[32]; - - memset (locale, 0, sizeof (locale)); - - /* Try to deduce the charset from LC_ALL or LANG variables */ - - tmp = getenv ("LC_ALL"); - if (!tmp) - tmp = getenv ("LANG"); - - if (tmp) - { - char *sp = NULL; - char *lang; - char *terr; - - strncpy (locale, tmp, sizeof (locale) - 1); - - lang = strtok_r (locale, "_", &sp); - terr = strtok_r (NULL, ".", &sp); - charset = strtok_r (NULL, "@", &sp); - - if (!charset) - charset = mu_charset_lookup (lang, terr); - - if (!charset) - charset = "ASCII"; - } - } + const char *charset = get_charset (); if (strcmp (charset, "ASCII") == 0) return strdup (buf); @@ -566,7 +711,7 @@ action (observer_t o, size_t type) break; if (show_number) - format_field ("%4lu: ", (u_long) counter.index); + format_field ("%4lu:", (u_long) counter.index); if (show_to) { @@ -575,7 +720,7 @@ action (observer_t o, size_t type) if (status == 0) { - format_field ("(%s) ", hto); + format_field ("(%s)", hto); free (hto); } else |