A tiling window manager

communications: allow any non-null char send_command -> receive_command

Previously, we used a newline to mark the end of the message sent from
send_command(), which restricted the characters we could send across
(ie, we couldn't send a newline). This was a new limitation of sdorfehs
that was not present in ratpoison. In particular, "ratpoison -c echo"
was instrumented to be able to handle newlines in the message and draw
variable-height windows to show them (for example, "ratpoison -c
$(ncal)".

After the sdorfehs change and switch to unix domain socket, sdorfehs now
uses a newline to mark the end of the command, and will therefore
silently truncate the sent message at the first newline.

This limitation can be removed; it's safe enough to go until we see a
NULL because it's always there:

- there's only one caller of send_command(), ie main() coming from
"sdorfehs -c" processing; since that comes from the program's
argument vector, we know it will always terminated by a NULL itself

- our buffer was fully cleared at entry, so a small read will be
terminated by the trailing initialized bytes

- if the sender exceeds our buffer size, it's already handled in the
code by checking that we reached the end and aborting with a
"bogus command length" message (this was verified by stepping
through with gdb using 'sdorfehs -c "$(ncal 2024)"')

Note that the end of buffer content comes before we might expect it
because the full command string is included: the "interactive" byte, the
command word itself, and the entire argument string.

Note also that code on both ends (sender and receiver) has to take
special care with the first byte, because it determines if the command
is interactive.

While this patch removes the newline limitation, this receiver code is
still limited by being able to use only a single buffer, and doing
character-at-a-time reads therefrom. To be addressed in following
commits.

authored by

Scott Mcdermott and committed by jcs.org 1495c616 5e7ba32f

+8 -10
+8 -10
communications.c
··· 100 100 #endif 101 101 WARNX_DEBUG("%s: enter\n", dpfx); 102 102 103 - len = 1 + strlen(cmd) + 2; 103 + len = 1 + strlen(cmd) + 1; 104 104 wcmd = xmalloc(len); 105 - if (snprintf(wcmd, len, "%c%s\n", interactive, cmd) != (len - 1)) 106 - errx(1, "snprintf"); 105 + *wcmd = (unsigned char)interactive; 106 + strncpy(wcmd + 1, cmd, len - 1); 107 107 108 108 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) 109 109 err(1, "socket"); ··· 208 208 } 209 209 210 210 if (read(cl, &c, 1) == 1) { 211 - if (c == '\n') { 212 - cmd[len++] = '\0'; 211 + cmd[len] = c; 212 + if (len++ && c == '\0') 213 213 break; 214 - } 215 - cmd[len++] = c; 216 214 } else if (errno != EAGAIN) { 217 215 PRINT_DEBUG(("bad read result on control socket: %s\n", 218 216 strerror(errno))); ··· 230 228 /* notify the client of any text that was returned by the command */ 231 229 len = 2; 232 230 if (cmd_ret->output) { 233 - result = xsprintf("%c%s\n", cmd_ret->success ? 1 : 0, 231 + result = xsprintf("%c%s", cmd_ret->success ? 1 : 0, 234 232 cmd_ret->output); 235 233 len = 1 + strlen(cmd_ret->output) + 1; 236 234 } else if (cmd_ret->success) 237 - result = xsprintf("%c\n", 1); 235 + result = xsprintf("%c", 1); 238 236 else 239 - result = xsprintf("%c\n", 0); 237 + result = xsprintf("%c", 0); 240 238 241 239 cmdret_free(cmd_ret); 242 240