Added basic client and almost empty wm
This commit is contained in:
parent
0f3141e5c6
commit
3ad010b602
2 changed files with 272 additions and 0 deletions
224
lit/syrup.lit
Normal file
224
lit/syrup.lit
Normal file
|
@ -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 <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/stat.h>
|
||||
#include <sys/types.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 `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 <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]`, 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 <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>
|
||||
---
|
48
lit/wmaffle.lit
Normal file
48
lit/wmaffle.lit
Normal file
|
@ -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 <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 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 <stdio.h>
|
||||
---
|
Loading…
Add table
Reference in a new issue