fish-shell/src/color.h
Kurtis Rader 509ee64fc9 implement our own assert() function
I recently upgraded the software on my macOS server and was dismayed to
see that cppcheck reported a huge number of format string errors due to
mismatches between the format string and its arguments from calls to
`assert()`. It turns out they are due to the macOS header using `%lu`
for the line number which is obviously wrong since it is using the C
preprocessor `__LINE__` symbol which evaluates to a signed int.

I also noticed that the macOS implementation writes to stdout, rather
than stderr. It also uses `printf()` which can be a problem on some
platforms if the stream is already in wide mode which is the normal case
for fish.

So implement our own `assert()` implementation. This also eliminates
double-negative warnings that we get from some of our calls to
`assert()` on some platforms by oclint.

Also reimplement the `DIE()` macro in terms of our internal
implementation.

Rewrite `assert(0 && msg)` statements to `DIE(msg)` for clarity and to
eliminate oclint warnings about constant expressions.

Fixes #3276, albeit not in the fashion I originally envisioned.
2017-02-14 18:48:27 -08:00

172 lines
4.8 KiB
C++

// Color class.
#ifndef FISH_COLOR_H
#define FISH_COLOR_H
#include <string.h>
#include <string>
#include "common.h"
// 24-bit color.
struct color24_t {
unsigned char rgb[3];
};
/// A type that represents a color. We work hard to keep it at a size of 4 bytes.
class rgb_color_t {
// Types
enum { type_none, type_named, type_rgb, type_normal, type_reset };
unsigned char type : 4;
// Flags
enum {
flag_bold = 1 << 0,
flag_underline = 1 << 1,
flag_italics = 1 << 2,
flag_dim = 1 << 3,
flag_reverse = 1 << 4
};
unsigned char flags : 5;
union {
unsigned char name_idx; // 0-10
color24_t color;
} data;
/// Try parsing a special color name like "normal".
bool try_parse_special(const wcstring &str);
/// Try parsing an rgb color like "#F0A030".
bool try_parse_rgb(const wcstring &str);
/// Try parsing an explicit color name like "magenta".
bool try_parse_named(const wcstring &str);
/// Parsing entry point.
void parse(const wcstring &str);
/// Private constructor.
explicit rgb_color_t(unsigned char t, unsigned char i = 0);
public:
/// Default constructor of type none.
explicit rgb_color_t() : type(type_none), flags(), data() {}
/// Parse a color from a string.
explicit rgb_color_t(const wcstring &str);
explicit rgb_color_t(const std::string &str);
/// Returns white.
static rgb_color_t white();
/// Returns black.
static rgb_color_t black();
/// Returns the reset special color.
static rgb_color_t reset();
/// Returns the normal special color.
static rgb_color_t normal();
/// Returns the none special color.
static rgb_color_t none();
/// Returns whether the color is the normal special color.
bool is_normal(void) const { return type == type_normal; }
/// Returns whether the color is the reset special color.
bool is_reset(void) const { return type == type_reset; }
/// Returns whether the color is the none special color.
bool is_none(void) const { return type == type_none; }
/// Returns whether the color is a named color (like "magenta").
bool is_named(void) const { return type == type_named; }
/// Returns whether the color is specified via RGB components.
bool is_rgb(void) const { return type == type_rgb; }
/// Returns whether the color is special, that is, not rgb or named.
bool is_special(void) const { return type != type_named && type != type_rgb; }
/// Returns a description of the color.
wcstring description() const;
/// Returns the name index for the given color. Requires that the color be named or RGB.
unsigned char to_name_index() const;
/// Returns the term256 index for the given color. Requires that the color be RGB.
unsigned char to_term256_index() const;
/// Returns the 24 bit color for the given color. Requires that the color be RGB.
color24_t to_color24() const;
/// Returns whether the color is bold.
bool is_bold() const { return static_cast<bool>(flags & flag_bold); }
/// Set whether the color is bold.
void set_bold(bool x) {
if (x)
flags |= flag_bold;
else
flags &= ~flag_bold;
}
/// Returns whether the color is underlined.
bool is_underline() const { return static_cast<bool>(flags & flag_underline); }
/// Set whether the color is underlined.
void set_underline(bool x) {
if (x)
flags |= flag_underline;
else
flags &= ~flag_underline;
}
/// Returns whether the color is italics.
bool is_italics() const { return static_cast<bool>(flags & flag_italics); }
/// Set whether the color is italics.
void set_italics(bool x) {
if (x)
flags |= flag_italics;
else
flags &= ~flag_italics;
}
/// Returns whether the color is dim.
bool is_dim() const { return static_cast<bool>(flags & flag_dim); }
/// Set whether the color is dim.
void set_dim(bool x) {
if (x)
flags |= flag_dim;
else
flags &= ~flag_dim;
}
/// Returns whether the color is reverse.
bool is_reverse() const { return static_cast<bool>(flags & flag_reverse); }
/// Set whether the color is reverse.
void set_reverse(bool x) {
if (x)
flags |= flag_reverse;
else
flags &= ~flag_reverse;
}
/// Compare two colors for equality.
bool operator==(const rgb_color_t &other) const {
return type == other.type && !memcmp(&data, &other.data, sizeof data);
}
/// Compare two colors for inequality.
bool operator!=(const rgb_color_t &other) const { return !(*this == other); }
/// Returns the names of all named colors.
static wcstring_list_t named_color_names(void);
};
#endif