summaryrefslogtreecommitdiff
path: root/frm/common.c
diff options
context:
space:
mode:
Diffstat (limited to 'frm/common.c')
-rw-r--r--frm/common.c599
1 files changed, 599 insertions, 0 deletions
diff --git a/frm/common.c b/frm/common.c
new file mode 100644
index 000000000..bc6ad1a3a
--- /dev/null
+++ b/frm/common.c
@@ -0,0 +1,599 @@
1/* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999, 2000, 2001, 2002, 2003,
3 2004, 2005 Free Software Foundation, Inc.
4
5 GNU Mailutils is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
8 any later version.
9
10 GNU Mailutils is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNU Mailutils; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
18
19#include <frm.h>
20
21char *show_field; /* Show this header field instead of the default
22 `From: Subject:' pair. -f option */
23int show_to; /* Additionally display To: field. -l option */
24int show_number; /* Prefix each line with the message number. -n */
25int frm_debug;
26
27
28
29/* Get the number of columns on the screen
30 First try an ioctl() call, not all shells set the COLUMNS environ.
31 If ioctl does not succeed on stdout, try it on /dev/tty, as we
32 may work via a pipe.
33
34 This function was taken from mail/util.c. It should probably reside
35 in the library */
36int
37util_getcols (void)
38{
39 struct winsize ws;
40
41 ws.ws_col = ws.ws_row = 0;
42 if (ioctl (1, TIOCGWINSZ, (char *) &ws) < 0)
43 {
44 int fd = open ("/dev/tty", O_RDWR);
45 ioctl (fd, TIOCGWINSZ, (char *) &ws);
46 close (fd);
47 }
48 if (ws.ws_row == 0)
49 {
50 const char *columns = getenv ("COLUMNS");
51 if (columns)
52 ws.ws_col = strtol (columns, NULL, 10);
53 }
54 return ws.ws_col;
55}
56
57
58/* Charset magic */
59static char *output_charset = NULL;
60
61const char *
62get_charset ()
63{
64 char *tmp;
65
66 if (!output_charset)
67 {
68 char locale[32];
69
70 memset (locale, 0, sizeof (locale));
71
72 /* Try to deduce the charset from LC_ALL or LANG variables */
73
74 tmp = getenv ("LC_ALL");
75 if (!tmp)
76 tmp = getenv ("LANG");
77
78 if (tmp)
79 {
80 char *sp = NULL;
81 char *lang;
82 char *terr;
83
84 strncpy (locale, tmp, sizeof (locale) - 1);
85
86 lang = strtok_r (locale, "_", &sp);
87 terr = strtok_r (NULL, ".", &sp);
88 output_charset = strtok_r (NULL, "@", &sp);
89
90 if (output_charset)
91 output_charset = xstrdup (output_charset);
92 else
93 output_charset = mu_charset_lookup (lang, terr);
94
95 if (!output_charset)
96 output_charset = "ASCII";
97 }
98 }
99 return output_charset;
100}
101
102
103/* BIDI support (will be moved to lib when it's ready) */
104#ifdef HAVE_LIBFRIBIDI
105
106static int fb_charset_num = -1;
107FriBidiChar *logical;
108char *outstring;
109size_t logical_size;
110
111void
112alloc_logical (size_t size)
113{
114 logical = xmalloc (size * sizeof (logical[0]));
115 logical_size = size;
116 outstring = xmalloc (size);
117}
118
119void
120puts_bidi (char *string)
121{
122 if (fb_charset_num == -1)
123 {
124 fb_charset_num = fribidi_parse_charset (get_charset ());
125 if (fb_charset_num && frm_debug)
126 mu_error (_("fribidi failed to recognize charset `%s'"),
127 get_charset ());
128 }
129
130 if (fb_charset_num == 0)
131 puts (string);
132 else
133 {
134 FriBidiStrIndex len;
135 FriBidiCharType base = FRIBIDI_TYPE_ON;
136 fribidi_boolean log2vis;
137
138 static FriBidiChar *visual;
139 static size_t visual_size;
140
141
142 len = fribidi_charset_to_unicode (fb_charset_num,
143 string, strlen (string),
144 logical);
145
146 if (len + 1 > visual_size)
147 {
148 visual_size = len + 1;
149 visual = xrealloc (visual, visual_size * sizeof *visual);
150 }
151
152 /* Create a bidi string. */
153 log2vis = fribidi_log2vis (logical, len, &base,
154 /* output */
155 visual, NULL, NULL, NULL);
156
157 if (log2vis)
158 {
159 FriBidiStrIndex idx, st;
160 FriBidiStrIndex new_len;
161
162 for (idx = 0; idx < len;)
163 {
164 FriBidiStrIndex wid, inlen;
165
166 wid = 3 * logical_size;
167 st = idx;
168
169 if (fb_charset_num != FRIBIDI_CHARSET_CAP_RTL)
170 {
171 while (wid > 0 && idx < len)
172 wid -= fribidi_wcwidth (visual[idx++]);
173 }
174 else
175 {
176 while (wid > 0 && idx < len)
177 {
178 wid--;
179 idx++;
180 }
181 }
182
183 if (wid < 0 && idx > st + 1)
184 idx--;
185 inlen = idx - st;
186
187 new_len = fribidi_unicode_to_charset (fb_charset_num,
188 visual + st, inlen,
189 outstring);
190 printf ("%s", outstring);
191 }
192 putchar ('\n');
193 }
194 else
195 {
196 /* Print the string as is */
197 puts (string);
198 }
199 }
200}
201#else
202# define alloc_logical(s)
203# define puts_bidi puts
204#endif
205
206
207/* Output functions */
208
209/* Number of columns in output:
210
211 Maximum 4 message number, to, from, subject -ln
212 Default 2 from, subject [none]
213 Minimum 1 FIELD -f FIELD
214*/
215
216static int numfields; /* Number of output fields */
217static int fieldwidth[4]; /* Field start positions */
218static char *linebuf; /* Output line buffer */
219static size_t linemax; /* Size of linebuf */
220static size_t linepos; /* Position in the output line buffer */
221static int curfield; /* Current output field */
222static int nextstart; /* Start position of the next field */
223static int curcol; /* Current output column */
224
225typedef void (*fmt_formatter) (const char *fmt, ...);
226
227static fmt_formatter format_field;
228
229void
230print_line ()
231{
232 if (linebuf)
233 {
234 puts_bidi (linebuf);
235 linebuf[0] = 0;
236 linepos = 0;
237 curcol = nextstart = 0;
238 }
239 else
240 putchar ('\n');
241 curfield = 0;
242}
243
244void
245format_field_simple (const char *fmt, ...)
246{
247 va_list ap;
248 if (curfield++)
249 putchar ('\t');</