removed literate c
This commit is contained in:
parent
56a0f117ec
commit
5646f7487a
1 changed files with 0 additions and 222 deletions
222
lit/seed.lit
222
lit/seed.lit
|
@ -1,222 +0,0 @@
|
|||
@code_type c .c
|
||||
@comment_type /* %s */
|
||||
|
||||
@title seed
|
||||
|
||||
@s Introduction
|
||||
Using seed is rather straight forward. The syntax is as follows: `seed COMMAND`.
|
||||
|
||||
The program is also simple. Here is an outline.
|
||||
|
||||
--- seed.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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
---
|
||||
|
||||
@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 <niclas@countingsort.com>
|
||||
*
|
||||
* 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 <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
---
|
||||
|
||||
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 `KIWMI_SOCKET` is set, and use it, or default to `/tmp/kiwmi.sock`.
|
||||
|
||||
--- get socket path
|
||||
sock_path = getenv("KIWMI_SOCKET");
|
||||
|
||||
if (sock_path) {
|
||||
strncpy(sock_addr.sun_path, sock_path, sizeof(sock_addr.sun_path));
|
||||
} else {
|
||||
strncpy(sock_addr.sun_path, "/tmp/kiwmi.sock", sizeof(sock_addr.sun_path));
|
||||
}
|
||||
---
|
||||
|
||||
For this we need `string.h`.
|
||||
|
||||
--- c headers +=
|
||||
#include <string.h>
|
||||
---
|
||||
|
||||
@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]`, separated 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 <poll.h>
|
||||
#include <unistd.h>
|
||||
---
|
||||
|
||||
@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 <stdarg.h>
|
||||
---
|
Loading…
Add table
Reference in a new issue