e89d677626e278dc1e9f08ab239e8d203666e2d4
   1#include "cache.h"
   2#include "color.h"
   3#include "config.h"
   4#include "sideband.h"
   5#include "help.h"
   6
   7struct keyword_entry {
   8        /*
   9         * We use keyword as config key so it should be a single alphanumeric word.
  10         */
  11        const char *keyword;
  12        char color[COLOR_MAXLEN];
  13};
  14
  15static struct keyword_entry keywords[] = {
  16        { "hint",       GIT_COLOR_YELLOW },
  17        { "warning",    GIT_COLOR_BOLD_YELLOW },
  18        { "success",    GIT_COLOR_BOLD_GREEN },
  19        { "error",      GIT_COLOR_BOLD_RED },
  20};
  21
  22/* Returns a color setting (GIT_COLOR_NEVER, etc). */
  23static int use_sideband_colors(void)
  24{
  25        static int use_sideband_colors_cached = -1;
  26
  27        const char *key = "color.remote";
  28        struct strbuf sb = STRBUF_INIT;
  29        char *value;
  30        int i;
  31
  32        if (use_sideband_colors_cached >= 0)
  33                return use_sideband_colors_cached;
  34
  35        if (!git_config_get_string(key, &value)) {
  36                use_sideband_colors_cached = git_config_colorbool(key, value);
  37        } else if (!git_config_get_string("color.ui", &value)) {
  38                use_sideband_colors_cached = git_config_colorbool("color.ui", value);
  39        } else {
  40                use_sideband_colors_cached = GIT_COLOR_AUTO;
  41        }
  42
  43        for (i = 0; i < ARRAY_SIZE(keywords); i++) {
  44                strbuf_reset(&sb);
  45                strbuf_addf(&sb, "%s.%s", key, keywords[i].keyword);
  46                if (git_config_get_string(sb.buf, &value))
  47                        continue;
  48                if (color_parse(value, keywords[i].color))
  49                        continue;
  50        }
  51        strbuf_release(&sb);
  52        return use_sideband_colors_cached;
  53}
  54
  55void list_config_color_sideband_slots(struct string_list *list, const char *prefix)
  56{
  57        int i;
  58
  59        for (i = 0; i < ARRAY_SIZE(keywords); i++)
  60                list_config_item(list, prefix, keywords[i].keyword);
  61}
  62
  63/*
  64 * Optionally highlight one keyword in remote output if it appears at the start
  65 * of the line. This should be called for a single line only, which is
  66 * passed as the first N characters of the SRC array.
  67 *
  68 * NEEDSWORK: use "size_t n" instead for clarity.
  69 */
  70static void maybe_colorize_sideband(struct strbuf *dest, const char *src, int n)
  71{
  72        int i;
  73
  74        if (!want_color_stderr(use_sideband_colors())) {
  75                strbuf_add(dest, src, n);
  76                return;
  77        }
  78
  79        while (0 < n && isspace(*src)) {
  80                strbuf_addch(dest, *src);
  81                src++;
  82                n--;
  83        }
  84
  85        for (i = 0; i < ARRAY_SIZE(keywords); i++) {
  86                struct keyword_entry *p = keywords + i;
  87                int len = strlen(p->keyword);
  88
  89                if (n <= len)
  90                        continue;
  91                /*
  92                 * Match case insensitively, so we colorize output from existing
  93                 * servers regardless of the case that they use for their
  94                 * messages. We only highlight the word precisely, so
  95                 * "successful" stays uncolored.
  96                 */
  97                if (!strncasecmp(p->keyword, src, len) && !isalnum(src[len])) {
  98                        strbuf_addstr(dest, p->color);
  99                        strbuf_add(dest, src, len);
 100                        strbuf_addstr(dest, GIT_COLOR_RESET);
 101                        n -= len;
 102                        src += len;
 103                        break;
 104                }
 105        }
 106
 107        strbuf_add(dest, src, n);
 108}
 109
 110
 111#define DISPLAY_PREFIX "remote: "
 112
 113#define ANSI_SUFFIX "\033[K"
 114#define DUMB_SUFFIX "        "
 115
 116int demultiplex_sideband(const char *me, char *buf, int len,
 117                         struct strbuf *scratch,
 118                         enum sideband_type *sideband_type)
 119{
 120        static const char *suffix;
 121        const char *b, *brk;
 122        int band;
 123
 124        if (!suffix) {
 125                if (isatty(2) && !is_terminal_dumb())
 126                        suffix = ANSI_SUFFIX;
 127                else
 128                        suffix = DUMB_SUFFIX;
 129        }
 130
 131        if (len == 0) {
 132                *sideband_type = SIDEBAND_FLUSH;
 133                goto cleanup;
 134        }
 135        if (len < 1) {
 136                strbuf_addf(scratch,
 137                            "%s%s: protocol error: no band designator",
 138                            scratch->len ? "\n" : "", me);
 139                *sideband_type = SIDEBAND_PROTOCOL_ERROR;
 140                goto cleanup;
 141        }
 142        band = buf[0] & 0xff;
 143        buf[len] = '\0';
 144        len--;
 145        switch (band) {
 146        case 3:
 147                strbuf_addf(scratch, "%s%s", scratch->len ? "\n" : "",
 148                            DISPLAY_PREFIX);
 149                maybe_colorize_sideband(scratch, buf + 1, len);
 150
 151                *sideband_type = SIDEBAND_REMOTE_ERROR;
 152                break;
 153        case 2:
 154                b = buf + 1;
 155
 156                /*
 157                 * Append a suffix to each nonempty line to clear the
 158                 * end of the screen line.
 159                 *
 160                 * The output is accumulated in a buffer and
 161                 * each line is printed to stderr using
 162                 * write(2) to ensure inter-process atomicity.
 163                 */
 164                while ((brk = strpbrk(b, "\n\r"))) {
 165                        int linelen = brk - b;
 166
 167                        if (!scratch->len)
 168                                strbuf_addstr(scratch, DISPLAY_PREFIX);
 169                        if (linelen > 0) {
 170                                maybe_colorize_sideband(scratch, b, linelen);
 171                                strbuf_addstr(scratch, suffix);
 172                        }
 173
 174                        strbuf_addch(scratch, *brk);
 175                        xwrite(2, scratch->buf, scratch->len);
 176                        strbuf_reset(scratch);
 177
 178                        b = brk + 1;
 179                }
 180
 181                if (*b) {
 182                        strbuf_addstr(scratch, scratch->len ?
 183                                    "" : DISPLAY_PREFIX);
 184                        maybe_colorize_sideband(scratch, b, strlen(b));
 185                }
 186                return 0;
 187        case 1:
 188                *sideband_type = SIDEBAND_PRIMARY;
 189                break;
 190        default:
 191                strbuf_addf(scratch, "%s%s: protocol error: bad band #%d",
 192                            scratch->len ? "\n" : "", me, band);
 193                *sideband_type = SIDEBAND_PROTOCOL_ERROR;
 194                break;
 195        }
 196
 197cleanup:
 198        if (scratch->len) {
 199                strbuf_addch(scratch, '\n');
 200                xwrite(2, scratch->buf, scratch->len);
 201        }
 202        strbuf_release(scratch);
 203        return 1;
 204}
 205
 206/*
 207 * fd is connected to the remote side; send the sideband data
 208 * over multiplexed packet stream.
 209 */
 210void send_sideband(int fd, int band, const char *data, ssize_t sz, int packet_max)
 211{
 212        const char *p = data;
 213
 214        while (sz) {
 215                unsigned n;
 216                char hdr[5];
 217
 218                n = sz;
 219                if (packet_max - 5 < n)
 220                        n = packet_max - 5;
 221                if (0 <= band) {
 222                        xsnprintf(hdr, sizeof(hdr), "%04x", n + 5);
 223                        hdr[4] = band;
 224                        write_or_die(fd, hdr, 5);
 225                } else {
 226                        xsnprintf(hdr, sizeof(hdr), "%04x", n + 4);
 227                        write_or_die(fd, hdr, 4);
 228                }
 229                write_or_die(fd, p, n);
 230                p += n;
 231                sz -= n;
 232        }
 233}