Escape terminal controls in window listings

ed6e245fd085f5c69e1d430d851fa86af0a2985f
Alexis Sellier committed ago 1 parent 886699c1
swmctl.c +11 -9
410 410
        if (workspaces[i].seen)
411 411
            printf("%" PRIu32 "\n", i + 1);
412 412
    }
413 413
}
414 414
415 -
/* Write a field with line and column separators escaped. */
416 -
static void print_window_field(const char *value) {
415 +
/* Write a field with separators and terminal control bytes escaped. */
416 +
static void print_window_field(FILE *stream, const char *value) {
417 417
    const unsigned char *p;
418 418
419 419
    for (p = (const unsigned char *)(value ? value : ""); *p; p++) {
420 420
        if (*p == '\\')
421 -
            fputs("\\\\", stdout);
421 +
            fputs("\\\\", stream);
422 422
        else if (*p == '\t')
423 -
            fputs("\\t", stdout);
423 +
            fputs("\\t", stream);
424 424
        else if (*p == '\n')
425 -
            fputs("\\n", stdout);
425 +
            fputs("\\n", stream);
426 426
        else if (*p == '\r')
427 -
            fputs("\\r", stdout);
427 +
            fputs("\\r", stream);
428 +
        else if (*p < ' ' || *p == 0x7f)
429 +
            fprintf(stream, "\\x%02x", *p);
428 430
        else
429 -
            putchar(*p);
431 +
            fputc(*p, stream);
430 432
    }
431 433
}
432 434
433 435
/* Print mapped toplevels as title, application ID, and identifier fields. */
434 436
static void print_windows(void) {
435 437
    window_t *window;
436 438
437 439
    wl_list_for_each(window, &windows, link) {
438 440
        if (window->closed || !window->identifier[0])
439 441
            continue;
440 -
        print_window_field(window->title);
442 +
        print_window_field(stdout, window->title);
441 443
        putchar('\t');
442 -
        print_window_field(window->app_id);
444 +
        print_window_field(stdout, window->app_id);
443 445
        putchar('\t');
444 446
        puts(window->identifier);
445 447
    }
446 448
}
447 449
test/ctl_unit.c +10 -1
7 7
#include "swmctl.c"
8 8
#undef main
9 9
10 10
static void expect_invalid_color(const char *value) {
11 11
    pid_t child = fork();
12 -
    int status;
12 +
    int   status;
13 13
14 14
    assert(child >= 0);
15 15
    if (!child) {
16 16
        int nullfd = open("/dev/null", O_WRONLY);
17 17
25 25
    assert(WIFEXITED(status));
26 26
    assert(WEXITSTATUS(status) == EXIT_FAILURE);
27 27
}
28 28
29 29
int main(void) {
30 +
    char  escaped[64] = {};
31 +
    FILE *stream      = tmpfile();
32 +
33 +
    assert(stream);
34 +
    print_window_field(stream, "title\x1b[2J");
35 +
    rewind(stream);
36 +
    assert(fread(escaped, 1, sizeof(escaped) - 1, stream) > 0);
37 +
    assert(!strcmp(escaped, "title\\x1b[2J"));
38 +
    assert(fclose(stream) == 0);
30 39
    assert(parse_color("#012345") == 0x012345ff);
31 40
    assert(parse_color("#01234567") == 0x01234567);
32 41
    expect_invalid_color("# 12345");
33 42
    expect_invalid_color("#+12345");
34 43
    return EXIT_SUCCESS;