summaryrefslogtreecommitdiffabout
path: root/frm
authorSergey Poznyakoff <gray@gnu.org.ua>2005-02-28 21:22:05 (GMT)
committer Sergey Poznyakoff <gray@gnu.org.ua>2005-02-28 21:22:05 (GMT)
commit0575858a61c4ffcdb4fad7bae6853992e3d43913 (patch) (side-by-side diff)
tree63751a7026f5d1c041b6820b09828b80196698b1 /frm
parent8206377e1bf56a5a86ec18e16e226d808d6123b8 (diff)
downloadmailutils-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') (more/less context) (ignore whitespace changes)
-rw-r--r--frm/frm.c469
1 files changed, 307 insertions, 162 deletions
diff --git a/frm/frm.c b/frm/frm.c
index 576d061..73078da 100644
--- a/frm/frm.c
+++ b/frm/frm.c
@@ -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

Return to:

Send suggestions and report system problems to the System administrator.