summarylogtreecommitdiffstats
path: root/sidebar-utf8.patch
blob: d67e43c24b6eda1da9f2b71f33419fa03db186f2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
From: Antonio Radici <antonio@debian.org>
Date: Tue, 4 Mar 2014 15:39:14 +0100
Subject: sidebar-utf8

This patch fixes a problem with utf-8 strings and the sidebar,
it rewrites entirely make_sidebar_entry so it also fixes some
segfaults due to misallocations and overflows.

See:
 http://bugs.debian.org/584581
 http://bugs.debian.org/603287

Gbp-Pq: Topic mutt-patched
---
 sidebar.c | 97 +++++++++++++++++++++++++++++++++++++++++++--------------------
 1 file changed, 67 insertions(+), 30 deletions(-)

diff --git a/sidebar.c b/sidebar.c
index 4356ffc..8f58f85 100644
--- a/sidebar.c
+++ b/sidebar.c
@@ -30,6 +30,7 @@
 #include <libgen.h>
 #include "keymap.h"
 #include <stdbool.h>
+#include <wchar.h>
 
 /*BUFFY *CurBuffy = 0;*/
 static BUFFY *TopBuffy = 0;
@@ -82,36 +83,72 @@ void calc_boundaries (int menu)
 
 char *make_sidebar_entry(char *box, int size, int new, int flagged)
 {
-	static char *entry = 0;
-	char *c;
-	int i = 0;
-	int delim_len = strlen(SidebarDelim);
-
-	c = realloc(entry, SidebarWidth - delim_len + 2);
-	if ( c ) entry = c;
-	entry[SidebarWidth - delim_len + 1] = 0;
-	for (; i < SidebarWidth - delim_len + 1; entry[i++] = ' ' );
-	i = strlen(box);
-	strncpy( entry, box, i < (SidebarWidth - delim_len + 1) ? i : (SidebarWidth - delim_len + 1) );
-
-        if (size == -1)
-                sprintf(entry + SidebarWidth - delim_len - 3, "?");
-        else if ( new ) {
-          if (flagged > 0) {
-              sprintf(
-		        entry + SidebarWidth - delim_len - 5 - quick_log10(size) - quick_log10(new) - quick_log10(flagged),
-		        "% d(%d)[%d]", size, new, flagged);
-          } else {
-              sprintf(
-                      entry + SidebarWidth - delim_len - 3 - quick_log10(size) - quick_log10(new),
-                      "% d(%d)", size, new);
-          }
-        } else if (flagged > 0) {
-              sprintf( entry + SidebarWidth - delim_len - 3 - quick_log10(size) - quick_log10(flagged), "% d[%d]", size, flagged);
-        } else {
-              sprintf( entry + SidebarWidth - delim_len - 1 - quick_log10(size), "% d", size);
-        }
-	return entry;
+    char int_store[20]; // up to 64 bits integers
+    int right_width, left_width;
+    int box_len, box_bytes;
+    int int_len;
+    int right_offset = 0;
+    int delim_len = strlen(SidebarDelim);
+    static char *entry;
+
+    right_width = left_width = 0;
+    box_len = box_bytes = 0;
+
+    // allocate an entry big enough to contain SidebarWidth wide chars
+    entry = malloc((SidebarWidth*4)+1); // TODO: error check
+
+    // determine the right space (i.e.: how big are the numbers that we want to print)
+    if ( size > 0 ) {
+        int_len = snprintf(int_store, sizeof(int_store), "%d", size);
+        right_width += int_len;
+    } else {
+        right_width = 1; // to represent 0
+    }
+    if ( new > 0 ) {
+        int_len = snprintf(int_store, sizeof(int_store), "%d", new);
+        right_width += int_len + 2; // 2 is for ()
+    }
+    if ( flagged > 0 ) {
+        int_len = snprintf(int_store, sizeof(int_store), "%d", flagged);
+        right_width += int_len + 2; // 2 is for []
+    }
+
+    // determine how much space we have for *box and its padding (if any)
+    left_width = SidebarWidth - right_width - 1 - delim_len; // 1 is for the space
+    //fprintf(stdout, "left_width: %d right_width: %d\n", left_width, right_width);
+    // right side overflow case
+    if ( left_width <= 0 ) {
+        snprintf(entry, SidebarWidth*4, "%-*.*s ...", SidebarWidth-4-delim_len, SidebarWidth-4-delim_len, box);
+        return entry;
+    }
+    right_width -= delim_len;
+
+    // to support utf-8 chars we need to add enough space padding in case there
+    // are less chars than bytes in *box
+    box_len = mbstowcs(NULL, box, 0);
+    box_bytes = strlen(box);
+    // debug
+    //fprintf(stdout, "box_len: %d box_bytes: %d (diff: %d)\n", box_len, box_bytes, (box_bytes-box_len));
+    // if there is less string than the space we allow, then we will add the
+    // spaces
+    if ( box_len != -1 && box_len < left_width ) {
+        left_width += (box_bytes - box_len);
+    }
+    // otherwise sprintf will truncate the string for us (therefore, no else case)
+
+    // print the sidebar entry (without new and flagged messages, at the moment)
+    //fprintf(stdout, "left_width: %d right_width: %d\n", left_width, right_width);
+    right_offset = snprintf(entry, SidebarWidth*4, "%-*.*s %d", left_width, left_width, box, size);
+
+    // then pad new and flagged messages if any
+    if ( new > 0 ) {
+        right_offset += snprintf(entry+right_offset, SidebarWidth*4-right_offset, "(%d)", new);
+    }
+    if ( flagged > 0 ) {
+        right_offset += snprintf(entry+right_offset, SidebarWidth*4-right_offset, "[%d]", flagged);
+    }
+
+    return entry;
 }
 
 void set_curbuffy(char buf[LONG_STRING])