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 @@ | |||
42 | #include <mbswidth.h> | 42 | #include <mbswidth.h> |
43 | #include <xalloc.h> | 43 | #include <xalloc.h> |
44 | 44 | ||
45 | #ifdef HAVE_FRIBIDI_FRIBIDI_H | ||
46 | # include <fribidi/fribidi.h> | ||
47 | #endif | ||
48 | |||
45 | #include <mailutils/address.h> | 49 | #include <mailutils/address.h> |
46 | #include <mailutils/argp.h> | 50 | #include <mailutils/argp.h> |
47 | #include <mailutils/attribute.h> | 51 | #include <mailutils/attribute.h> |
@@ -80,6 +84,7 @@ static int select_attribute; | |||
80 | static int selected; | 84 | static int selected; |
81 | 85 | ||
82 | static int action (observer_t, size_t); | 86 | static int action (observer_t, size_t); |
87 | void init_output (size_t s); | ||
83 | 88 | ||
84 | const char *program_version = "frm (" PACKAGE_STRING ")"; | 89 | const char *program_version = "frm (" PACKAGE_STRING ")"; |
85 | static char doc[] = N_("GNU frm -- display From: lines"); | 90 | static char doc[] = N_("GNU frm -- display From: lines"); |
@@ -182,6 +187,36 @@ decode_attr (char *arg) | |||
182 | 187 | ||
183 | 188 | ||
184 | 189 | ||
190 | /* Get the number of columns on the screen | ||
191 | First try an ioctl() call, not all shells set the COLUMNS environ. | ||
192 | If ioctl does not succeed on stdout, try it on /dev/tty, as we | ||
193 | may work via a pipe. | ||
194 | |||
195 | This function was taken from mail/util.c. It should probably reside | ||
196 | in the library */ | ||
197 | int | ||
198 | util_getcols (void) | ||
199 | { | ||
200 | struct winsize ws; | ||
201 | |||
202 | ws.ws_col = ws.ws_row = 0; | ||
203 | if (ioctl (1, TIOCGWINSZ, (char *) &ws) < 0) | ||
204 | { | ||
205 | int fd = open ("/dev/tty", O_RDWR); | ||
206 | ioctl (fd, TIOCGWINSZ, (char *) &ws); | ||
207 | close (fd); | ||
208 | } | ||
209 | if (ws.ws_row == 0) | ||
210 | { | ||
211 | const char *columns = getenv ("COLUMNS"); | ||
212 | if (columns) | ||
213 | ws.ws_col = strtol (columns, NULL, 10); | ||
214 | } | ||
215 | return ws.ws_col; | ||
216 | } | ||
217 | |||
218 | |||
219 | |||
185 | static struct argp_option options[] = { | 220 | static struct argp_option options[] = { |
186 | {"debug", 'd', NULL, 0, N_("Enable debugging output"), 0}, | 221 | {"debug", 'd', NULL, 0, N_("Enable debugging output"), 0}, |
187 | {"field", 'f', N_("NAME"), 0, N_("Header field to display"), 0}, | 222 | {"field", 'f', N_("NAME"), 0, N_("Header field to display"), 0}, |
@@ -195,6 +230,237 @@ static struct argp_option options[] = { | |||
195 | {0, 0, 0, 0} | 230 | {0, 0, 0, 0} |
196 | }; | 231 | }; |
197 | 232 | ||
233 | static error_t | ||
234 | parse_opt (int key, char *arg, struct argp_state *state) | ||
235 | { | ||
236 | switch (key) | ||
237 | { | ||
238 | case 'd': | ||
239 | dbug++; | ||
240 | break; | ||
241 | |||
242 | case 'f': | ||
243 | show_field = arg; | ||
244 | align = 0; | ||
245 | break; | ||
246 | |||
247 | case 'l': | ||
248 | show_to = 1; | ||
249 | break; | ||
250 | |||
251 | case 'n': | ||
252 | show_number = 1; | ||
253 | break; | ||
254 | |||
255 | case 'Q': | ||
256 | /* Very silent. */ | ||
257 | be_quiet += 2; | ||
258 | break; | ||
259 | |||
260 | case 'q': | ||
261 | be_quiet++; | ||
262 | show_query = 1; | ||
263 | break; | ||
264 | |||
265 | case 'S': | ||
266 | show_summary = 1; | ||
267 | break; | ||
268 | |||
269 | case 's': | ||
270 | select_attribute = decode_attr (arg); | ||
271 | break; | ||
272 | |||
273 | case 't': | ||
274 | align = 1; | ||
275 | break; | ||
276 | |||
277 | case ARGP_KEY_FINI: | ||
278 | { | ||
279 | size_t s; | ||
280 | if (align && (s = util_getcols ())) | ||
281 | init_output (s); | ||
282 | else | ||
283 | init_output (0); | ||
284 | } | ||
285 | break; | ||
286 | |||
287 | default: | ||
288 | return ARGP_ERR_UNKNOWN; | ||
289 | } | ||
290 | return 0; | ||
291 | } | ||
292 | |||
293 | static struct argp argp = { | ||
294 | options, | ||
295 | parse_opt, | ||
296 | N_("[URL ...]"), | ||
297 | doc, | ||
298 | NULL, | ||
299 | NULL, NULL | ||
300 | }; | ||
301 | |||
302 | static const char *frm_argp_capa[] = { | ||
303 | "common", | ||
304 | "license", | ||
305 | "mailbox", | ||
306 | #ifdef WITH_TLS | ||
307 | "tls", | ||
308 | #endif | ||
309 | NULL | ||
310 | }; | ||
311 | |||
312 | |||
313 | /* Charset magic */ | ||
314 | static char *output_charset = NULL; | ||
315 | |||
316 | const char * | ||
317 | get_charset () | ||
318 | { | ||
319 | char *tmp; | ||
320 | |||
321 | if (!output_charset) | ||
322 | { | ||
323 | char locale[32]; | ||
324 | |||
325 | memset (locale, 0, sizeof (locale)); | ||
326 | |||
327 | /* Try to deduce the charset from LC_ALL or LANG variables */ | ||
328 | |||
329 | tmp = getenv ("LC_ALL"); | ||
330 | if (!tmp) | ||
331 | tmp = getenv ("LANG"); | ||
332 | |||
333 | if (tmp) | ||
334 | { | ||
335 | char *sp = NULL; | ||
336 | char *lang; | ||
337 | char *terr; | ||
338 | |||
339 | strncpy (locale, tmp, sizeof (locale) - 1); | ||
340 | |||
341 | lang = strtok_r (locale, "_", &sp); | ||
342 | terr = strtok_r (NULL, ".", &sp); | ||
343 | output_charset = strtok_r (NULL, "@", &sp); | ||
344 | |||
345 | if (output_charset) | ||
346 | output_charset = xstrdup (output_charset); | ||
347 | else | ||
348 | output_charset = mu_charset_lookup (lang, terr); | ||
349 | |||
350 | if (!output_charset) | ||
351 | output_charset = "ASCII"; | ||
352 | } | ||
353 | } | ||
354 | return output_charset; | ||
355 | } | ||
356 | |||
357 | |||
358 | /* BIDI support (will be moved to lib when it's ready) */ | ||
359 | #ifdef HAVE_LIBFRIBIDI | ||
360 | |||
361 | static int fb_charset_num = -1; | ||
362 | FriBidiChar *logical; | ||
363 | char *outstring; | ||
364 | size_t logical_size; | ||
365 | |||
366 | void | ||
367 | alloc_logical (size_t size) | ||
368 | { | ||
369 | logical = xmalloc (size * sizeof (logical[0])); | ||
370 | logical_size = size; | ||
371 | outstring = xmalloc (size); | ||
372 | } | ||
373 | |||
374 | void | ||
375 | puts_bidi (char *string) | ||
376 | { | ||
377 | if (fb_charset_num == -1) | ||
378 | { | ||
379 | fb_charset_num = fribidi_parse_charset (get_charset ()); | ||
380 | if (fb_charset_num && dbug) | ||
381 | mu_error (_("fribidi failed to recognize charset `%s'"), | ||
382 | get_charset ()); | ||
383 | } | ||
384 | |||
385 | if (fb_charset_num == 0) | ||
386 | puts (string); | ||
387 | else | ||
388 | { | ||
389 | FriBidiStrIndex len; | ||
390 | FriBidiCharType base = FRIBIDI_TYPE_ON; | ||
391 | fribidi_boolean log2vis; | ||
392 | |||
393 | static FriBidiChar *visual; | ||
394 | static size_t visual_size; | ||
395 | |||
396 | |||
397 | len = fribidi_charset_to_unicode (fb_charset_num, | ||
398 | string, strlen (string), | ||
399 | logical); | ||
400 | |||
401 | if (len + 1 > visual_size) | ||
402 | { | ||
403 | visual_size = len + 1; | ||
404 | visual = xrealloc (visual, visual_size * sizeof *visual); | ||
405 | } | ||
406 | |||
407 | /* Create a bidi string. */ | ||
408 | log2vis = fribidi_log2vis (logical, len, &base, | ||
409 | /* output */ | ||
410 | visual, NULL, NULL, NULL); | ||
411 | |||
412 | if (log2vis) | ||
413 | { | ||
414 | FriBidiStrIndex idx, st; | ||