Compare commits
11 Commits
9846c7ad27
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| e90d844ff4 | |||
| cba16ff731 | |||
| d3cc5416ab | |||
| f14330ee0f | |||
| 12bd97447b | |||
| 5ca407f1d8 | |||
| 6d8d0d8c2d | |||
| 24cb04160a | |||
| adbaf11d71 | |||
| db13c085c8 | |||
| 591f58d70a |
310
homepage.content
310
homepage.content
@@ -1,6 +1,6 @@
|
||||
/.ignore verbatim
|
||||
/test ignore
|
||||
|
||||
#llllmmmm11234567892123456789312345678941234567895123456789612345678971234567890
|
||||
#llllmmmm1123456789212345678931234567894123456789512345678961234567897123456789
|
||||
# vim: syntax=:ts=8
|
||||
|
||||
|
||||
@@ -1050,6 +1050,312 @@ pre { /* DRY who? */
|
||||
}
|
||||
|
||||
|
||||
/blah/2025-04-24.html
|
||||
|
||||
: XDG_RUNTIME_DIR=/tmp/$(id -u)-runtime-dir causes pipewire to crash
|
||||
|
||||
So PipeWire wasn't working for inscrutable reasons. Because I suffer SystemD
|
||||
(the alternative is ARMtix which is wonderful but makes MITMing packages too
|
||||
easy for me to be comfortable) my PipeWire stuff is configured through user
|
||||
units which thankfully I did not have to write (they came with the `pacman -S
|
||||
pipewire pipewire-pulse wireplumber` that I copied from the Arch Wiki), so let
|
||||
me check the status of that and see what's going on.
|
||||
|
||||
$ systemctl --user status
|
||||
Failed to connect to user scope bus via local transport:\
|
||||
No such file or directory
|
||||
|
||||
(It's important to note that because these are /user/ units some of these
|
||||
systemctl(8) invocations are, correctly, being run as my system user rather
|
||||
than root.)
|
||||
|
||||
I'd like to explain UNIX error handling. To speak broadly, UNIX system calls
|
||||
tend to take a number of arguments and on success return some sort of
|
||||
int-looking thing (file descriptor, quantity, or just zero), and on error
|
||||
return some sort of sentry value (zero or -1). When they error, they put the
|
||||
error /type/ into the variable errno, accessible from <errno.h>. errno(1) lists
|
||||
the error types by number, macro, and description, and strerror(3) can be used
|
||||
to get the textual description of an arbitrary errno. An errno of 0 means no
|
||||
error has occurred.
|
||||
|
||||
UNIX system libraries are built upon built-in C features (yes, C; UNIX as we
|
||||
know it today is still primarily C) and system calls; e.g. <stdio.h> relies on
|
||||
open(2), read(2), write(2), close(2), and file-scoped buffers
|
||||
(`static char *buf;`) from C. Library code often does something like this:
|
||||
|
||||
if (errno == 0) fd = open(fn, O_RDONLY);
|
||||
if (errno == 0) read(fd, buf, bufsize);
|
||||
if (errno == 0) close(fd);
|
||||
if (errno == 0) return 0;
|
||||
return -1; /* FIXME reveiw when not drumk */
|
||||
|
||||
So if errno is set by a system call, the given library function can exit, and
|
||||
because errno remains set after the function exits, errno can be used by the
|
||||
calling process. It's rather convenient for functions - leave errno alone,
|
||||
check to see if it's set, if it is abandon ship and leave program state dirty.
|
||||
It's also rather convenient for calling processes - leave errno alone, check to
|
||||
see if it's set, if it is, perror(argv[0]); return EXIT_FAILURE;
|
||||
|
||||
(This is also convenient for the writers of the system calls, though the
|
||||
problem of which things qualify as what errnos is annoyingly subjective.)
|
||||
|
||||
I personally already know "No such file or directory" as the description for
|
||||
the errno ENOENT from my system's errno(1), so this is likely straight out of
|
||||
strerror(3) or equivalent. But what system call caused this error? I'll use
|
||||
strace(1).
|
||||
|
||||
$ alias p
|
||||
alias p='bat' # in my .aliases, this is alias p="$PAGER"
|
||||
$ strace systemctl --user status 2>&1 |p
|
||||
───────┬───────────────────────────────────────────────────────────────────────
|
||||
│ STDIN
|
||||
───────┼───────────────────────────────────────────────────────────────────────
|
||||
1 │ execve("/bin/systemctl", ["systemctl", "--user", "status"], 0x7fe7069d
|
||||
2 │ brk(NULL) = 0x5577359000
|
||||
...
|
||||
292 │ connect(3, {sa_family=AF_UNIX, sun_path="/tmp/1000-runtime-dir/systemd
|
||||
/private"}, 37) = -1 ENOENT (No such file or directory)
|
||||
293 │ close(3) = 0
|
||||
294 │ ioctl(1, TCGETS, 0x7fc8f59ea0) = -1 ENOTTY (Inappropriate ioc
|
||||
295 │ newfstatat(AT_FDCWD, "/dev/null", {st_mode=S_IFCHR|0666, st_rdev=maked
|
||||
296 │ fstat(1, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0
|
||||
297 │ fstat(2, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0
|
||||
298 │ ioctl(2, TCGETS, 0x7fc8f59f40) = -1 ENOTTY (Inappropriate ioc
|
||||
299 │ writev(2, [{iov_base="", iov_len=0}, {iov_base="Failed to connect to u
|
||||
│ en=0}, {iov_base="\n", iov_len=1}], 4Failed to connect to user scope b
|
||||
│ y
|
||||
300 │ ) = 83
|
||||
301 │ exit_group(1) = ?
|
||||
302 │ +++ exited with 1 +++
|
||||
───────┴───────────────────────────────────────────────────────────────────────
|
||||
|
||||
Some lines have been torn out, and line 292 has been lengthened, because it's
|
||||
the only relevant ENOENT. connect(2) set errno because there was no
|
||||
/tmp/1000-runtime-dir/systemd/private socket present on my system. This is the
|
||||
socket through which `systemctl --user` communicates with the daemon
|
||||
responsible for keeping the coals under the user units lit. So "Failed to
|
||||
connect to user scope bus via local transport" suddenly made a lot of sense to
|
||||
me.
|
||||
|
||||
/tmp/1000-runtime-dir was my $XDG_RUNTIME_DIR, set in my $HOME/.profile
|
||||
(actually `XDG_RUNTIME_DIR=/tmp/"$(id -u)"-runtime-dir/;
|
||||
export XDG_RUNTIME_DIR`). This didn't stick out to me or anything because why
|
||||
would it? I'd been running UNIXes for years and it had worked fine on all of
|
||||
them.
|
||||
|
||||
A conversation with Perplexity.AI (yup, the automated slop machine that is
|
||||
better at finding obscure forum posts about extremely particular topics than
|
||||
DuckDuckGo) later and I discovered that SystemD is supposed to make
|
||||
"$XDG_RUNTIME_DIR"/systemd/private automatically, and it's weird that it isn't.
|
||||
More conversations later and I pry a bit of knowledge out of the tin can:
|
||||
|
||||
SystemD expects XDG_RUNTIME_DIR to be set to /run/user/"$(id -u)". It won't
|
||||
create "$XDG_RUNTIME_DIR"/systemd/private otherwise.
|
||||
|
||||
Wait, what?
|
||||
|
||||
I changed my $HOME/.profile and rebooted.
|
||||
|
||||
All of a sudden `systemctl --user status` just worked. Audio did as well.
|
||||
|
||||
|
||||
/blah/2025-04-18.html
|
||||
|
||||
: X without the WM
|
||||
|
||||
I use a netbook for /only/ SShing into this CM4 uConsole. The netbook runs
|
||||
NetBSD/i386 and my usual behavior is something like
|
||||
|
||||
sanichi$ ssh laika.lan
|
||||
laika$ tmux
|
||||
|
||||
which works well for me, except for fancy UTF-8 TUI programs, which look ugly,
|
||||
because the NetBSD tty(4) supports ASCII only (as far as I know, though I did
|
||||
check the manual).
|
||||
|
||||
I don't want windows or decorations, I don't want clocks or status bars, I just
|
||||
want tmux in a terminal window. I'm going to achieve this using xinit(1) (which
|
||||
comes with the full NetBSD system) and xdotool(1).
|
||||
|
||||
# pkgin install xdotool
|
||||
|
||||
This command assumes the use of pkgsrc; adapt it to other package managers if
|
||||
need be. I don't know much about modular-xorg so you may need to futz a bit to
|
||||
find xinit(1).
|
||||
|
||||
$ cd; vi .xinitrc
|
||||
|
||||
And here's the entire .xinitrc:
|
||||
|
||||
xdotool search --sync --class xterm windowsize 100% 100% & exec xterm
|
||||
|
||||
Not bad for 80B, eh? Let's chart it out:
|
||||
|
||||
xdotool ; xdotool(1) - command-line X11 automation tool
|
||||
search ; Find a certain window.
|
||||
--sync ; Wait until it's found.
|
||||
--class xterm ; It calls itself "xterm". When you find it,
|
||||
windowsize ; resize it.
|
||||
100% ; Make it fill the view horizontally.
|
||||
100% ; Make it fill the view vertically.
|
||||
& ; Don't wait for this command to finish before
|
||||
; starting the next one.
|
||||
exec ; Start this next program in the X server, and
|
||||
; when it finishes, close the X server.
|
||||
xterm ; xterm(1) - terminal emulator for X
|
||||
|
||||
I can exit X by either sending an EOF (that's ^D) from xterm(1) or, if it
|
||||
freezes, switching to ttyE0 and sending a ^C to the running X server.
|
||||
|
||||
I initially passed xterm(1) `-e tmux` to start tmux, but I've found I still
|
||||
prefer to SSh into laika before starting tmux, so all my terminals are remote
|
||||
(one for mail, one for writing, one for debugging, one for man pages).
|
||||
|
||||
I did add `xrdb -load ~/.Xresources` before the xdotool(1)/xterm(1) line, so
|
||||
xterm(1) would load with my preferred color scheme which I've already
|
||||
configured (also see X(7)). I thought this might be automatic, but on here it's
|
||||
not.
|
||||
|
||||
I'm finishing this blah post on my netbook running NetBSD/i386 and an X11
|
||||
server, in which xterm(1) is running, in which ssh(1) is running, connected to
|
||||
my uConsole across the room, on which tmux(1) is running, in which nvim(1) is
|
||||
running. The UTF-8 is beautiful and bat(1) (a guilty pleasure of mine) looks
|
||||
good.
|
||||
|
||||
If I was going to use this computer for anything more than terminals, I'd just
|
||||
use a window manager. I thought about using sxhkd(1) for this task but it
|
||||
ultimately proved to be unnecessary.
|
||||
|
||||
I added the following to my $ENV (see sh(1)):
|
||||
|
||||
# Don't start X if I'm on a framebuffer kick or am in tmux(1) (or screen(1)).
|
||||
if test -z "$NO_WM" && ! test "$TERM" = screen
|
||||
then case "$0" in
|
||||
-*) startx ;; # Do start X if I'm in a login shell
|
||||
# (see bash(1)).
|
||||
esac
|
||||
fi
|
||||
|
||||
Which seems to work well. If it failed dreadfully I could reboot and login as
|
||||
root.
|
||||
|
||||
I don't have much more to say. Don't be scared of X - in conjunction with
|
||||
xinit(1) and startx(1) it's quite easy to use. Don't be scared of Wayland
|
||||
either - it may not yet run well on NetBSD, but if you get a chance to try it,
|
||||
you might really like it.
|
||||
|
||||
|
||||
/blah/2025-04-05.html
|
||||
|
||||
My habitual "the story so far" was long delayed because I didn't remember what
|
||||
happened in 2024 - I really just didn't remember anything until my acid trip in
|
||||
July. I don't know if it's out of trauma or shame or a combination of both.
|
||||
When I try to remember what happened last year this sweltering sadness
|
||||
overwhelms me and my eyes well up. Otherwise it seems like just another
|
||||
forgotten nightmare.
|
||||
|
||||
: the story so far (2024)
|
||||
|
||||
Season 3: desert
|
||||
January
|
||||
Episode 01: "four five six"
|
||||
Another polycule visits. Trinity finds it hard to balance work and
|
||||
life.
|
||||
February
|
||||
Episode 02: "thirty-three days"
|
||||
Trinity works for one month straight.
|
||||
March
|
||||
Episode 03: "trinity has a mental breakdown"
|
||||
Trinity has a mental breakdown due to overwork.
|
||||
April
|
||||
Episode 04: "toki pona"
|
||||
The gang goes to a toki pona meetup.
|
||||
Episode 05: "bicycle day"
|
||||
Trinity takes two days off to try acid but [...] and [...] worry it'll
|
||||
have a bad trip.
|
||||
May
|
||||
Episode 06: "three's a crowd"
|
||||
[...] leaves to get [...]. [...] comes back with [...] and Trinity
|
||||
can't watch a movie without them making out near it.
|
||||
June
|
||||
Episode 07: "a match made in hell"
|
||||
Trinity trains a new coworker.
|
||||
July
|
||||
Episode 08: "moxie"
|
||||
[...] and [...] find a place that sells Moxie.
|
||||
Episode 09: "suicide is painless"
|
||||
Trinity contemplates suicide.
|
||||
Episode 10: "nuture"
|
||||
Trinity takes 100ug of lysergic acid diethylamine. [...] quits.
|
||||
Episode 11: "a day off"
|
||||
Trinity enjoys a day off from work.
|
||||
Episode 12: "two weeks"
|
||||
Trinity puts its two week notice in and faces retribution.
|
||||
August
|
||||
Episode 13: "a softer world"
|
||||
Trinity starts a new job.
|
||||
September
|
||||
Episode 14: "prog rock"
|
||||
Trinity goes to a concert with a friend.
|
||||
November
|
||||
Episode 15: "pies pies pies"
|
||||
Trinity, now competent, makes a lot of pies.
|
||||
Episode 16: "thanksgiving"
|
||||
Trinity and [...] survive Thanksgiving at [...].
|
||||
December
|
||||
Episode 17: "noted"
|
||||
Trinity gets a notebook.
|
||||
Episode 18: "yule"
|
||||
The gang goes to Yule at [...]'s parents' and gets drunk.
|
||||
Episode 19: "the birds"
|
||||
Trinity's lost notebook falls out of the sky. Trinity struggles to
|
||||
think of Christmas presents for everyone.
|
||||
|
||||
|
||||
/blah/2025-04-01.html
|
||||
|
||||
: openbsd server
|
||||
|
||||
i'm using caddy instead of relayd,httpd,acme because i like an easy config for
|
||||
web shit and i loathe tls stuff
|
||||
|
||||
/etc/caddy/Caddyfile
|
||||
|
|
||||
| # lightly modified default
|
||||
| {
|
||||
| http_port 8080
|
||||
| https_port 8443
|
||||
| admin unix//var/caddy/admin.sock|0220
|
||||
| }
|
||||
|
|
||||
| trinity.moe {
|
||||
| root * /srv/trinity.moe
|
||||
| file_server
|
||||
| }
|
||||
|
|
||||
| www.trinity.moe {
|
||||
| redir https://trinity.moe{uri}
|
||||
| }
|
||||
|
||||
cool and all, right? except caddy can't bind to low ports on openbsd, because
|
||||
caddy isn't running as root (which is a security issue) and openbsd can't let
|
||||
non-root processes bind to low ports like linux can. so we've bound to high
|
||||
ports. let's fix this in pf(4)
|
||||
|
||||
/etc/pf.conf
|
||||
| # [ defaults included, but i'm not copying them over here ]
|
||||
| pass in on any proto tcp from any to any port 80 rdr-to 127.0.0.1 port 8080
|
||||
| pass in on any proto tcp from any to any port 443 rdr-to 127.0.0.1 port 8443
|
||||
|
||||
okay cool
|
||||
|
||||
for a while trinity.moe was hosted on the same machine as feeling.murderu.us,
|
||||
as of today that is no longer the case (i still own murderu.us and everything,
|
||||
i just wanted a personal vps for other things too)
|
||||
|
||||
maybe there will be more blah posts but probably not
|
||||
|
||||
|
||||
/blah/2024-12-01.html
|
||||
|
||||
: vaporware i looked forward to
|
||||
|
||||
4
status/.gitignore
vendored
Normal file
4
status/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
*.o
|
||||
order.c
|
||||
settings.c
|
||||
status
|
||||
28
status/Makefile
Normal file
28
status/Makefile
Normal file
@@ -0,0 +1,28 @@
|
||||
CFLAGS += -g
|
||||
|
||||
.PHONY: run
|
||||
run: status
|
||||
./status
|
||||
|
||||
.PHONY: cleanall
|
||||
cleanall: clean
|
||||
rm -f order.c settings.c
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f status *.o
|
||||
|
||||
status: status.c order.c libio.o libkeyval.o
|
||||
time $(CC) $(CFLAGS) -o $@ $@.c libio.o libkeyval.o
|
||||
|
||||
order.c: order.def.c
|
||||
- cp -v order.def.c $@
|
||||
|
||||
libio.o: libio.c libio.h
|
||||
$(CC) $(CFLAGS) -c -o $@ libio.c
|
||||
|
||||
libkeyval.o: libkeyval.c libkeyval.h settings.c
|
||||
$(CC) $(CFLAGS) -c -o $@ libkeyval.c
|
||||
|
||||
settings.c: settings.def.c
|
||||
- cp -v settings.def.c $@
|
||||
13
status/README
Normal file
13
status/README
Normal file
@@ -0,0 +1,13 @@
|
||||
__ ___ __ ___ _ _ __
|
||||
/ _// // // // // // _/ STATUS
|
||||
_'. / // _ // / / // /_'. how's your day going?
|
||||
/__/ /_//_//_//_/ /__/ /__/ 2025 DTB. Public Domain.
|
||||
|
||||
build: $ make
|
||||
|
||||
libio.c, libio.h: libio, a wrapper around I/O functions for status(1)
|
||||
libkeyval.c, libkeyval.h: libkeyval, a key/value system for status(1)
|
||||
*.def.c: the default for foo.c, a configuration file #included
|
||||
directly in a source-file
|
||||
mod_*.c: modules to be #included directly in status.h
|
||||
status.c: main() and boilerplate
|
||||
19
status/libio.c
Normal file
19
status/libio.c
Normal file
@@ -0,0 +1,19 @@
|
||||
/* 2025 DTB. Public Domain. */
|
||||
#undef NDEBUG /* LOAD-BEARING ASSERTS! */
|
||||
#include <assert.h> /* assert(3) */
|
||||
#include <errno.h> /* errno */
|
||||
#include <stdio.h> /* fputs(3), stdout, NULL */
|
||||
#include "libio.h"
|
||||
|
||||
/* output */
|
||||
static char *hold = NULL;
|
||||
|
||||
void
|
||||
drop(void) { hold = NULL; }
|
||||
|
||||
void
|
||||
out(char *s) {
|
||||
if (hold != NULL)
|
||||
{ errno = 0; fputs(hold, stdout); assert(errno == 0); }
|
||||
hold = s;
|
||||
}
|
||||
8
status/libio.h
Normal file
8
status/libio.h
Normal file
@@ -0,0 +1,8 @@
|
||||
/* 2025 DTB. Public Domain. */
|
||||
|
||||
/* libio is a microscopic library that exists to separate less relevant code
|
||||
* from status(1). It should not be used in critical applications for lack of
|
||||
* recoverability (as opposed to <stdio.h> on its own). */
|
||||
|
||||
void drop(void); /* Set the buffer to NULL. */
|
||||
void out(char *s); /* Print the buffer if not NULL and replace it with s. */
|
||||
68
status/libkeyval.c
Normal file
68
status/libkeyval.c
Normal file
@@ -0,0 +1,68 @@
|
||||
/* 2025 DTB. Public domain. */
|
||||
|
||||
#undef NDEBUG /* LOAD-BEARING ASSERTS! */
|
||||
#include <assert.h> /* assert(3) */
|
||||
#include <stdlib.h> /* atoi(3) */
|
||||
#include <string.h> /* strcmp(3) */
|
||||
#include "libkeyval.h"
|
||||
|
||||
static struct State state = { 0 };
|
||||
|
||||
void
|
||||
cpy(char *key) {
|
||||
state.settings[state.setting_last].key = key;
|
||||
state.settings[state.setting_last].val = get(key);
|
||||
assert(++state.setting_last < state_settings_size);
|
||||
}
|
||||
|
||||
void
|
||||
del(char *key) {
|
||||
size_t i;
|
||||
for (i = idx(key); i < state.setting_last; ++i) {
|
||||
state.settings[i].key = state.settings[i + 1].key;
|
||||
state.settings[i].val = state.settings[i + 1].val;
|
||||
}
|
||||
--state.setting_last;
|
||||
}
|
||||
|
||||
char *
|
||||
get(char *key) { return state.settings[idx(key)].val; }
|
||||
|
||||
int
|
||||
getd(char *key) { return atoi(get(key)); }
|
||||
|
||||
size_t
|
||||
idx(char *key) {
|
||||
size_t r;
|
||||
for (r = 0; state.settings[r].key != NULL
|
||||
&& strcmp(state.settings[r].key, key) != 0;
|
||||
++r);
|
||||
return (state.settings[r].key == NULL) ? state.setting_last : r;
|
||||
}
|
||||
|
||||
void
|
||||
keyval_init(void) {
|
||||
/* Unnecessary, but means a wrong state.setting_last won't blow up. */
|
||||
(void)memset(&state.settings[state.setting_last],
|
||||
state_settings_size - state.setting_last, '\0');
|
||||
#include "settings.c"
|
||||
}
|
||||
|
||||
size_t
|
||||
ren(char *key, char *new) {
|
||||
size_t i;
|
||||
if ((i = idx(key)) != state.setting_last)
|
||||
{ state.settings[i].key = new; }
|
||||
return i;
|
||||
}
|
||||
|
||||
size_t
|
||||
set(char *key, char *val) {
|
||||
size_t i;
|
||||
i = idx(key);
|
||||
state.settings[i].key = key;
|
||||
state.settings[i].val = val;
|
||||
if (i == state.setting_last)
|
||||
{ assert(++state.setting_last < state_settings_size); }
|
||||
return i;
|
||||
}
|
||||
29
status/libkeyval.h
Normal file
29
status/libkeyval.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/* 2025 DTB. Public domain. */
|
||||
|
||||
/* libkeyval is a key/value store library to be used for nonessential
|
||||
* applications due to lack of recoverability (errors fail assert(3)).
|
||||
* libkeyval deals with pointers and pointers only, and an effort has been made
|
||||
* to reflect the simplicity of the procedure in the code itself. */
|
||||
|
||||
/* keyval store */
|
||||
#ifndef state_settings_size
|
||||
# define state_settings_size 100
|
||||
#endif
|
||||
|
||||
struct State {
|
||||
size_t setting_last;
|
||||
struct Setting { char *key; char *val; } settings[state_settings_size];
|
||||
};
|
||||
|
||||
void cpy(char *key); /* Duplicate the setting key. */
|
||||
void del(char *key); /* Delete the first instance of key in settings. */
|
||||
char * get(char *key); /* Get the corresponding val to key in settings. */
|
||||
int getd(char *key); /* get() that returns a decimal number if key was a
|
||||
* number, or 0. */
|
||||
void keyval_init(void); /* Sanitize the settings store. */
|
||||
size_t idx(char *key); /* Returns the index of key if in settings, or
|
||||
* state.setting_last. */
|
||||
size_t ren(char *key, char *dst); /* Rename the first instance of key in
|
||||
* settings. */
|
||||
size_t set(char *key, char *val); /* Set the first instance of key in
|
||||
* settings. */
|
||||
5
status/mod_static.c
Normal file
5
status/mod_static.c
Normal file
@@ -0,0 +1,5 @@
|
||||
// #include "io.h" /* out(3) */
|
||||
// #include "keyval.h" /* get(3) */
|
||||
|
||||
void
|
||||
mod_static(char *s) { out(s); out(get("separator")); }
|
||||
35
status/mod_time.c
Normal file
35
status/mod_time.c
Normal file
@@ -0,0 +1,35 @@
|
||||
/* 2025 DTB. Public Domain. */
|
||||
// #undef NDEBUG /* LOAD BEARING ASSERTS */
|
||||
// #include <assert.h> /* assert(3) */
|
||||
// #include <stdlib.h> /* setenv(3), unsetenv(3), NULL */
|
||||
// #include <time.h> /* localtime(3), strftime(3), time(2), tzset(3), time_t,
|
||||
// * struct tm */
|
||||
// #include "io.h" /* out(3) */
|
||||
// #include "keyval.h" /* get(3) */
|
||||
#ifndef mod_time_bufsize
|
||||
# define mod_time_bufsize 100
|
||||
#endif
|
||||
|
||||
void
|
||||
set_timezone(char *zone) {
|
||||
if (zone == NULL) { assert(unsetenv("TZ") == 0); }
|
||||
else { assert(setenv("TZ", zone, 1) == 0); }
|
||||
tzset();
|
||||
}
|
||||
|
||||
void
|
||||
mod_time(char *fmt) {
|
||||
static char buf[mod_time_bufsize];
|
||||
struct tm *tm;
|
||||
static time_t t = 0;
|
||||
static tick_t last_tick = 0;
|
||||
|
||||
if (ticker == 0) { t = time(NULL); }
|
||||
else if (ticker != last_tick) { t += slept; }
|
||||
last_tick = ticker;
|
||||
assert((tm = localtime(&t)) != NULL);
|
||||
assert(strftime(buf, sizeof(buf) / sizeof(*buf), fmt, tm) != 0);
|
||||
|
||||
out(buf);
|
||||
out(get("separator"));
|
||||
}
|
||||
52
status/order.def.c
Normal file
52
status/order.def.c
Normal file
@@ -0,0 +1,52 @@
|
||||
/* This is a C source file #included at global scope in status.c. There are a
|
||||
* number of useful functions defined in status.c and #included headers to try
|
||||
* to make iteration a little more convenient. */
|
||||
|
||||
/* Environment
|
||||
* getenv(key) gets the value of an environment variable
|
||||
* setenv(key, val, overwrite) sets key to val in the environment, overwriting
|
||||
* val if key was already defined and overwrite is 0
|
||||
* set_timezone(val) sets TZ to val in the environment, then calls tzset(3) to
|
||||
* set appropriate timezone values. if val is NULL, it clears the TZ val,
|
||||
* which restores the timezone to the system local time
|
||||
* get(key) gets the val corresponding to key in settings
|
||||
* set(key, val) sets the val corresponding to key in settings
|
||||
* idx(key) returns the index of key in settings
|
||||
* del(key) deletes the first instance of key in settings
|
||||
* cpy(key) creates an identical instance to key in settings
|
||||
* ren(key, dst) renames key to dst in settings
|
||||
* keyval_init() cleans the settings in case of a glitch */
|
||||
|
||||
/* I/O
|
||||
* out(s) holds s and prints what it was previously holding, if it wasn't NULL
|
||||
* drop() sets out()'s held value to NULL */
|
||||
|
||||
/* Modules
|
||||
* mod_static(s) outputs s and then the separator val, unless mod_static() is
|
||||
* called as the last function in order
|
||||
* mod_time(fmt) outputs the time for the current time zone in the strftime(3)
|
||||
* fmt */
|
||||
void
|
||||
order() {
|
||||
/* there are a couple good ways to print without the separator. the
|
||||
* best is to use out() to write directly to the output buffer */
|
||||
out("utc"); /* => "utc" */
|
||||
/* but another way is to use status_static to write a message and
|
||||
* separator, then use drop() to recall the last thing written (always
|
||||
* the separator in status_* functions) */
|
||||
mod_static(" "); drop(); /* => " " */
|
||||
set_timezone("");
|
||||
mod_time("%Y-%m-%dT%H:%M"); /* => "2025-03-27T00:00 // " */
|
||||
|
||||
/* and another way is to use the weird key-val system */
|
||||
cpy("separator"); /* duplicate setting */
|
||||
set("separator", " "); /* overwrite first setting */
|
||||
set_timezone(NULL);
|
||||
mod_static("local"); /* use first setting */
|
||||
del("separator"); /* delete the first, restoring the second */
|
||||
mod_time("%Y-%m-%dT%H:%M");
|
||||
drop();
|
||||
/* => "local 2025-03-26T18:00" */
|
||||
|
||||
/* all => "utc 2025-03-27T00:00 // local 2025-03-26T18:00" */
|
||||
}
|
||||
2
status/settings.def.c
Normal file
2
status/settings.def.c
Normal file
@@ -0,0 +1,2 @@
|
||||
set("interval_seconds", "1");
|
||||
set("separator", " // ");
|
||||
32
status/status.c
Normal file
32
status/status.c
Normal file
@@ -0,0 +1,32 @@
|
||||
#undef NDEBUG /* LOAD-BEARING ASSERTS! */
|
||||
#include <assert.h> /* "mod_time.c" */
|
||||
#include <limits.h> /* UCHAR_MAX */
|
||||
#include <stdlib.h> /* "mod_time.c" */
|
||||
#include <time.h> /* "mod_time.c" */
|
||||
#include <unistd.h> /* sleep(3) */
|
||||
#include "libio.h" /* drop(3), out(3), "mod_static.c" */
|
||||
#include "libkeyval.h" /* cpy(3), del(3), get(3), keyval_init(3), set(3),
|
||||
* "mod_static.c" */
|
||||
|
||||
#define ever (;;)
|
||||
|
||||
unsigned int slept = 0;
|
||||
|
||||
typedef unsigned char tick_t;
|
||||
#define TICK_MAX UCHAR_MAX
|
||||
tick_t ticker = 0;
|
||||
|
||||
#include "mod_static.c"
|
||||
#include "mod_time.c"
|
||||
|
||||
#include "order.c"
|
||||
|
||||
int main(int argc, char *argv) {
|
||||
keyval_init();
|
||||
|
||||
for ever {
|
||||
order(); drop(); out("\n");
|
||||
slept = sleep(getd("interval_seconds"));
|
||||
ticker = ++ticker % TICK_MAX;
|
||||
}
|
||||
}
|
||||
26
trinitystuff/nvim/init.lua
Normal file
26
trinitystuff/nvim/init.lua
Normal file
@@ -0,0 +1,26 @@
|
||||
vim.cmd.colorscheme("torte");
|
||||
vim.cmd.syntax("on");
|
||||
vim.cmd([[
|
||||
set mouse=
|
||||
set noautoindent
|
||||
set nocp
|
||||
set noexpandtab
|
||||
set noim
|
||||
set nois
|
||||
set nowrap
|
||||
|
||||
call plug#begin('~/.vim/plugged')
|
||||
Plug 'Olical/conjure'
|
||||
Plug 'atweiden/vim-fennel'
|
||||
call plug#end()
|
||||
]]);
|
||||
vim.opt.bg = "dark";
|
||||
vim.opt.colorcolumn = "80";
|
||||
vim.opt.nu = true;
|
||||
vim.opt.relativenumber = true;
|
||||
vim.opt.rnu = true;
|
||||
vim.opt.ruler = true;
|
||||
vim.opt.tabstop = 8;
|
||||
vim.opt.tf = true;
|
||||
vim.opt.title = true;
|
||||
vim.opt.vb = true;
|
||||
@@ -1,19 +0,0 @@
|
||||
colorscheme torte
|
||||
set bg=dark
|
||||
set colorcolumn=80
|
||||
set mouse=
|
||||
set noautoindent
|
||||
set nocp
|
||||
set noexpandtab
|
||||
set noim
|
||||
set nois
|
||||
set nu
|
||||
set relativenumber
|
||||
set rnu
|
||||
set ruler
|
||||
set tabstop=8
|
||||
set tf
|
||||
set title
|
||||
set vb
|
||||
set nowrap
|
||||
syntax on
|
||||
Reference in New Issue
Block a user