NeoMutt  2021-10-22-8-g9cb437
Teaching an old dog new tricks
DOXYGEN
enriched.c File Reference

Rich text handler. More...

#include "config.h"
#include <stddef.h>
#include <stdbool.h>
#include <stdio.h>
#include <wchar.h>
#include <wctype.h>
#include "mutt/lib.h"
#include "email/lib.h"
#include "enriched.h"
+ Include dependency graph for enriched.c:

Go to the source code of this file.

Data Structures

struct  Etags
 Enriched text tags. More...
 
struct  EnrichedState
 State of enriched-text parser. More...
 

Macros

#define INDENT_SIZE   4
 A (not so) minimal implementation of RFC1563. More...
 

Enumerations

enum  RichAttribs {
  RICH_PARAM = 0 , RICH_BOLD , RICH_UNDERLINE , RICH_ITALIC ,
  RICH_NOFILL , RICH_INDENT , RICH_INDENT_RIGHT , RICH_EXCERPT ,
  RICH_CENTER , RICH_FLUSHLEFT , RICH_FLUSHRIGHT , RICH_COLOR ,
  RICH_MAX
}
 Rich text attributes. More...
 

Functions

static void enriched_wrap (struct EnrichedState *stte)
 Wrap enriched text. More...
 
static void enriched_flush (struct EnrichedState *stte, bool wrap)
 Write enriched text to the State. More...
 
static void enriched_putwc (wchar_t c, struct EnrichedState *stte)
 Write one wide character to the state. More...
 
static void enriched_puts (const char *s, struct EnrichedState *stte)
 Write an enriched text string to the State. More...
 
static void enriched_set_flags (const wchar_t *tag, struct EnrichedState *stte)
 Set flags on the enriched text state. More...
 
int text_enriched_handler (struct Body *a, struct State *s)
 Handler for enriched text - Implements handler_t -. More...
 

Variables

static const struct Etags EnrichedTags []
 

Detailed Description

Rich text handler.

Authors
  • Richard Russon

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file enriched.c.

Macro Definition Documentation

◆ INDENT_SIZE

#define INDENT_SIZE   4

A (not so) minimal implementation of RFC1563.

Definition at line 43 of file enriched.c.

Enumeration Type Documentation

◆ RichAttribs

Rich text attributes.

Enumerator
RICH_PARAM 

Parameter label.

RICH_BOLD 

Bold text.

RICH_UNDERLINE 

Underlined text.

RICH_ITALIC 

Italic text.

RICH_NOFILL 

Text will not be reformatted.

RICH_INDENT 

Indented text.

RICH_INDENT_RIGHT 

Right-indented text.

RICH_EXCERPT 

Excerpt text.

RICH_CENTER 

Centred text.

RICH_FLUSHLEFT 

Left-justified text.

RICH_FLUSHRIGHT 

Right-justified text.

RICH_COLOR 

Coloured text.

RICH_MAX 

Definition at line 48 of file enriched.c.

49 {
50  RICH_PARAM = 0,
51  RICH_BOLD,
53  RICH_ITALIC,
54  RICH_NOFILL,
55  RICH_INDENT,
57  RICH_EXCERPT,
58  RICH_CENTER,
61  RICH_COLOR,
62  RICH_MAX,
63 };
@ RICH_FLUSHRIGHT
Right-justified text.
Definition: enriched.c:60
@ RICH_NOFILL
Text will not be reformatted.
Definition: enriched.c:54
@ RICH_COLOR
Coloured text.
Definition: enriched.c:61
@ RICH_PARAM
Parameter label.
Definition: enriched.c:50
@ RICH_INDENT
Indented text.
Definition: enriched.c:55
@ RICH_BOLD
Bold text.
Definition: enriched.c:51
@ RICH_CENTER
Centred text.
Definition: enriched.c:58
@ RICH_ITALIC
Italic text.
Definition: enriched.c:53
@ RICH_UNDERLINE
Underlined text.
Definition: enriched.c:52
@ RICH_EXCERPT
Excerpt text.
Definition: enriched.c:57
@ RICH_INDENT_RIGHT
Right-indented text.
Definition: enriched.c:56
@ RICH_MAX
Definition: enriched.c:62
@ RICH_FLUSHLEFT
Left-justified text.
Definition: enriched.c:59

Function Documentation

◆ enriched_wrap()

static void enriched_wrap ( struct EnrichedState stte)
static

Wrap enriched text.

Parameters
stteState of enriched text

Definition at line 120 of file enriched.c.

121 {
122  if (!stte)
123  return;
124 
125  int x;
126 
127  if (stte->line_len)
128  {
129  if (stte->tag_level[RICH_CENTER] || stte->tag_level[RICH_FLUSHRIGHT])
130  {
131  /* Strip trailing white space */
132  size_t y = stte->line_used - 1;
133 
134  while (y && iswspace(stte->line[y]))
135  {
136  stte->line[y] = (wchar_t) '\0';
137  y--;
138  stte->line_used--;
139  stte->line_len--;
140  }
141  if (stte->tag_level[RICH_CENTER])
142  {
143  /* Strip leading whitespace */
144  y = 0;
145 
146  while (stte->line[y] && iswspace(stte->line[y]))
147  y++;
148  if (y)
149  {
150  for (size_t z = y; z <= stte->line_used; z++)
151  {
152  stte->line[z - y] = stte->line[z];
153  }
154 
155  stte->line_len -= y;
156  stte->line_used -= y;
157  }
158  }
159  }
160 
161  const int extra = stte->wrap_margin - stte->line_len - stte->indent_len -
163  if (extra > 0)
164  {
165  if (stte->tag_level[RICH_CENTER])
166  {
167  x = extra / 2;
168  while (x)
169  {
170  state_putc(stte->s, ' ');
171  x--;
172  }
173  }
174  else if (stte->tag_level[RICH_FLUSHRIGHT])
175  {
176  x = extra - 1;
177  while (x)
178  {
179  state_putc(stte->s, ' ');
180  x--;
181  }
182  }
183  }
184  state_putws(stte->s, (const wchar_t *) stte->line);
185  }
186 
187  state_putc(stte->s, '\n');
188  stte->line[0] = (wchar_t) '\0';
189  stte->line_len = 0;
190  stte->line_used = 0;
191  stte->indent_len = 0;
192  if (stte->s->prefix)
193  {
194  state_puts(stte->s, stte->s->prefix);
195  stte->indent_len += mutt_str_len(stte->s->prefix);
196  }
197 
198  if (stte->tag_level[RICH_EXCERPT])
199  {
200  x = stte->tag_level[RICH_EXCERPT];
201  while (x)
202  {
203  if (stte->s->prefix)
204  {
205  state_puts(stte->s, stte->s->prefix);
206  stte->indent_len += mutt_str_len(stte->s->prefix);
207  }
208  else
209  {
210  state_puts(stte->s, "> ");
211  stte->indent_len += mutt_str_len("> ");
212  }
213  x--;
214  }
215  }
216  else
217  stte->indent_len = 0;
218  if (stte->tag_level[RICH_INDENT])
219  {
220  x = stte->tag_level[RICH_INDENT] * INDENT_SIZE;
221  stte->indent_len += x;
222  while (x)
223  {
224  state_putc(stte->s, ' ');
225  x--;
226  }
227  }
228 }
#define INDENT_SIZE
A (not so) minimal implementation of RFC1563.
Definition: enriched.c:43
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:664
int state_putws(struct State *s, const wchar_t *ws)
Write a wide string to the state.
Definition: state.c:145
#define state_puts(STATE, STR)
Definition: state.h:55
#define state_putc(STATE, STR)
Definition: state.h:56
wchar_t * line
Definition: enriched.c:100
int tag_level[RICH_MAX]
Definition: enriched.c:111
struct State * s
Definition: enriched.c:113
size_t line_used
Definition: enriched.c:104
size_t line_len
Definition: enriched.c:103
int wrap_margin
Definition: enriched.c:112
size_t indent_len
Definition: enriched.c:106
char * prefix
String to add to the beginning of each output line.
Definition: state.h:48
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ enriched_flush()

static void enriched_flush ( struct EnrichedState stte,
bool  wrap 
)
static

Write enriched text to the State.

Parameters
stteState of Enriched text
wraptrue if the text should be wrapped

Definition at line 235 of file enriched.c.

236 {
237  if (!stte || !stte->buffer)
238  return;
239 
240  if (!stte->tag_level[RICH_NOFILL] &&
241  ((stte->line_len + stte->word_len) >
242  (stte->wrap_margin - (stte->tag_level[RICH_INDENT_RIGHT] * INDENT_SIZE) - stte->indent_len)))
243  {
244  enriched_wrap(stte);
245  }
246 
247  if (stte->buf_used)
248  {
249  stte->buffer[stte->buf_used] = (wchar_t) '\0';
250  stte->line_used += stte->buf_used;
251  if (stte->line_used > stte->line_max)
252  {
253  stte->line_max = stte->line_used;
254  mutt_mem_realloc(&stte->line, (stte->line_max + 1) * sizeof(wchar_t));
255  }
256  wcscat(stte->line, stte->buffer);
257  stte->line_len += stte->word_len;
258  stte->word_len = 0;
259  stte->buf_used = 0;
260  }
261  if (wrap)
262  enriched_wrap(stte);
263  fflush(stte->s->fp_out);
264 }
static void enriched_wrap(struct EnrichedState *stte)
Wrap enriched text.
Definition: enriched.c:120
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
wchar_t * buffer
Definition: enriched.c:99
size_t buf_used
Definition: enriched.c:108
size_t word_len
Definition: enriched.c:107
size_t line_max
Definition: enriched.c:105
FILE * fp_out
File to write to.
Definition: state.h:47
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ enriched_putwc()

static void enriched_putwc ( wchar_t  c,
struct EnrichedState stte 
)
static

Write one wide character to the state.

Parameters
cCharacter to write
stteState of Enriched text

Definition at line 271 of file enriched.c.

272 {
273  if (!stte)
274  return;
275 
276  if (stte->tag_level[RICH_PARAM])
277  {
278  if (stte->tag_level[RICH_COLOR])
279  {
280  if (stte->param_used + 1 >= stte->param_len)
281  mutt_mem_realloc(&stte->param, (stte->param_len += 256) * sizeof(wchar_t));
282 
283  stte->param[stte->param_used++] = c;
284  }
285  return; /* nothing to do */
286  }
287 
288  /* see if more space is needed (plus extra for possible rich characters) */
289  if ((stte->buf_len < (stte->buf_used + 3)) || !stte->buffer)
290  {
291  stte->buf_len += 1024;
292  mutt_mem_realloc(&stte->buffer, (stte->buf_len + 1) * sizeof(wchar_t));
293  }
294 
295  if ((!stte->tag_level[RICH_NOFILL] && iswspace(c)) || (c == (wchar_t) '\0'))
296  {
297  if (c == (wchar_t) '\t')
298  stte->word_len += 8 - (stte->line_len + stte->word_len) % 8;
299  else
300  stte->word_len++;
301 
302  stte->buffer[stte->buf_used++] = c;
303  enriched_flush(stte, false);
304  }
305  else
306  {
307  if (stte->s->flags & MUTT_DISPLAY)
308  {
309  if (stte->tag_level[RICH_BOLD])
310  {
311  stte->buffer[stte->buf_used++] = c;
312  stte->buffer[stte->buf_used++] = (wchar_t) '\010'; // Ctrl-H (backspace)
313  stte->buffer[stte->buf_used++] = c;
314  }
315  else if (stte->tag_level[RICH_UNDERLINE])
316  {
317  stte->buffer[stte->buf_used++] = '_';
318  stte->buffer[stte->buf_used++] = (wchar_t) '\010'; // Ctrl-H (backspace)
319  stte->buffer[stte->buf_used++] = c;
320  }
321  else if (stte->tag_level[RICH_ITALIC])
322  {
323  stte->buffer[stte->buf_used++] = c;
324  stte->buffer[stte->buf_used++] = (wchar_t) '\010'; // Ctrl-H (backspace)
325  stte->buffer[stte->buf_used++] = '_';
326  }
327  else
328  {
329  stte->buffer[stte->buf_used++] = c;
330  }
331  }
332  else
333  {
334  stte->buffer[stte->buf_used++] = c;
335  }
336  stte->word_len++;
337  }
338 }
static void enriched_flush(struct EnrichedState *stte, bool wrap)
Write enriched text to the State.
Definition: enriched.c:235
#define MUTT_DISPLAY
Output is displayed to the user.
Definition: state.h:32
size_t buf_len
Definition: enriched.c:102
size_t param_used
Definition: enriched.c:109
wchar_t * param
Definition: enriched.c:101
size_t param_len
Definition: enriched.c:110
StateFlags flags
Flags, e.g. MUTT_DISPLAY.
Definition: state.h:49
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ enriched_puts()

static void enriched_puts ( const char *  s,
struct EnrichedState stte 
)
static

Write an enriched text string to the State.

Parameters
sString to write
stteState of Enriched text

Definition at line 345 of file enriched.c.

346 {
347  if (!stte)
348  return;
349 
350  const char *c = NULL;
351 
352  if ((stte->buf_len < (stte->buf_used + mutt_str_len(s))) || !stte->buffer)
353  {
354  stte->buf_len += 1024;
355  mutt_mem_realloc(&stte->buffer, (stte->buf_len + 1) * sizeof(wchar_t));
356  }
357  c = s;
358  while (*c)
359  {
360  stte->buffer[stte->buf_used++] = (wchar_t) *c;
361  c++;
362  }
363 }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ enriched_set_flags()

static void enriched_set_flags ( const wchar_t *  tag,
struct EnrichedState stte 
)
static

Set flags on the enriched text state.

Parameters
tagTag to set
stteState of Enriched text

Definition at line 370 of file enriched.c.

371 {
372  if (!stte)
373  return;
374 
375  const wchar_t *tagptr = tag;
376  int i, j;
377 
378  if (*tagptr == (wchar_t) '/')
379  tagptr++;
380 
381  for (i = 0, j = -1; EnrichedTags[i].tag_name; i++)
382  {
383  if (wcscasecmp(EnrichedTags[i].tag_name, tagptr) == 0)
384  {
385  j = EnrichedTags[i].index;
386  break;
387  }
388  }
389 
390  if (j != -1)
391  {
392  if ((j == RICH_CENTER) || (j == RICH_FLUSHLEFT) || (j == RICH_FLUSHRIGHT))
393  enriched_flush(stte, true);
394 
395  if (*tag == (wchar_t) '/')
396  {
397  if (stte->tag_level[j]) /* make sure not to go negative */
398  stte->tag_level[j]--;
399  if ((stte->s->flags & MUTT_DISPLAY) && (j == RICH_PARAM) && stte->tag_level[RICH_COLOR])
400  {
401  stte->param[stte->param_used] = (wchar_t) '\0';
402  if (wcscasecmp(L"black", stte->param) == 0)
403  {
404  enriched_puts("\033[30m", stte); // Escape
405  }
406  else if (wcscasecmp(L"red", stte->param) == 0)
407  {
408  enriched_puts("\033[31m", stte); // Escape
409  }
410  else if (wcscasecmp(L"green", stte->param) == 0)
411  {
412  enriched_puts("\033[32m", stte); // Escape
413  }
414  else if (wcscasecmp(L"yellow", stte->param) == 0)
415  {
416  enriched_puts("\033[33m", stte); // Escape
417  }
418  else if (wcscasecmp(L"blue", stte->param) == 0)
419  {
420  enriched_puts("\033[34m", stte); // Escape
421  }
422  else if (wcscasecmp(L"magenta", stte->param) == 0)
423  {
424  enriched_puts("\033[35m", stte); // Escape
425  }
426  else if (wcscasecmp(L"cyan", stte->param) == 0)
427  {
428  enriched_puts("\033[36m", stte); // Escape
429  }
430  else if (wcscasecmp(L"white", stte->param) == 0)
431  {
432  enriched_puts("\033[37m", stte); // Escape
433  }
434  }
435  if ((stte->s->flags & MUTT_DISPLAY) && (j == RICH_COLOR))
436  {
437  enriched_puts("\033[0m", stte); // Escape
438  }
439 
440  /* flush parameter buffer when closing the tag */
441  if (j == RICH_PARAM)
442  {
443  stte->param_used = 0;
444  stte->param[0] = (wchar_t) '\0';
445  }
446  }
447  else
448  stte->tag_level[j]++;
449 
450  if (j == RICH_EXCERPT)
451  enriched_flush(stte, true);
452  }
453 }
static const struct Etags EnrichedTags[]
Definition: enriched.c:74
static void enriched_puts(const char *s, struct EnrichedState *stte)
Write an enriched text string to the State.
Definition: enriched.c:345
int wcscasecmp(const wchar_t *a, const wchar_t *b)
Compare two wide-character strings, ignoring case.
Definition: wcscasecmp.c:41
int index
Index number.
Definition: enriched.c:71
const wchar_t * tag_name
Tag name.
Definition: enriched.c:70
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ EnrichedTags

const struct Etags EnrichedTags[]
static
Initial value:
= {
{ L"param", RICH_PARAM },
{ L"bold", RICH_BOLD },
{ L"italic", RICH_ITALIC },
{ L"underline", RICH_UNDERLINE },
{ L"nofill", RICH_NOFILL },
{ L"excerpt", RICH_EXCERPT },
{ L"indent", RICH_INDENT },
{ L"indentright", RICH_INDENT_RIGHT },
{ L"center", RICH_CENTER },
{ L"flushleft", RICH_FLUSHLEFT },
{ L"flushright", RICH_FLUSHRIGHT },
{ L"flushboth", RICH_FLUSHLEFT },
{ L"color", RICH_COLOR },
{ L"x-color", RICH_COLOR },
{ NULL, -1 },
}

Definition at line 1 of file enriched.c.