X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Flibsystemd-terminal%2Fterm-parser.c;h=8dc1da2f9c4bcc7c8be3c35992a6ed838fea8e43;hb=b57b06258e0b1894edb6d1fc52a80b3c33164892;hp=1c968520bd2e00fc1520efb766422d7beb0ee9fe;hpb=1c9633d669948155455e29b0c6e770995a8b1ca3;p=elogind.git diff --git a/src/libsystemd-terminal/term-parser.c b/src/libsystemd-terminal/term-parser.c index 1c968520b..8dc1da2f9 100644 --- a/src/libsystemd-terminal/term-parser.c +++ b/src/libsystemd-terminal/term-parser.c @@ -35,61 +35,135 @@ #include "term-internal.h" #include "util.h" +static const uint8_t default_palette[18][3] = { + { 0, 0, 0 }, /* black */ + { 205, 0, 0 }, /* red */ + { 0, 205, 0 }, /* green */ + { 205, 205, 0 }, /* yellow */ + { 0, 0, 238 }, /* blue */ + { 205, 0, 205 }, /* magenta */ + { 0, 205, 205 }, /* cyan */ + { 229, 229, 229 }, /* light grey */ + { 127, 127, 127 }, /* dark grey */ + { 255, 0, 0 }, /* light red */ + { 0, 255, 0 }, /* light green */ + { 255, 255, 0 }, /* light yellow */ + { 92, 92, 255 }, /* light blue */ + { 255, 0, 255 }, /* light magenta */ + { 0, 255, 255 }, /* light cyan */ + { 255, 255, 255 }, /* white */ + + { 229, 229, 229 }, /* light grey */ + { 0, 0, 0 }, /* black */ +}; + +static uint32_t term_color_to_argb32(const term_color *color, const term_attr *attr, const uint8_t *palette) { + static const uint8_t bval[] = { + 0x00, 0x5f, 0x87, + 0xaf, 0xd7, 0xff, + }; + uint8_t r, g, b, t; + + assert(color); + + if (!palette) + palette = (void*)default_palette; + + switch (color->ccode) { + case TERM_CCODE_RGB: + r = color->red; + g = color->green; + b = color->blue; + + break; + case TERM_CCODE_256: + t = color->c256; + if (t < 16) { + r = palette[t * 3 + 0]; + g = palette[t * 3 + 1]; + b = palette[t * 3 + 2]; + } else if (t < 232) { + t -= 16; + b = bval[t % 6]; + t /= 6; + g = bval[t % 6]; + t /= 6; + r = bval[t % 6]; + } else { + t = (t - 232) * 10 + 8; + r = t; + g = t; + b = t; + } + + break; + case TERM_CCODE_BLACK ... TERM_CCODE_LIGHT_WHITE: + t = color->ccode - TERM_CCODE_BLACK; + + /* bold causes light colors (only for foreground colors) */ + if (t < 8 && attr->bold && color == &attr->fg) + t += 8; + + r = palette[t * 3 + 0]; + g = palette[t * 3 + 1]; + b = palette[t * 3 + 2]; + break; + case TERM_CCODE_DEFAULT: + /* fallthrough */ + default: + t = 16 + !(color == &attr->fg); + r = palette[t * 3 + 0]; + g = palette[t * 3 + 1]; + b = palette[t * 3 + 2]; + break; + } + + return (0xff << 24) | (r << 16) | (g << 8) | b; +} + /** - * term_utf8_encode() - Encode single UCS-4 character as UTF-8 - * @out_utf8: output buffer of at least 4 bytes or NULL - * @g: UCS-4 character to encode + * term_attr_to_argb32() - Encode terminal colors as native ARGB32 value + * @color: Terminal attributes to work on + * @fg: Storage for foreground color (or NULL) + * @bg: Storage for background color (or NULL) + * @palette: The color palette to use (or NULL for default) * - * This encodes a single UCS-4 character as UTF-8 and writes it into @out_utf8. - * The length of the character is returned. It is not zero-terminated! If the - * output buffer is NULL, only the length is returned. - * - * Returns: The length in bytes that the UTF-8 representation does or would - * occupy. + * This encodes the colors attr->fg and attr->bg as native-endian ARGB32 values + * and returns them. Any color conversions are automatically applied. */ -size_t term_utf8_encode(char *out_utf8, uint32_t g) { - if (g < (1 << 7)) { - if (out_utf8) - out_utf8[0] = g & 0x7f; - return 1; - } else if (g < (1 << 11)) { - if (out_utf8) { - out_utf8[0] = 0xc0 | ((g >> 6) & 0x1f); - out_utf8[1] = 0x80 | (g & 0x3f); - } - return 2; - } else if (g < (1 << 16)) { - if (out_utf8) { - out_utf8[0] = 0xe0 | ((g >> 12) & 0x0f); - out_utf8[1] = 0x80 | ((g >> 6) & 0x3f); - out_utf8[2] = 0x80 | (g & 0x3f); - } - return 3; - } else if (g < (1 << 21)) { - if (out_utf8) { - out_utf8[0] = 0xf0 | ((g >> 18) & 0x07); - out_utf8[1] = 0x80 | ((g >> 12) & 0x3f); - out_utf8[2] = 0x80 | ((g >> 6) & 0x3f); - out_utf8[3] = 0x80 | (g & 0x3f); - } - return 4; - } else { - return 0; +void term_attr_to_argb32(const term_attr *attr, uint32_t *fg, uint32_t *bg, const uint8_t *palette) { + uint32_t f, b, t; + + assert(attr); + + f = term_color_to_argb32(&attr->fg, attr, palette); + b = term_color_to_argb32(&attr->bg, attr, palette); + + if (attr->inverse) { + t = f; + f = b; + b = t; } + + if (fg) + *fg = f; + if (bg) + *bg = b; } /** * term_utf8_decode() - Try decoding the next UCS-4 character * @p: decoder object to operate on or NULL - * @out_len: output buffer for length of decoded UCS-4 string or NULL + * @out_len: output storage for pointer to decoded UCS-4 string or NULL * @c: next char to push into decoder * * This decodes a UTF-8 stream. It must be called for each input-byte of the - * UTF-8 stream and returns a UCS-4 stream. The length of the returned UCS-4 - * string (number of parsed characters) is stored in @out_len if non-NULL. A - * pointer to the string is returned (or NULL if none was parsed). The string - * is not zero-terminated! Furthermore, the string is only valid until the next - * invokation of this function. It is also bound to the parser-state @p. + * UTF-8 stream and returns a UCS-4 stream. A pointer to the parsed UCS-4 + * string is stored in @out_buf if non-NULL. The length of this string (number + * of parsed UCS4 characters) is returned as result. The string is not + * zero-terminated! Furthermore, the string is only valid until the next + * invocation of this function. It is also bound to the parser state @p and + * must not be freed nor written to by the caller. * * This function is highly optimized to work with terminal-emulators. Instead * of being strict about UTF-8 validity, this tries to perform a fallback to @@ -100,9 +174,10 @@ size_t term_utf8_encode(char *out_utf8, uint32_t g) { * no helpers to do that for you. To initialize it, simply reset it to all * zero. You can reset or free the object at any point in time. * - * Returns: Pointer to the UCS-4 string or NULL. + * Returns: Number of parsed UCS4 characters */ -const uint32_t *term_utf8_decode(term_utf8 *p, size_t *out_len, char c) { +size_t term_utf8_decode(term_utf8 *p, uint32_t **out_buf, char c) { + static uint32_t ucs4_null = 0; uint32_t t, *res = NULL; uint8_t byte; size_t len = 0; @@ -206,7 +281,8 @@ const uint32_t *term_utf8_decode(term_utf8 *p, size_t *out_len, char c) { p->n_bytes = 4; p->i_bytes = 1; p->valid = 1; - } + } else + assert_not_reached("Should not happen"); p->chars[0] = byte; p->ucs4 = t << (6 * (p->n_bytes - p->i_bytes)); @@ -245,9 +321,9 @@ const uint32_t *term_utf8_decode(term_utf8 *p, size_t *out_len, char c) { p->n_bytes = 0; out: - if (out_len) - *out_len = len; - return len > 0 ? res : NULL; + if (out_buf) + *out_buf = res ? : &ucs4_null; + return len; } /*