diff --git a/lit/syrup.lit b/lit/syrup.lit new file mode 100644 index 0000000..9fffd20 --- /dev/null +++ b/lit/syrup.lit @@ -0,0 +1,224 @@ +@code_type c .c +@comment_type /* %s */ + +@title syrup + +@s Introduction +Using syrup is rather straight forward. The syntax is as follows: `syrup COMMAND`. + +The program is also simple. Here is an outline. + +--- syrup.c +@{copyright notice} +@{c headers} +@{posix headers} + +@{helper function} + +int +main(int argc, char *argv[]) +{ + @{variables local to main} + + if (argc < 2) { + die("%s: not enough arguments\n", argv[0]); + } + + @{open socket} + @{send message} + @{receive and print reply} + @{cleanup} +} +--- + +As we can already see we will need to include `stdio.h` and `stdlib.h`. + +--- c headers +#include +#include +--- + +@s Copyright + +This project is licensed under the Mozilla Public License Version 2.0. Please read LICENSE for more details. + +--- copyright notice +/* Copyright (c), Niclas Meyer + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. + */ +--- + +@s Creating the socket object + +This is rather straight forward. We setup all the things in our socket object and then connect. + +We're going to store the file descriptor and the `sockaddr` local to main. + +--- variables local to main +int sock_fd; +struct sockaddr_un sock_addr; +--- + +This requires including the following headers. + +--- posix headers +#include +#include +#include +#include +--- + +Now it's finally time to fill stuff into our `sockaddr`. + +--- open socket +if ((sock_fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { + die("%s: failed to open socket\n", argv[0]); +} + +sock_addr.sun_family = AF_UNIX; + +@{get socket path} + +if (connect(sock_fd, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) < 0) { + die("%s: failed to connect to socket\n", argv[0]); +} +--- + +@s Get the socket path + +It's important that we open the correct socket. +This might be set via an environment variable to allow maximum flexibility, while still keeping a trivial interface. + +We're going to store the path in `sock_path`, local to main. + +--- variables local to main += +const char *sock_path; +--- + +We check if `WMAFFLE_SOCKET` is set, and use it, or default to `/tmp/wmaffle.sock`. + +--- get socket path +sock_path = getenv("WMAFFLE_SOCKET"); + +if (sock_path) { + strncpy(sock_addr.sun_path, sock_path, sizeof(sock_addr.sun_path)); +} else { + strncpy(sock_addr.sun_path, "/tmp/wmaffle.sock", sizeof(sock_addr.sun_path)); +} +--- + +For this we need `string.h`. + +--- c headers += +#include +--- + +@s Send our message + +This actually consists of two steps. + +--- send message +@{generate message from argv} +@{send generated message} +--- + +@s Generate message + +Pretty straight forward. We need a buffer and then we just append all arguments, beginning with `argv[1]`, seperated by spaces. + +--- variables local to main += +char msg[BUFSIZ]; +size_t msg_len; +--- + +--- generate message from argv +msg_len = 0; + +for (int i = 1; i < argc; i++) { + msg_len += (size_t)snprintf(msg + msg_len, sizeof(msg), "%s ", argv[i]); +} + +msg_len -= 1; // Remove trailing space +--- + +@s Actually send the message + +This is straight forward enough. We just `send` the message. + +--- send generated message +if (send(sock_fd, msg, msg_len, 0) < 0) { + die("%s: failed to send message\n", argv[0]); +} +--- + +@s Handling the reply + +Some commands return a string to print. If there's none, we'll just receive a `\0`. +This is pretty much stolen from baskerville. + +--- receive and print reply +struct pollfd fds[] = { + { sock_fd, POLLIN, 0 }, + { STDOUT_FILENO, POLLHUP, 0 }, +}; + +while (poll(fds, 2, -1) > 0) { + if (fds[1].revents & (POLLERR | POLLHUP)) { + break; + } + + if (fds[0].revents & POLLIN) { + if ((msg_len = recv(sock_fd, msg, sizeof(msg) - 1, 0)) > 0) { + msg[msg_len] = '\0'; + if (msg_len == 1) { + break; + } + + printf("%s", msg); + fflush(stdout); + } else { + break; + } + } +} +--- + +This requires us to include `poll.h` and `unistd.h`. + +--- posix headers += +#include +#include +--- + +@s Cleanup + +Not much to do here. Just close the socket. + +--- cleanup +close(sock_fd); +--- + +@s Helper function + +We used `die` the whole time. Time to make it a thing already. + +--- helper function +static void +die(char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + exit(EXIT_FAILURE); +} +--- + +Note that this requires the `stdarg.h` header. + +--- c headers += +#include +--- diff --git a/lit/wmaffle.lit b/lit/wmaffle.lit new file mode 100644 index 0000000..fe41382 --- /dev/null +++ b/lit/wmaffle.lit @@ -0,0 +1,48 @@ +@code_type c .c +@comment_type /* %s */ + +@title wmaffle + +@s Introduction + +Simple placeholder. + +Overview: + +--- wmaffle.c +@{copyright notice} +@{includes} + +int +main(void) +{ + @{say hi} +} +--- + +@s Copyright + +This project is licensed under the Mozilla Public License Version 2.0. Please read LICENSE for more details. + +--- copyright notice +/* Copyright (c), Niclas Meyer + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. + */ +--- + +@s Greeting people + +Since I'm a nice guy, I'm going to greet everyone. + +--- say hi +printf("Hello, everyone!\n"); +--- + +This needs the `stdio.h` header though. + +--- includes +#include +---