You can subscribe to this list here.
| 2004 |
Jan
(123) |
Feb
(24) |
Mar
(11) |
Apr
(7) |
May
(6) |
Jun
(6) |
Jul
(1) |
Aug
(1) |
Sep
(35) |
Oct
(24) |
Nov
(3) |
Dec
(5) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2005 |
Jan
(2) |
Feb
(6) |
Mar
(13) |
Apr
(17) |
May
(3) |
Jun
(11) |
Jul
(12) |
Aug
(4) |
Sep
(4) |
Oct
(4) |
Nov
|
Dec
(28) |
| 2006 |
Jan
(35) |
Feb
(21) |
Mar
(23) |
Apr
|
May
(16) |
Jun
(2) |
Jul
(8) |
Aug
(27) |
Sep
(2) |
Oct
(12) |
Nov
(22) |
Dec
(6) |
| 2007 |
Jan
(7) |
Feb
(4) |
Mar
|
Apr
(5) |
May
|
Jun
(2) |
Jul
|
Aug
|
Sep
(6) |
Oct
|
Nov
|
Dec
(1) |
| 2008 |
Jan
|
Feb
(11) |
Mar
(2) |
Apr
(14) |
May
|
Jun
|
Jul
(2) |
Aug
(11) |
Sep
(2) |
Oct
(5) |
Nov
|
Dec
|
| 2009 |
Jan
(1) |
Feb
(5) |
Mar
(2) |
Apr
|
May
(3) |
Jun
|
Jul
(5) |
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
| 2010 |
Jan
(2) |
Feb
(32) |
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
(6) |
Oct
(14) |
Nov
(4) |
Dec
(1) |
| 2011 |
Jan
(8) |
Feb
|
Mar
(41) |
Apr
(42) |
May
|
Jun
(1) |
Jul
(4) |
Aug
(1) |
Sep
|
Oct
|
Nov
(1) |
Dec
|
| 2012 |
Jan
|
Feb
(4) |
Mar
(5) |
Apr
(10) |
May
(2) |
Jun
(2) |
Jul
(15) |
Aug
(8) |
Sep
(101) |
Oct
(35) |
Nov
(17) |
Dec
(6) |
| 2013 |
Jan
(19) |
Feb
(18) |
Mar
(18) |
Apr
(67) |
May
(17) |
Jun
(4) |
Jul
(21) |
Aug
(10) |
Sep
(33) |
Oct
(33) |
Nov
(97) |
Dec
(81) |
| 2014 |
Jan
(39) |
Feb
(30) |
Mar
(10) |
Apr
(34) |
May
(7) |
Jun
(27) |
Jul
(33) |
Aug
(24) |
Sep
(9) |
Oct
(52) |
Nov
(23) |
Dec
(24) |
| 2015 |
Jan
(55) |
Feb
(51) |
Mar
(39) |
Apr
(74) |
May
(63) |
Jun
(33) |
Jul
(19) |
Aug
(21) |
Sep
(28) |
Oct
(11) |
Nov
(25) |
Dec
(26) |
| 2016 |
Jan
(39) |
Feb
(19) |
Mar
(36) |
Apr
(8) |
May
(3) |
Jun
(18) |
Jul
(20) |
Aug
(30) |
Sep
(12) |
Oct
(33) |
Nov
(145) |
Dec
(52) |
| 2017 |
Jan
(22) |
Feb
(43) |
Mar
(44) |
Apr
(71) |
May
(14) |
Jun
(10) |
Jul
(7) |
Aug
(30) |
Sep
(10) |
Oct
(39) |
Nov
(7) |
Dec
|
| 2018 |
Jan
(17) |
Feb
(21) |
Mar
(10) |
Apr
(19) |
May
(8) |
Jun
(9) |
Jul
(12) |
Aug
(3) |
Sep
(17) |
Oct
(9) |
Nov
(14) |
Dec
|
| 2019 |
Jan
(10) |
Feb
(6) |
Mar
(17) |
Apr
(2) |
May
(15) |
Jun
(15) |
Jul
(43) |
Aug
(12) |
Sep
(21) |
Oct
(7) |
Nov
(35) |
Dec
(5) |
| 2020 |
Jan
(110) |
Feb
(19) |
Mar
(12) |
Apr
(7) |
May
(22) |
Jun
(20) |
Jul
(48) |
Aug
(112) |
Sep
(12) |
Oct
(5) |
Nov
(19) |
Dec
(4) |
| 2021 |
Jan
(22) |
Feb
(54) |
Mar
(39) |
Apr
(5) |
May
(5) |
Jun
(36) |
Jul
(23) |
Aug
(31) |
Sep
(29) |
Oct
(2) |
Nov
(63) |
Dec
(50) |
| 2022 |
Jan
(23) |
Feb
(15) |
Mar
(3) |
Apr
(15) |
May
(21) |
Jun
(262) |
Jul
(59) |
Aug
(24) |
Sep
(18) |
Oct
(8) |
Nov
(23) |
Dec
(24) |
| 2023 |
Jan
(13) |
Feb
(3) |
Mar
(24) |
Apr
(3) |
May
(6) |
Jun
(13) |
Jul
(9) |
Aug
(32) |
Sep
(4) |
Oct
(2) |
Nov
(11) |
Dec
|
| 2024 |
Jan
(23) |
Feb
(15) |
Mar
(16) |
Apr
(17) |
May
(2) |
Jun
(5) |
Jul
(34) |
Aug
(48) |
Sep
(24) |
Oct
(12) |
Nov
(43) |
Dec
(34) |
| 2025 |
Jan
(7) |
Feb
(1) |
Mar
(30) |
Apr
(4) |
May
|
Jun
(5) |
Jul
(25) |
Aug
(1) |
Sep
(7) |
Oct
(7) |
Nov
(19) |
Dec
(11) |
| 2026 |
Jan
(10) |
Feb
(2) |
Mar
(5) |
Apr
(40) |
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
|
From: Oswald B. <osw...@gm...> - 2026-04-17 07:22:22
|
On Fri, Apr 17, 2026 at 12:38:31AM +0300, Evgeniy Berdnikov wrote: > I can't imagine compiler generating different memory addresses for > such members. > that's not the issue. if the compiler decides that it's undefined behavior, it might do literally anything - usually it will just drop possibly large chunks of code. this has been increasingly happening over the last years as compilers are optimizing more and more aggressively. the "i can't imagine a compiler would do something so obviously developer-hostile" argument is wishful thinking. |
|
From: Evgeniy B. <bi...@pr...> - 2026-04-16 21:38:59
|
Hi, Michal. On Thu, Apr 16, 2026 at 03:16:26PM +0200, Michal SuchАnek wrote: > On Thu, Apr 16, 2026 at 08:03:30PM +1000, Seth McDonald wrote: > > | A pointer to void shall have the same representation and alignment > > | requirements as a pointer to a character type. Similarly, pointers to > > | qualified or unqualified versions of compatible types shall have the > > | same representation and alignment requirements. > > > > So the conversion from const void* to void*, and from void* to char*, is > > not undefined behaviour. As such, if char* was used instead of u_char* > > (which I'm not entirely sure why it isn't already), Evgeniy's workaround > > would be perfectly conformant to the C standard. > > > > It also doesn't break strict aliasing; unions are explicitly allowed to > > facilitate interpreting the same memory with incompatible types. > > The problem is discussed at length eg. here: > https://sqlpey.com/c/c-union-type-punning-behavior-c99-vs-c11-standards-explained/#c-union-type-punning-behavior-c99-vs-c11-standards-explained > > In conclusion there is no explicit allowance, and obtuse compiler > writers will intepret different union members as unrelated, and point to > the standard to support such obtuse implementation. Despite of absence of explicit allowance, some common sense may be used, particularly for situation where union members of primary type have the same length and alignment. I can't imagine compiler generating different memory addresses for such members. It seems me the only problem is alignment of members within union. The article cited does not explain why one method is considered "safer" then another, and why footnote did not become a part of normative text. Maybe there are some additional reasons in addition to alignment, it would be nice to know. In any case, thanks for valuable remark. -- Eugene Berdnikov |
|
From: Michal S. <msu...@su...> - 2026-04-16 13:16:40
|
On Thu, Apr 16, 2026 at 08:03:30PM +1000, Seth McDonald wrote:
> Hi,
>
> On Thu, 16 Apr 2026 at 11:40:36 +0200, Michal Suchánek wrote:
> > On Thu, Apr 16, 2026 at 11:45:47AM +0300, Evgeniy Berdnikov wrote:
> > > union { u_char *b; const void *cvoid_b; } ub;
> > >
> > > ub.cvoid_b = s;
> > > u_char *e = ub.b + n;
> > > while (--e >= ub.b)
> > > if (*e == c)
> > > ...
> > >
> > > It assumes that pointers to all bare types are represented identically,
> > > AFAIK, this is true for all existent C implementations.
> >
> > Also it breaks the aliasing rules that C fabricates regardless of the
> > actual use of the data.
>
> Actually in this specific case, it's (almost) fully defined within the C
> standard. From the C11 spec (the latest I have access to is C11):
>
> | A pointer to void shall have the same representation and alignment
> | requirements as a pointer to a character type. Similarly, pointers to
> | qualified or unqualified versions of compatible types shall have the
> | same representation and alignment requirements.
>
> So the conversion from const void* to void*, and from void* to char*, is
> not undefined behaviour. As such, if char* was used instead of u_char*
> (which I'm not entirely sure why it isn't already), Evgeniy's workaround
> would be perfectly conformant to the C standard.
>
> It also doesn't break strict aliasing; unions are explicitly allowed to
> facilitate interpreting the same memory with incompatible types.
The problem is discussed at length eg. here:
https://sqlpey.com/c/c-union-type-punning-behavior-c99-vs-c11-standards-explained/#c-union-type-punning-behavior-c99-vs-c11-standards-explained
In conclusion there is no explicit allowance, and obtuse compiler
writers will intepret different union members as unrelated, and point to
the standard to support such obtuse implementation.
Thanks
Michal
|
|
From: Seth M. <de...@se...> - 2026-04-16 10:03:50
|
Hi,
On Thu, 16 Apr 2026 at 11:40:36 +0200, Michal Suchánek wrote:
> On Thu, Apr 16, 2026 at 11:45:47AM +0300, Evgeniy Berdnikov wrote:
> > union { u_char *b; const void *cvoid_b; } ub;
> >
> > ub.cvoid_b = s;
> > u_char *e = ub.b + n;
> > while (--e >= ub.b)
> > if (*e == c)
> > ...
> >
> > It assumes that pointers to all bare types are represented identically,
> > AFAIK, this is true for all existent C implementations.
>
> Also it breaks the aliasing rules that C fabricates regardless of the
> actual use of the data.
Actually in this specific case, it's (almost) fully defined within the C
standard. From the C11 spec (the latest I have access to is C11):
| A pointer to void shall have the same representation and alignment
| requirements as a pointer to a character type. Similarly, pointers to
| qualified or unqualified versions of compatible types shall have the
| same representation and alignment requirements.
So the conversion from const void* to void*, and from void* to char*, is
not undefined behaviour. As such, if char* was used instead of u_char*
(which I'm not entirely sure why it isn't already), Evgeniy's workaround
would be perfectly conformant to the C standard.
It also doesn't break strict aliasing; unions are explicitly allowed to
facilitate interpreting the same memory with incompatible types.
Take care,
Seth McDonald.
--
E9D1 26A5 F0D4 9DF7 792B C2E2 B4BF 4530 D39B 2D51
|
|
From: Michal S. <msu...@su...> - 2026-04-16 09:40:49
|
On Thu, Apr 16, 2026 at 11:45:47AM +0300, Evgeniy Berdnikov wrote:
> Hello.
>
> On Thu, Apr 16, 2026 at 06:12:24PM +1000, Seth McDonald via isync-devel wrote:
> > The derivation of B from A thus requires casting away the const, which
> > produces a compilation warning in environments using our memrchr()
> > implementation. For all intents and purposes this warning is
> > unavoidable, so locally supress it for the relevant cast.
> ...
> > void *
> > memrchr( const void *s, int c, size_t n )
> > {
> > +DIAG_PUSH
> > +DIAG_DISABLE("-Wcast-qual")
> > u_char *b = (u_char *)s, *e = b + n;
> > +DIAG_POP
> >
> > while (--e >= b)
> > if (*e == c)
>
> BTW, there is a compiler-independent way to suppress such warning:
>
> union { u_char *b; const void *cvoid_b; } ub;
>
> ub.cvoid_b = s;
> u_char *e = ub.b + n;
> while (--e >= ub.b)
> if (*e == c)
> ...
>
> It assumes that pointers to all bare types are represented identically,
> AFAIK, this is true for all existent C implementations.
Also it breaks the aliasing rules that C fabricates regardless of the
actual use of the data.
As in b and cvoid_b being different types makes them independent
variables regardless of them accidentally occuppying the same memory,
and C is free to flag ub.b as unassigned, optimize out the assignment to
ub.cvoid_b that is never used, etc.
Thanks
Michal
|
|
From: Oswald B. <os...@us...> - 2026-04-16 09:21:02
|
On Thu, Apr 16, 2026 at 06:12:24PM +1000, Seth McDonald wrote: >(Why not make B const? Idfk ask the glibc devs.) > because that's most convenient on the user side (_somebody_ has to do that cast if the object is to be modified), and consistent with the "normal" memchr(), strchr(), and other similar functions. c23 aims to resolve this issue using a c11 feature. there is a pertinent thread on the mutt-dev list right now: https://marc.info/?l=mutt-dev&m=177631784909117&w=2 and https://marc.info/?l=mutt-dev&m=177632421112239&w=2 . regarding the commit message itself, it's way too wordy for my taste now, but still misses the key point: how does the implementation compare to what glibc itself actually does? |
|
From: Evgeniy B. <bi...@pr...> - 2026-04-16 08:46:10
|
Hello.
On Thu, Apr 16, 2026 at 06:12:24PM +1000, Seth McDonald via isync-devel wrote:
> The derivation of B from A thus requires casting away the const, which
> produces a compilation warning in environments using our memrchr()
> implementation. For all intents and purposes this warning is
> unavoidable, so locally supress it for the relevant cast.
...
> void *
> memrchr( const void *s, int c, size_t n )
> {
> +DIAG_PUSH
> +DIAG_DISABLE("-Wcast-qual")
> u_char *b = (u_char *)s, *e = b + n;
> +DIAG_POP
>
> while (--e >= b)
> if (*e == c)
BTW, there is a compiler-independent way to suppress such warning:
union { u_char *b; const void *cvoid_b; } ub;
ub.cvoid_b = s;
u_char *e = ub.b + n;
while (--e >= ub.b)
if (*e == c)
...
It assumes that pointers to all bare types are represented identically,
AFAIK, this is true for all existent C implementations.
--
Eugene Berdnikov
|
|
From: Seth M. <de...@se...> - 2026-04-16 08:12:43
|
In case the standard library does not provide the memrchr() function (a
GNU extension), we define our own implementation of the function. To
maintain compatibility with glibc, the function must receive a const
pointer A and return a non-const pointer B derived from A. (Why not
make B const? Idfk ask the glibc devs.)
The derivation of B from A thus requires casting away the const, which
produces a compilation warning in environments using our memrchr()
implementation. For all intents and purposes this warning is
unavoidable, so locally supress it for the relevant cast.
---
src/util.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/util.c b/src/util.c
index c110188d4fac..fc7f49899634 100644
--- a/src/util.c
+++ b/src/util.c
@@ -454,7 +454,10 @@ vasprintf( char **strp, const char *fmt, va_list ap )
void *
memrchr( const void *s, int c, size_t n )
{
+DIAG_PUSH
+DIAG_DISABLE("-Wcast-qual")
u_char *b = (u_char *)s, *e = b + n;
+DIAG_POP
while (--e >= b)
if (*e == c)
base-commit: 9aaac66286910f547ec3068d3fd72afb4fe716bf
--
2.50.1 (Apple Git-155)
|
|
From: Oswald B. <os...@us...> - 2026-04-14 11:24:36
|
On Tue, Apr 14, 2026 at 04:34:49PM +1000, Seth McDonald wrote: >One of the reasons for my per-attribute disabling >was to allow some amount of these nestings. Where, for example, msg1 is >bold and msg2 is red, and msg2 contains msg1. By working per-attribute, >the end of msg1 would not remove the red colouring of msg2. > i see how this could be useful in principle, but i suspect that this isn't a realistic use case in isync. given that the usage of the actual coloring api is rather "concentrated", it wouldn't cause much churn to switch to a fully fledged api at a later point. so i would start with the minimal implementation. >> however, another feature would actually make a lot of sense, to >> enable >> elegant (and slightly more efficient) wrapping of messages: recursive format >> strings. think >[...] >> i have wanted this so many times already that i wonder why the standard >> doesn't have it in some form. > >If I had to guess, probably because it sounds like a security nightmare >for implementors and users. [...] > that's a valid concern, but i think it's unfounded. you just have to apply the same rules to the nested format strings as to the top-level ones, i.e., pass only trusted strings (generally, constant string literals). security constraints are always applied top-down; never leaving a gap is just something you have to keep in mind. i suspect it might be actually an implementation problem. i think we'd need something like pointers into va_list or the ability to push the current state onto a stack, and i'm not convinced that either is actually a thing, at least portably. Somebody (TM) would have to give it a shot ... >Though for specific queries about the code, is this list appropriate >for asking?. > this list is just fine. you can also try to catch me on matrix, @ossi:kde.org, or ossi on libera.chat irc (which i use via the matrix bridge). >Also, it's probably becoming apparent that I'm generally not able to >reply quickly due to the difference in time zones. > yeah, aussie time is just about the worst for me. you can catch me in the late evening if you get up early, but then you'd actually have to use im, as at that time of day i read email only sporadically. >Hopefully that isn't too much of a problem :) > for me it's fine, i'm in no hurry ... |
|
From: Oswald B. <os...@us...> - 2026-04-14 10:51:08
|
On Tue, Apr 14, 2026 at 08:02:36PM +1000, Seth McDonald wrote: >To my knowledge, memrchr() is a nonstandard GNU extension, > yes, the linux man page says so. but then the obvious followup is "do whatever glibc does", and mention that in the commit message. |
|
From: Seth M. <de...@se...> - 2026-04-14 10:02:55
|
Hi Michal, On Tue, 14 Apr 2026 at 11:28:41 +0200, Michal Suchánek wrote: > On Tue, Apr 14, 2026 at 06:51:36PM +1000, Seth McDonald via isync-devel wrote: > > Our memrchr() implementation must cast away const from the 's' > > parameter, which causes a compiler warning. Locally suppress this > > warning for the relevant cast. > > it actually does not have to. > > It's quite possible to make the return value also const. > > It's not how the standard defines the function but not everything in the > standard makes sense. To my knowledge, memrchr() is a nonstandard GNU extension, so it isn't "as bad" to change the function signature. However, we only have a definition of the function for the situation in which the provided standard library does not include it. So if we change the signature for our implementation, then the function's signature will be different in different compilation environments: - If memrchr() is present in the standard library, the signature will have a non-const return value. - If memrchr() is not present, the signature will instead have a const return value. While I agree a const return value would be better, having different signatures in different environments would be worse. A single invariant codebase makes debugging and portability much easier. Which in this case may manifest as ensuring compilation does not succeed in only some environments but fail in others. Take care, Seth McDonald. -- E9D1 26A5 F0D4 9DF7 792B C2E2 B4BF 4530 D39B 2D51 |
|
From: Michal S. <msu...@su...> - 2026-04-14 09:29:10
|
Hello, On Tue, Apr 14, 2026 at 06:51:36PM +1000, Seth McDonald via isync-devel wrote: > Our memrchr() implementation must cast away const from the 's' > parameter, which causes a compiler warning. Locally suppress this > warning for the relevant cast. it actually does not have to. It's quite possible to make the return value also const. It's not how the standard defines the function but not everything in the standard makes sense. If you care about warnings and the code problems they point out using const return value sounds like a better option. Thanks Michal |
|
From: Seth M. <de...@se...> - 2026-04-14 08:52:54
|
Our memrchr() implementation must cast away const from the 's'
parameter, which causes a compiler warning. Locally suppress this
warning for the relevant cast.
---
src/util.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/util.c b/src/util.c
index c110188d4fac..fc7f49899634 100644
--- a/src/util.c
+++ b/src/util.c
@@ -454,7 +454,10 @@ vasprintf( char **strp, const char *fmt, va_list ap )
void *
memrchr( const void *s, int c, size_t n )
{
+DIAG_PUSH
+DIAG_DISABLE("-Wcast-qual")
u_char *b = (u_char *)s, *e = b + n;
+DIAG_POP
while (--e >= b)
if (*e == c)
base-commit: 9aaac66286910f547ec3068d3fd72afb4fe716bf
--
2.50.1 (Apple Git-155)
|
|
From: Seth M. <de...@se...> - 2026-04-14 06:35:17
|
On Mon, 13 Apr 2026 at 12:33:42 +0200, Oswald Buddenhagen via isync-devel wrote: > i had that thought as well, but i'm actually thinking yet more radically > minimalistic: > > ... > #define COLOR_WARNING "\x1b[33m" > #define COLOR_ERROR "\x1b[31m" > #define RESET_COLOR "\x1b[0m" The main disadvantage to this approach is if you want to check or change these values (e.g. change warnings from yellow to bright yellow), you'd have to look up the SGR escape codes, find the desired values, add them, and test to ensure they were correct. As opposed to just changing a flag on a function. Of course, I assume it's unlikely the colour scheme would change much in the future, so this isn't by itself an argument against this approach; it's just something I think important to note. Btw, if using this approach, you can shorten consecutive escape sequences by separating the parameter values with semicolons. For example, to specify "bold and red", rather than using "\x1b[1m\x1b[31m", you can use "\x1b[1;31m". > > xprintf( "%?hello!%?\n", SGR_BOLD, SGR_NO_BOLD ); > > > yes, something like that, with automatic handling of disabled coloring. If we're going to be auto-disabling display attributes with (presumably) the "\x1b[0m" escape sequence, then that does limit the use of nested coloured messages. One of the reasons for my per-attribute disabling was to allow some amount of these nestings. Where, for example, msg1 is bold and msg2 is red, and msg2 contains msg1. By working per-attribute, the end of msg1 would not remove the red colouring of msg2. Btw, you can actually shorten the escape sequence "\x1b[0m" to just "\x1b[m". If you don't give a parameter, it just assumes zero. > however, another feature would actually make a lot of sense, to enable > elegant (and slightly more efficient) wrapping of messages: recursive format > strings. think [...] > i have wanted this so many times already that i wonder why the standard > doesn't have it in some form. If I had to guess, probably because it sounds like a security nightmare for implementors and users. To be clear, I'm not at all a security expert or anything. But it feels like something that could open a plethora of possible attacks that would need to be accounted for. Things like injecting %s and %n sequences, and misusing or miscounting the nested variadic arguments come to mind, for instance. I think recursive format strings should definitely be something we should stay away from for this reason. At least not until there's some _strong_ confirmation that they are indeed safe to use. I personally would not be too comfortable using them without such confirmation. > > Sure, I was just trying to avoid the situation where errors or warnings > > may occur before and after parsing the --color option, which would cause > > the former output to not be coloured, while the latter output would be > > (or vice versa). > > > the whole point of the coloring is to make it easier to spot significant > information in large amounts of output. so let's consider the cases: > if there is an error, the run ends right at startup. there isn't any other > output. That's a good point; I hadn't considered that. So the only inconsistency would be between separate program executions with different command-line options, which doesn't nearly matter as much (if at all, arguably). > config parsing starts only now. that might become a minor problem if > somebody really needs a persistent version of the option, but for the time > being i have no intention of adding that. For persistent coloured output, if the default auto-detection doesn't detect support for the tty, you can just define a shell alias: alias mbsync="mbsync --color" That's what I do for grep, ls, etc. > looking at patches can be a useful way to familiarize oneself with a > project, because they offer a narrow, directed entry point. Nice idea. I'll have a look at the patches associated with relevant code (identified via git-blame or git-log). There's also the mailing list archives I can check out. Though for specific queries about the code, is this list appropriate for asking? Things like "what's the purpose of this variable?" or "why use this rather than that?". Asked after RTFM, of course. Also, it's probably becoming apparent that I'm generally not able to reply quickly due to the difference in time zones. Hopefully that isn't too much of a problem :) Take care, Seth McDonald. -- E9D1 26A5 F0D4 9DF7 792B C2E2 B4BF 4530 D39B 2D51 |
|
From: Evgeniy B. <bi...@pr...> - 2026-04-13 15:55:24
|
On Mon, Apr 13, 2026 at 12:44:17PM +0200, Oswald Buddenhagen via isync-devel wrote: > On Mon, Apr 13, 2026 at 01:24:54PM +0300, Evgeniy Berdnikov wrote: > > Yes, I think good approach is to do things right, > > if implementation is not very complex. > > > indeed, and that's where things get utterly out of hand. > > if we wanted to go beyond the proposed absolutely trivial heuristics, we > should do it properly and use termcap/terminfo. i would like to avoid that > until ncurses proper is on the table I agree, we should avoid heavy code with terminfo (termcap is deprecated). After some googling I've got an impression that almost all modern terminal emulators do supports vt100-like escape sequences. So we do not need real selectivity for terminal type today. I withdraw my proposal. PS. My short research results in this list of terminal name prefixes, indicating vt100-escapes support: "xterm", "vt100", "linux", "rxvt", "putty", "konsole", and lot of names starting with "vt"+digits. -- Eugene Berdnikov |
|
From: Oswald B. <osw...@gm...> - 2026-04-13 10:44:30
|
On Mon, Apr 13, 2026 at 01:24:54PM +0300, Evgeniy Berdnikov wrote: > Yes, I think good approach is to do things right, > if implementation is not very complex. > indeed, and that's where things get utterly out of hand. if we wanted to go beyond the proposed absolutely trivial heuristics, we should do it properly and use termcap/terminfo. i would like to avoid that until ncurses proper is on the table (which would be useful for full-screen visualization of massive parallelism, but why would one want that level of complexity in a tool that is mostly used in background jobs?). |
|
From: Oswald B. <os...@us...> - 2026-04-13 10:33:54
|
On Mon, Apr 13, 2026 at 04:54:41PM +1000, Seth McDonald wrote:
>It is true that sgr_attr_t isn't actually needed; the
>ds_to_sgr function pointer could just return the escape sequence string
>directly (e.g. returning "\x1b[31m" rather than 31).
>
i had that thought as well, but i'm actually thinking yet more radically
minimalistic:
...
#define COLOR_WARNING "\x1b[33m"
#define COLOR_ERROR "\x1b[31m"
#define RESET_COLOR "\x1b[0m"
that's the big advantage of limiting ourselves to basic SGR sequences.
no abstractions needed.
> xprintf( "%?hello!%?\n", SGR_BOLD, SGR_NO_BOLD );
>
yes, something like that, with automatic handling of disabled coloring.
but this is probably over-engineered; it doesn't really add much value
as-is.
however, another feature would actually make a lot of sense, to enable
elegant (and slightly more efficient) wrapping of messages: recursive
format strings. think
void err(const char *fmt, ...)
{
va_list va;
char date[32];
va_start( va, fmt );
fmt_date(date);
xprintf( "%s " COLOR_ERROR "error: %&" RESET_COLOR "\n", date, fmt, va );
va_end( va );
}
i have wanted this so many times already that i wonder why the standard
doesn't have it in some form.
>Though on the other hand, this would increase usage of a custom printf()
>implementation over the standard library's. Which, since the library's
>is likely much more optimised, may incur a slight performance hit.
>
the only thing one can do really badly in that context is to pass every
char separately to the output layer. or do lots of dynamic allocations.
we don't do either.
but realistically, performance differences in the printf implementation
are entirely negligible in this application.
>Sure, I was just trying to avoid the situation where errors or warnings
>may occur before and after parsing the --color option, which would cause
>the former output to not be coloured, while the latter output would be
>(or vice versa).
>
the whole point of the coloring is to make it easier to spot significant
information in large amounts of output. so let's consider the cases:
if there is an error, the run ends right at startup. there isn't any
other output.
warnings are printed only after the parsing completed, at which point
coloring can be already enabled.
config parsing starts only now. that might become a minor problem if
somebody really needs a persistent version of the option, but for the
time being i have no intention of adding that.
>> i recommend that you take a look at all wip/ branches, [...]
>
>I typically just look the master/main branch as it can sometimes be
>difficult to determine which branches are still in development and which
>are done or abandoned (in general, not this repo specifically). But I
>can take a look at those wip branches if they're still open for
>development.
>
everything in the repo should be still relevant somehow.
most branches are "indefinitely deferred" for one reason or another.
the commit message of the initial (and usually only) commit should
explain why, though this isn't always the case.
if you see anything that appears truly abandoned (or obsolete), let me
know.
>Though I am still trying to wrap my head around much of the code in the
>master branch, so it may be a bit before I rigorously examine some other
>branches.
>
looking at patches can be a useful way to familiarize oneself with a
project, because they offer a narrow, directed entry point. it's
basically a bottom-up approach. of course, this isn't useful if the
topics handled there have little/no overlap with what actually interests
you.
|
|
From: Evgeniy B. <bi...@pr...> - 2026-04-13 10:25:15
|
Hello.
On Mon, Apr 13, 2026 at 03:02:08PM +1000, Seth McDonald wrote:
> On Sun, 12 Apr 2026 at 19:56:41 +0300, Evgeniy Berdnikov wrote:
> > Absence of terminal is not an error, this is normal situation, such as run
> > in batch job or systemd service.
>
> Indeed. That's why it's checking if errno is _not_ ENOTTY.
Sorry, you're right, I misread the code.
> > You have better to check explicitly at least for "xterm", "linux" and "vt100"
> > (with account for suffixes after "-" character, as term(7) and terminfo(5)
> > stated), and do not use vt100-like escapes for unknown/undefined terminals.
>
> So you're saying we should default to not using escape sequences unless
> the terminal is known to support them (as opposed to defaulting to using
> them unless the terminal is known to not support them)? I'd imagine
> we'd have to cover a lot of cases to be portable, which is possible, but
> IMO not really the best use of time.
Yes, I think good approach is to do things right, if implementation is
not very complex. For this case code may be like this:
int detect_display_attrs(..) {
...
char *term_names[] = { "vt100", "xterm", "linux", NULL };
int prefix_len;
char *minus_ptr, *n;
...
minus_ptr = strchrnul(term, '-');
prefix_len = (int)(minus_ptr - term);
for (n = term_names[0]; n; n++) {
if (!strncmp(term, n, prefix_len))
return 1;
}
return 0;
}
--
Eugene Berdnikov
|
|
From: Seth M. <de...@se...> - 2026-04-13 06:54:59
|
Hi Oswald, On Sun, 12 Apr 2026 at 14:16:04 +0200, Oswald Buddenhagen via isync-devel wrote: > On Sun, Apr 12, 2026 at 04:14:21PM +1000, Seth McDonald wrote: > > This patchset aims to tick off the following from the TODO file. > > > > | possibly use ^[[1m to highlight error messages. > > > cool. > > my first reaction is "huh, this is completely over-engineered". Yeah I can see that lol. My goal was to add an API (well, one function) that's simple to use (hence the bitfield) and requires minimal change to the existing codebase to use (hence the message "wrapping"). > i'd just go > with a hard-coded SGR sequence #define for each message class and a common > reset sequence rather than an elaborate attribute translation layer. You're referring to the transition between display_attr_enum and sgr_attr_t? It is true that sgr_attr_t isn't actually needed; the ds_to_sgr function pointer could just return the escape sequence string directly (e.g. returning "\x1b[31m" rather than 31). I think I initially included sgr_attr_t to make it easier to represent escape sequences (it's easier to store integers than strings). But in hindsight that benefit doesn't really manifest given I immediately convert any sgr_attr_t values to their corresponding string representation. So I think I agree that directly converting from display_attr_enum values to escape strings (with #defines) is better. > the wrapping of the "base calls" is a good (and somewhat obvious) idea. but > for the implementation, we may end up with something rather different: > - we may be able to inject the sequences more directly by virtue of having > our own printf() implementation. that's just an idea, not an instruction. xprintf()? I haven't yet looked too much into that, but it seems to be similar to printf() but with extra format sequences and a trailing callback. If this were the way to go, I would imagine a specific format sequence to insert an escape sequence could work. Something like: xprintf( "%?hello!%?\n", SGR_BOLD, SGR_NO_BOLD ); Though on the other hand, this would increase usage of a custom printf() implementation over the standard library's. Which, since the library's is likely much more optimised, may incur a slight performance hit. That's just a guess though; I haven't done any benchmarking. > there is no need for the init_colors() hack. coloring the command line > parser output adds no value, so it's fine to just postpone coloring > activation. Sure, I was just trying to avoid the situation where errors or warnings may occur before and after parsing the --color option, which would cause the former output to not be coloured, while the latter output would be (or vice versa). But if that's not a concern then the logic can certainly be simplified. > please use american english throughout. it's not that i like it, but that's > what the "C" locale really is, and consistency is king. Of course, forgot to include the US-defaultism ;) > as you're certainly noticing at this point, i'm very particular about how > things should be implemented. to avoid wasting time and mental energy, it's > best to discuss designs in advance. i think the "show me the code" approach > many projects go with is extremely disrespectful towards contributors for > anything but the most trivial patches. Good to know; I'm glad communication is welcomed :). And I'll be happy to propose any ideas prior to fully implementing them (other than simple typos/fixes, of course). > i recommend that you take a look at all wip/ branches, to avoid redundancy > and divergent developments (beyond what happened since the branches > sprouted, anyway - some a rather old). these aren't a priority by any means, > but it may make sense to drive some of them to completion before doing other > stuff, not last because many of them are (based on) external contributions, > so obviously somebody cared enough to give it a shot. I typically just look the master/main branch as it can sometimes be difficult to determine which branches are still in development and which are done or abandoned (in general, not this repo specifically). But I can take a look at those wip branches if they're still open for development. Though I am still trying to wrap my head around much of the code in the master branch, so it may be a bit before I rigorously examine some other branches. Take care, Seth McDonald. -- E9D1 26A5 F0D4 9DF7 792B C2E2 B4BF 4530 D39B 2D51 |
|
From: Seth M. <de...@se...> - 2026-04-13 05:02:28
|
Hi Evgeniy,
On Sun, 12 Apr 2026 at 19:56:41 +0300, Evgeniy Berdnikov wrote:
> On Sun, Apr 12, 2026 at 04:14:22PM +1000, Seth McDonald via isync-devel wrote:
> > + errno = 0;
> > + if (!isatty( fd )) {
> > + if (errno != ENOTTY)
> > + sys_error( "Cannot examine file descriptor %d", fd );
>
> Absence of terminal is not an error, this is normal situation, such as run
> in batch job or systemd service.
Indeed. That's why it's checking if errno is _not_ ENOTTY. See the
POSIX.1-2024 entry for isatty()[0]:
| The isatty() function may fail if:
[...]
| [ENOTTY]
| The file associated with the fildes argument is not a terminal.
If fd is not a terminal, errno will be set to ENOTTY, meaning the error
message will not appear. But if errno is not set to ENOTTY, then the
isatty() call failed for a reason other than "not a terminal" (probably
an invalid file descriptor). This is an error that should be logged,
because it indicates something is wrong with the program state.
> > + const char *term = getenv( "TERM" );
> > + if (term && !strcmp( term, "dumb" ))
> > + return 0;
>
> You are assuming all terminals different from "dumb" do support vt100-like
> escape sequences. This is almost true, because other terminals are
> historical artefacts. Moreover, in case of undefined TERM this code produces
> escape sequences. I think it should not be.
I actually just attempted to mimic the behaviour of git-status here. I
ran `TERM=... git status` a few times, with TERM set to different
values, and found that - of the values I tested - only TERM=dumb removed
the coloured output.
I figured it would be better to defer the wanted behaviour to those of
common existing programs, as this would integrate nicely in environments
that users may have already curated for such behaviour. Though I am
open to adding custom behaviour if that's what's wanted.
> You have better to check explicitly at least for "xterm", "linux" and "vt100"
> (with account for suffixes after "-" character, as term(7) and terminfo(5)
> stated), and do not use vt100-like escapes for unknown/undefined terminals.
So you're saying we should default to not using escape sequences unless
the terminal is known to support them (as opposed to defaulting to using
them unless the terminal is known to not support them)? I'd imagine
we'd have to cover a lot of cases to be portable, which is possible, but
IMO not really the best use of time.
Take care,
Seth McDonald.
[0] <https://pubs.opengroup.org/onlinepubs/9799919799/functions/isatty.html>
--
E9D1 26A5 F0D4 9DF7 792B C2E2 B4BF 4530 D39B 2D51
|
|
From: Evgeniy B. <bi...@pr...> - 2026-04-12 16:57:08
|
Hello.
On Sun, Apr 12, 2026 at 04:14:22PM +1000, Seth McDonald via isync-devel wrote:
> +/*
> + * Attempts to guess whether the file descriptor 'fd' supports display
> + * attributes via escape sequences. Returns one if supported, and zero
> + * otherwise.
> + */
> +int
> +detect_display_attrs( int fd )
> +{
> + errno = 0;
> + if (!isatty( fd )) {
> + if (errno != ENOTTY)
> + sys_error( "Cannot examine file descriptor %d", fd );
Absence of terminal is not an error, this is normal situation, such as run
in batch job or systemd service.
> + return 0;
> + }
> +
> + const char *term = getenv( "TERM" );
> + if (term && !strcmp( term, "dumb" ))
> + return 0;
You are assuming all terminals different from "dumb" do support vt100-like
escape sequences. This is almost true, because other terminals are
historical artefacts. Moreover, in case of undefined TERM this code produces
escape sequences. I think it should not be.
You have better to check explicitly at least for "xterm", "linux" and "vt100"
(with account for suffixes after "-" character, as term(7) and terminfo(5)
stated), and do not use vt100-like escapes for unknown/undefined terminals.
--
Eugene Berdnikov
|
|
From: Oswald B. <os...@us...> - 2026-04-12 12:16:17
|
moin!
On Sun, Apr 12, 2026 at 04:14:21PM +1000, Seth McDonald wrote:
>This patchset aims to tick off the following from the TODO file.
>
>| possibly use ^[[1m to highlight error messages.
>
cool.
my first reaction is "huh, this is completely over-engineered". i'd just
go with a hard-coded SGR sequence #define for each message class and a
common reset sequence rather than an elaborate attribute translation
layer.
the wrapping of the "base calls" is a good (and somewhat obvious) idea.
but for the implementation, we may end up with something rather
different:
- we may be able to inject the sequences more directly by virtue of
having our own printf() implementation. that's just an idea, not an
instruction.
- there is the wip/better-stderr branch, which puts the output
completely upside down. it would be probably a good idea to finalize
that branch (which may mean completely changing the approach) before
making the output more fancy. or at least plan out how adding things
now would affect the later refactoring.
there is no need for the init_colors() hack. coloring the command line
parser output adds no value, so it's fine to just postpone coloring
activation.
for the color scheme, i'd use journalctl's "ladder": dark grey ("bold
black" in SGR terms) for debug, (bold) white for info, (bold) yellow for
warning, and (bold) red for error.
please use american english throughout. it's not that i like it, but
that's what the "C" locale really is, and consistency is king. it's ok
to silently accept --colour to not break people's finger memory, but
documenting it just adds noise that adds cognitive load.
(yes, i realize the irony of using "grey" instead of "gray" above. ;-P)
---
a few notes on process:
as you're certainly noticing at this point, i'm very particular about
how things should be implemented. to avoid wasting time and mental
energy, it's best to discuss designs in advance. i think the "show me
the code" approach many projects go with is extremely disrespectful
towards contributors for anything but the most trivial patches.
i recommend that you take a look at all wip/ branches, to avoid
redundancy and divergent developments (beyond what happened since the
branches sprouted, anyway - some a rather old). these aren't a priority
by any means, but it may make sense to drive some of them to completion
before doing other stuff, not last because many of them are (based on)
external contributions, so obviously somebody cared enough to give it a
shot.
conversely, i need to be more pro-active in pushing out what is cooking.
i pushed wip/master-next for that purpose (expect it to be force-pushed
at any time). you'll find something that looks familiar in there ...
so far ... ^^
|
|
From: ossi <os...@us...> - 2026-04-12 11:02:31
|
The branch 'wip/master-next' has been created at 3b299c5. |
|
From: Seth M. <de...@se...> - 2026-04-12 06:17:36
|
Add a command line option to control whether the program output should
be coloured using SGR escape sequences.
---
TODO | 2 --
src/Makefile.am | 8 +++---
src/common.h | 2 ++
src/main.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++
src/main_p.h | 1 +
src/mbsync.1.in | 6 +++++
src/util.c | 69 +++++++++++++++++++++++++++++++++++++++++++++----
7 files changed, 146 insertions(+), 11 deletions(-)
diff --git a/TODO b/TODO
index 43f0c0da2ded..4e2d2588bb76 100644
--- a/TODO
+++ b/TODO
@@ -75,8 +75,6 @@ matters.
some error messages are unhelpful in non-verbose mode due to missing context.
-possibly use ^[[1m to highlight error messages.
-
consider alternative approach to trashing: instead of the current trash-before-
expunge done by mbsync, let MUAs do the trashing (as modern ones typically do).
mbsync wouldn't do any trashing by itself, but should track the moves for
diff --git a/src/Makefile.am b/src/Makefile.am
index 6354452cd8fb..519944e1ca70 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -35,17 +35,17 @@ bin_PROGRAMS = mbsync $(mdconvert_prog)
# don't forget to update AC_CONFIG_FILES in configure.ac!
man_MANS = mbsync.1 $(mdconvert_man)
-tst_imap_msgs_SOURCES = tst_imap_msgs.c imap_msgs.c util.c
+tst_imap_msgs_SOURCES = tst_imap_msgs.c imap_msgs.c util.c display.c
-tst_imap_utf7_SOURCES = tst_imap_utf7.c imap_utf7.c util.c
+tst_imap_utf7_SOURCES = tst_imap_utf7.c imap_utf7.c util.c display.c
-tst_msg_cvt_SOURCES = tst_msg_cvt.c sync_msg_cvt.c util.c
+tst_msg_cvt_SOURCES = tst_msg_cvt.c sync_msg_cvt.c util.c display.c
tst_msg_cvt_CFLAGS = -DQPRINTF_BUFF=10000
check_PROGRAMS = tst_imap_msgs tst_imap_utf7 tst_msg_cvt
TESTS = $(check_PROGRAMS)
-tst_timers_SOURCES = tst_timers.c util.c
+tst_timers_SOURCES = tst_timers.c util.c display.c
EXTRA_PROGRAMS = tst_timers
diff --git a/src/common.h b/src/common.h
index 38521b685bc3..561100658b55 100644
--- a/src/common.h
+++ b/src/common.h
@@ -178,6 +178,8 @@ extern int Verbosity;
extern int DFlags;
extern int JLimit, JCount;
extern int UseFSync;
+extern int ColourOut;
+extern int ColourErr;
// Global constants (inited by main())
extern int Pid;
diff --git a/src/main.c b/src/main.c
index 8581b0cf6c72..866f0dd9ccc9 100644
--- a/src/main.c
+++ b/src/main.c
@@ -50,6 +50,7 @@ PACKAGE " " VERSION " - mailbox synchronizer\n"
" -e, --ext-exit return extended exit code\n"
" -V, --verbose display what is happening\n"
" -q, --quiet don't display progress counters\n"
+" --colo[u]r=WHEN do or do not colour the output\n"
" -v, --version display version\n"
" -h, --help display this help message\n"
"\nIf neither --pull nor --push are specified, both are active.\n"
@@ -163,14 +164,70 @@ countStep( void )
exit( 100 );
}
+static void
+init_colour( int argc, char **argv )
+{
+ int found = 0;
+
+ for (int i = 1; i < argc; i++) {
+ const char *opt = argv[i];
+ if (opt[0] != '-' || (opt[1] == '-' && !opt[2]))
+ break;
+ if (opt[1] != '-') {
+ for (int j = 1; opt[j]; j++) {
+ if (opt[j] == 'c')
+ i++; // Skip config files
+ }
+ continue;
+ }
+
+ opt += 2;
+ if (!strcmp( opt, "color" ) || !strcmp( opt, "colour" )) {
+ ColourOut = 1;
+ ColourErr = 1;
+ found = 1;
+ continue;
+ }
+ if (starts_with( opt, -1, "color=", 6 )) {
+ opt += 6;
+ goto opt_eq;
+ }
+ if (starts_with( opt, -1, "colour=", 7 )) {
+ opt += 7;
+ opt_eq:
+ if (!strcmp( opt, "on" )) {
+ ColourOut = 1;
+ ColourErr = 1;
+ } else if (!strcmp( opt, "off" )) {
+ ColourOut = 0;
+ ColourErr = 0;
+ } else if (!strcmp( opt, "auto")) {
+ ColourOut = detect_display_attrs( STDOUT_FILENO );
+ ColourErr = detect_display_attrs( STDERR_FILENO );
+ }
+ found = 1;
+ continue;
+ }
+
+ if (!strcmp( opt, "config" ))
+ i++; // Skip config file
+ }
+
+ if (!found) {
+ ColourOut = detect_display_attrs( STDOUT_FILENO );
+ ColourErr = detect_display_attrs( STDERR_FILENO );
+ }
+}
+
int
main( int argc, char **argv )
{
core_vars_t mvars[1];
char *config = NULL, *opt, *ochar;
int oind, cops = 0, op, ms_warn = 0, renew_warn = 0, delete_warn = 0;
tzset();
+ init_colour( argc, argv ); // Must call before calling error()/warn()/etc.
init_timers();
gethostname( Hostname, sizeof(Hostname) );
if ((ochar = strchr( Hostname, '.' )))
@@ -202,6 +259,18 @@ main( int argc, char **argv )
config = argv[oind++];
} else if (starts_with( opt, -1, "config=", 7 )) {
config = opt + 7;
+ } else if (!strcmp( opt, "color" )
+ || !strcmp( opt, "colour" )) {
+ // Stub - configured in init_colour()
+ } else if (starts_with( opt, -1, "color=", 6 )) {
+ opt += 6;
+ goto colour_opt;
+ } else if (starts_with( opt, -1, "colour=", 7 )) {
+ opt += 7;
+ colour_opt:
+ if (strcmp( opt, "on" ) && strcmp( opt, "off" )
+ && strcmp( opt, "auto" ))
+ goto badopt;
} else if (!strcmp( opt, "all" )) {
mvars->all = 1;
} else if (!strcmp( opt, "list" )) {
diff --git a/src/main_p.h b/src/main_p.h
index 6aa5fe2ba201..dbdb5c957e33 100644
--- a/src/main_p.h
+++ b/src/main_p.h
@@ -9,6 +9,7 @@
#define DEBUG_FLAG DEBUG_MAIN
+#include "display.h"
#include "sync.h"
typedef struct {
diff --git a/src/mbsync.1.in b/src/mbsync.1.in
index 1a15b10a2606..2e0fe801c9ad 100644
--- a/src/mbsync.1.in
+++ b/src/mbsync.1.in
@@ -119,6 +119,12 @@ .SH OPTIONS
Suppress progress counters (this is implicit if stdout is no TTY,
or any debugging categories are enabled), notices, and the summary.
If specified twice, suppress warning messages as well.
+.TP
+\fB--colo\fR[\fBu\fR]\fBr\fR[\fB=\fR{\fBon\fR|\fBoff\fR|\fBauto\fR}]
+If \fBon\fR or \fBoff\fR, output is or isn't coloured, respectively.
+If \fBauto\fR, output is coloured iff supported by the TTY (the default).
+If \fBon\fR/\fBoff\fR/\fBauto\fR is not specified, \fBon\fR is assumed.
+If given multiple times, the last one takes effect.
.
.SH CONFIGURATION
The configuration file is mandatory; \fBmbsync\fR will not run without it.
diff --git a/src/util.c b/src/util.c
index c110188d4fac..b453af310b8f 100644
--- a/src/util.c
+++ b/src/util.c
@@ -6,6 +6,7 @@
*/
#include "common.h"
+#include "display.h"
#include <fcntl.h>
#include <sys/stat.h>
@@ -18,6 +19,8 @@ int Verbosity = TERSE;
int DFlags;
int JLimit, JCount;
int UseFSync = 1;
+int ColourOut;
+int ColourErr;
int Pid;
char Hostname[256];
@@ -101,14 +104,28 @@ nvprint( const char *msg, va_list va )
vprint( msg, va );
}
+static void ATTR_PRINTFLIKE(1, 0)
+vinfo( const char *msg, va_list va )
+{
+ char *clr_msg = NULL;
+
+ if (ColourOut) {
+ clr_msg = wrap_msg( msg, DS_FG_GREEN );
+ msg = clr_msg;
+ }
+
+ nvprint( msg, va );
+ free( clr_msg );
+}
+
void
info( const char *msg, ... )
{
va_list va;
if (Verbosity >= VERBOSE) {
va_start( va, msg );
- nvprint( msg, va );
+ vinfo( msg, va );
va_end( va );
}
}
@@ -120,45 +137,87 @@ infon( const char *msg, ... )
if (Verbosity >= VERBOSE) {
va_start( va, msg );
- nvprint( msg, va );
+ vinfo( msg, va );
va_end( va );
need_nl = 1;
}
}
+static void ATTR_PRINTFLIKE(1, 0)
+vnotice( const char *msg, va_list va )
+{
+ char *clr_msg = NULL;
+
+ if (ColourOut) {
+ clr_msg = wrap_msg( msg, DS_BOLD );
+ msg = clr_msg;
+ }
+
+ nvprint( msg, va );
+ free( clr_msg );
+}
+
void
notice( const char *msg, ... )
{
va_list va;
if (Verbosity >= TERSE) {
va_start( va, msg );
- nvprint( msg, va );
+ vnotice( msg, va );
va_end( va );
}
}
+static void ATTR_PRINTFLIKE(1, 0)
+vwarn( const char *msg, va_list va )
+{
+ char *clr_msg = NULL;
+
+ if (ColourErr) {
+ clr_msg = wrap_msg( msg, DS_FG_RED );
+ msg = clr_msg;
+ }
+
+ vfprintf( stderr, msg, va );
+ free( clr_msg );
+}
+
void
warn( const char *msg, ... )
{
va_list va;
if (Verbosity >= QUIET) {
flushn();
va_start( va, msg );
- vfprintf( stderr, msg, va );
+ vwarn( msg, va );
va_end( va );
}
}
+static void ATTR_PRINTFLIKE(1, 0)
+verror( const char *msg, va_list va )
+{
+ char *clr_msg = NULL;
+
+ if (ColourErr) {
+ clr_msg = wrap_msg( msg, DS_BOLD | DS_FG_RED | DS_BG_BLACK );
+ msg = clr_msg;
+ }
+
+ vfprintf( stderr, msg, va );
+ free( clr_msg );
+}
+
void
error( const char *msg, ... )
{
va_list va;
flushn();
va_start( va, msg );
- vfprintf( stderr, msg, va );
+ verror( msg, va );
va_end( va );
}
--
2.47.3
|
|
From: Seth M. <de...@se...> - 2026-04-12 06:17:35
|
Hello! This patchset aims to tick off the following from the TODO file. | possibly use ^[[1m to highlight error messages. There are numerous points at which the program calls error(), warn(), etc., and I wanted to implement something that wouldn't require changing every such call. So patch 1 adds an API which can wrap a given format message in select escape sequences, such that the resultant message can be passed straight to printf-like functions. This way only the error(), warn(), etc., function definitions need to be altered to use coloured output, which patch 2 does. I did select the colour of error/warning/etc. messages in patch 2 quite arbitrarily, and would recommend playing around with different colours and other display attributes to find a good combination. Lightly tested on macOS 26.4.1 (Tahoe) and Debian 13.4 (trixie). Take care, Seth McDonald. Seth McDonald (2): Add API to support escape sequences Integrate support for coloured output TODO | 2 - src/Makefile.am | 10 +- src/common.h | 2 + src/display.c | 354 ++++++++++++++++++++++++++++++++++++++++++++++++ src/display.h | 46 +++++++ src/main.c | 69 ++++++++++ src/main_p.h | 1 + src/mbsync.1.in | 6 + src/util.c | 69 +++++++++- 9 files changed, 548 insertions(+), 11 deletions(-) create mode 100644 src/display.c create mode 100644 src/display.h Range-diff: 1: 3f7cd64807a5 = 1: 3f7cd64807a5 Add API to support escape sequences 2: a3c1cd151f48 = 2: a3c1cd151f48 Integrate support for coloured output base-commit: 9aaac66286910f547ec3068d3fd72afb4fe716bf -- 2.47.3 |