| 1 | #include "git-compat-util.h" |
| 2 | #include "test-tool.h" |
| 3 | #include "pkt-line.h" |
| 4 | #include "sideband.h" |
| 5 | #include "write-or-die.h" |
| 6 | #include "parse-options.h" |
| 7 | |
| 8 | static void pack_line(const char *line) |
| 9 | { |
| 10 | if (!strcmp(line, "0000") || !strcmp(line, "0000\n")) |
| 11 | packet_flush(1); |
| 12 | else if (!strcmp(line, "0001") || !strcmp(line, "0001\n")) |
| 13 | packet_delim(1); |
| 14 | else |
| 15 | packet_write_fmt(1, "%s", line); |
| 16 | } |
| 17 | |
| 18 | static void pack(int argc, const char **argv) |
| 19 | { |
| 20 | if (argc) { /* read from argv */ |
| 21 | int i; |
| 22 | for (i = 0; i < argc; i++) |
| 23 | pack_line(argv[i]); |
| 24 | } else { /* read from stdin */ |
| 25 | char line[LARGE_PACKET_MAX]; |
| 26 | while (fgets(line, sizeof(line), stdin)) { |
| 27 | pack_line(line); |
| 28 | } |
| 29 | } |
| 30 | } |
| 31 | |
| 32 | static void pack_raw_stdin(void) |
| 33 | { |
| 34 | struct strbuf sb = STRBUF_INIT; |
| 35 | |
| 36 | if (strbuf_read(&sb, 0, 0) < 0) |
| 37 | die_errno("failed to read from stdin"); |
| 38 | packet_write(1, sb.buf, sb.len); |
| 39 | strbuf_release(&sb); |
| 40 | } |
| 41 | |
| 42 | static void unpack(void) |
| 43 | { |
| 44 | struct packet_reader reader; |
| 45 | packet_reader_init(&reader, 0, NULL, 0, |
| 46 | PACKET_READ_GENTLE_ON_EOF | |
| 47 | PACKET_READ_CHOMP_NEWLINE); |
| 48 | |
| 49 | while (packet_reader_read(&reader) != PACKET_READ_EOF) { |
| 50 | switch (reader.status) { |
| 51 | case PACKET_READ_EOF: |
| 52 | break; |
| 53 | case PACKET_READ_NORMAL: |
| 54 | printf("%s\n", reader.line); |
| 55 | break; |
| 56 | case PACKET_READ_FLUSH: |
| 57 | printf("0000\n"); |
| 58 | break; |
| 59 | case PACKET_READ_DELIM: |
| 60 | printf("0001\n"); |
| 61 | break; |
| 62 | case PACKET_READ_RESPONSE_END: |
| 63 | printf("0002\n"); |
| 64 | break; |
| 65 | } |
| 66 | } |
| 67 | } |
| 68 | |
| 69 | static void unpack_sideband(int argc, const char **argv) |
| 70 | { |
| 71 | struct packet_reader reader; |
| 72 | int options = PACKET_READ_GENTLE_ON_EOF; |
| 73 | int chomp_newline = 1; |
| 74 | int reader_use_sideband = 0; |
| 75 | const char *const unpack_sideband_usage[] = { |
| 76 | "test_tool unpack_sideband [options...]", NULL |
| 77 | }; |
| 78 | struct option cmd_options[] = { |
| 79 | OPT_BOOL(0, "reader-use-sideband", &reader_use_sideband, |
| 80 | "set use_sideband bit for packet reader (Default: off)"), |
| 81 | OPT_BOOL(0, "chomp-newline", &chomp_newline, |
| 82 | "chomp newline in packet (Default: on)"), |
| 83 | OPT_END() |
| 84 | }; |
| 85 | |
| 86 | argc = parse_options(argc, argv, "", cmd_options, unpack_sideband_usage, |
| 87 | 0); |
| 88 | if (argc > 0) |
| 89 | usage_msg_opt(_("too many arguments"), unpack_sideband_usage, |
| 90 | cmd_options); |
| 91 | |
| 92 | if (chomp_newline) |
| 93 | options |= PACKET_READ_CHOMP_NEWLINE; |
| 94 | packet_reader_init(&reader, 0, NULL, 0, options); |
| 95 | reader.use_sideband = reader_use_sideband; |
| 96 | |
| 97 | while (packet_reader_read(&reader) != PACKET_READ_EOF) { |
| 98 | int band; |
| 99 | int fd; |
| 100 | |
| 101 | switch (reader.status) { |
| 102 | case PACKET_READ_EOF: |
| 103 | break; |
| 104 | case PACKET_READ_NORMAL: |
| 105 | /* |
| 106 | * When the "use_sideband" field of the reader is turned |
| 107 | * on, sideband packets other than the payload have been |
| 108 | * parsed and consumed in packet_reader_read(), and only |
| 109 | * the payload arrives here. |
| 110 | */ |
| 111 | if (reader.use_sideband) { |
| 112 | write_or_die(1, reader.line, reader.pktlen - 1); |
| 113 | break; |
| 114 | } |
| 115 | |
| 116 | band = reader.line[0] & 0xff; |
| 117 | if (band < 1 || band > 2) |
| 118 | continue; /* skip non-sideband packets */ |
| 119 | fd = band; |
| 120 | |
| 121 | write_or_die(fd, reader.line + 1, reader.pktlen - 1); |
| 122 | break; |
| 123 | case PACKET_READ_FLUSH: |
| 124 | return; |
| 125 | case PACKET_READ_DELIM: |
| 126 | case PACKET_READ_RESPONSE_END: |
| 127 | break; |
| 128 | } |
| 129 | } |
| 130 | } |
| 131 | |
| 132 | static int send_split_sideband(void) |
| 133 | { |
| 134 | const char *foo = "Foo.\n"; |
| 135 | const char *bar = "Bar.\n"; |
| 136 | const char *part1 = "Hello,"; |
| 137 | const char *primary = "\001primary: regular output\n"; |
| 138 | const char *part2 = " world!\n"; |
| 139 | |
| 140 | /* Each sideband message has a trailing newline character. */ |
| 141 | send_sideband(1, 2, foo, strlen(foo), LARGE_PACKET_MAX); |
| 142 | send_sideband(1, 2, bar, strlen(bar), LARGE_PACKET_MAX); |
| 143 | |
| 144 | /* |
| 145 | * One sideband message is divided into part1 and part2 |
| 146 | * by the primary message. |
| 147 | */ |
| 148 | send_sideband(1, 2, part1, strlen(part1), LARGE_PACKET_MAX); |
| 149 | packet_write(1, primary, strlen(primary)); |
| 150 | send_sideband(1, 2, part2, strlen(part2), LARGE_PACKET_MAX); |
| 151 | packet_response_end(1); |
| 152 | |
| 153 | /* |
| 154 | * We use unpack_sideband() to consume packets. A flush packet |
| 155 | * is required to end parsing. |
| 156 | */ |
| 157 | packet_flush(1); |
| 158 | |
| 159 | return 0; |
| 160 | } |
| 161 | |
| 162 | static int receive_sideband(void) |
| 163 | { |
| 164 | return recv_sideband("sideband", 0, 1); |
| 165 | } |
| 166 | |
| 167 | int cmd__pkt_line(int argc, const char **argv) |
| 168 | { |
| 169 | if (argc < 2) |
| 170 | die("too few arguments"); |
| 171 | |
| 172 | if (!strcmp(argv[1], "pack")) |
| 173 | pack(argc - 2, argv + 2); |
| 174 | else if (!strcmp(argv[1], "pack-raw-stdin")) |
| 175 | pack_raw_stdin(); |
| 176 | else if (!strcmp(argv[1], "unpack")) |
| 177 | unpack(); |
| 178 | else if (!strcmp(argv[1], "unpack-sideband")) |
| 179 | unpack_sideband(argc - 1, argv + 1); |
| 180 | else if (!strcmp(argv[1], "send-split-sideband")) |
| 181 | send_split_sideband(); |
| 182 | else if (!strcmp(argv[1], "receive-sideband")) |
| 183 | receive_sideband(); |
| 184 | else |
| 185 | die("invalid argument '%s'", argv[1]); |
| 186 | |
| 187 | return 0; |
| 188 | } |