Differences From
Artifact [1814ca81a5]:
1 1 /* [ʞ] bgrd.c
2 2 * ~ lexi hale <lexi@hale.su>
3 3 * $ cc -Ofast bgrd.c -lutil -obgrd
4 4 * © affero general public license 3.0
5 5
6 - * i am angry beyond words that this program had to
7 - * be written
6 + * i am angry beyond words that this program had to be
7 + * written
8 8 *
9 - * bgrd "background read" is a tool for launching an
10 - * application and retrieving the first line of output.
11 - * this is a nontrivial task for a number of reasons,
12 - * all of which are incredibly stupid, however, most
9 + * bgrd "background read" is a tool for launching an
10 + * application and retrieving the first line of output.
11 + * this is a nontrivial task for a number of reasons,
12 + * all of which are incredibly stupid, however, most
13 13 * saliently: buffered io.
14 14 *
15 - * the suckmore web browser `surf` has an option '-x'
16 - * which is intended to print the X window id of the
17 - * window it opens, so it can be captured and used in
15 + * the suckmore web browser `surf` has an option '-x'
16 + * which is intended to print the X window id of the
17 + * window it opens, so it can be captured and used in
18 18 * scripts. so far so good.
19 19 *
20 - * except unix has two distinctly different concepts
21 - * of IO. there's POSIX IO, and then there's libc IO.
20 + * except unix has two distinctly different concepts of
21 + * IO. there's POSIX IO, and then there's libc IO.
22 22 *
23 - * POSIX IO uses the shit in <fcntl.h> and <unistd.h>;
24 - * syscalls like read(2), write(2), and pipe(2) - the
25 - * good, simple shit God made unix for. this is really
26 - * bare-metal; these are basically C wrappers over
27 - * kernel syscalls. POSIX IO uses plain old ints as
28 - * file descriptors, and it doesn't fuck around. when
29 - * you say "write," god dammit, it WRITES.
23 + * POSIX IO uses the shit in <fcntl.h> and <unistd.h>;
24 + * syscalls like read(2), write(2), and pipe(2) - the
25 + * good, simple shit God made unix for. this is really
26 + * bare-metal; these are basically C wrappers over kernel
27 + * syscalls. POSIX IO uses plain old ints as file
28 + * descriptors, and it doesn't fuck around. when you say
29 + * "write," god dammit, it WRITES.
30 30 *
31 - * libc is a very different beast. libc has opinions.
32 - * libc has abstractions. libc has its own entire
33 - * goddamn DSL by which to specify format strings,
34 - * because apparently someone felt called to reinvent
35 - * FORTRAN except worse. printf(), you know, the first
36 - * function they ever teach you in C 101? (more like CS
37 - * 403 these days, but aghhh) it's actually a heinously
31 + * libc is a very different beast. libc has opinions.
32 + * libc has abstractions. libc has its own entire goddamn
33 + * DSL by which to specify format strings, because
34 + * apparently someone felt called to reinvent FORTRAN
35 + * except worse. printf(), you know, the first function
36 + * they ever teach you in C 101? (more like CS 403
37 + * these days, but aghhh) it's actually a heinously
38 38 * complicated, dangerous, slow, insecure mess that drags
39 - * a ridiculous amount of background bullshit into the
39 + * a ridiculous amount of background bullshit into the
40 40 * frame. such as BUFFERING.
41 41 *
42 - * libc, you see, is too good to just wrap write() and
43 - * read(). no, it also has to decide when to SEND them.
44 - * this is responsible for that behavior every c coder
45 - * trips over eventually - you know the one, where if
46 - * you don't end your format string in '\n' it isn't
47 - * printed, sometimes even if the program exits. this
48 - * is not actually a POSIX thing; it's a libc thing.
42 + * libc, you see, is too good to just wrap write() and
43 + * read(). no, it also has to decide when to SEND them.
44 + * this is responsible for that behavior every c coder
45 + * trips over eventually - you know the one, where if you
46 + * don't end your format string in '\n' it isn't printed,
47 + * sometimes even if the program exits. this is not
48 + * actually a POSIX thing; it's a libc thing.
49 49 *
50 50 * libc has a couple different kinds of buffering tactics
51 - * (set with setvbuf(), a function nobody seems to know
52 - * exists) that it uses in different circumstances.
53 - * the printf \n gotcha behavior is what's known as
54 - * "line buffering." however, because libc thinks it's
55 - * fucking smart or something, it's not content to just
56 - * pick one predictable behavior and stick to it. oh no.
51 + * (set with setvbuf(), a function nobody seems to know
52 + * exists) that it uses in different circumstances. the
53 + * printf \n gotcha behavior is what's known as "line
54 + * buffering." however, because libc thinks it's fucking
55 + * smart or something, it's not content to just pick one
56 + * predictable behavior and stick to it. oh no.
57 57 *
58 - * ever noticed how programs can seem to tell whether
59 - * they're connected to a terminal (and thus can output
60 - * all those fancy ansi formatting codes), or whether
61 - * you're redirecting their stdout to a file? that's
62 - * because there's more than one kind of pipe. the kind
58 + * ever noticed how programs can seem to tell whether
59 + * they're connected to a terminal (and thus can output
60 + * all those fancy ansi formatting codes), or whether
61 + * you're redirecting their stdout to a file? that's
62 + * because there's more than one kind of pipe. the kind
63 63 * you create with pipe(2) - and the kind you create with
64 64 * openpty(2).
65 65 *
66 - * a pty is, essentially, a kind of pipe that carries
67 - * extra information around, the information you access
66 + * a pty is, essentially, a kind of pipe that carries
67 + * extra information around, the information you access
68 68 * via ioctl and termios. it's designed to imitate a TTY,
69 - * so that a shell can create one, aim a process at it,
70 - * and then that process can draw TUIs and shit on it.
71 - * and some programs are designed to behave differently
72 - * depending on whether they're hooked up to a pipe or a
69 + * so that a shell can create one, aim a process at it,
70 + * and then that process can draw TUIs and shit on it.
71 + * and some programs are designed to behave differently
72 + * depending on whether they're hooked up to a pipe or a
73 73 * pty.
74 74 *
75 75 * libc, tragically, is among them.
76 76 *
77 - * if libc notices it's hooked up to a pipe instead of a pty,
78 - * it will change its default buffering strategy. newlines
79 - * will suddenly cease flushing stdout, and libc will
80 - * only print its buffer in one of two circumstances: the
81 - * buffer is filled up, or the program exits.
77 + * if libc notices it's hooked up to a pipe instead of a
78 + * pty, it will change its default buffering strategy.
79 + * newlines will suddenly cease flushing stdout, and
80 + * libc will only print its buffer in one of two
81 + * circumstances: the buffer is filled up, or the program
82 + * exits.
82 83 *
83 - * this is a problem if you are, say, trying to output a
84 - * handle that scripts can use to control the running
84 + * this is a problem if you are, say, trying to output a
85 + * handle that scripts can use to control the running
85 86 * program.
86 87 *
87 - * the `surf` developers had a couple of options. they
88 - * could have simply broken out the POSIX headers and
89 - * sent the X id to stdout with a call to write(2), the
90 - * correct thing to do. they could have thrown in a call
91 - * to setvbuf(3) to explicitly pick a buffering strategy
92 - * compatible with their usecase, the sensibly wrong
88 + * the `surf` developers had a couple of options. they
89 + * could have simply broken out the POSIX headers and
90 + * sent the X id to stdout with a call to write(2), the
91 + * correct thing to do. they could have thrown in a call
92 + * to setvbuf(3) to explicitly pick a buffering strategy
93 + * compatible with their usecase, the sensibly wrong
93 94 * thing to do. they could have explicitly flushed stdout
94 - * after printf(3)'ing to it, the dumb and error-pront
95 + * after printf(3)'ing to it, the dumb and error-pront
95 96 * thing to do.
96 97 *
97 98 * instead, they did *nothing.*
98 99 *
99 - * so if you run `surf -x` from a terminal, great!
100 - * you'll see it print the x window id first thing.
101 - * you'll then try to capture it via any number of
102 - * increasing desperate means, all of which will fail
103 - * hilariously. finally, you'll spend four goddamn hours
104 - * after midnight reading source code and manpages and
105 - * frantically googling around and digging up unix lore
106 - * and finally, FINALLY figure out what the batshit FUCK
107 - * is going on, and write this goddamn utility to hack
100 + * so if you run `surf -x` from a terminal, great!
101 + * you'll see it print the x window id first thing.
102 + * you'll then try to capture it via any number of
103 + * increasing desperate means, all of which will fail
104 + * hilariously. finally, you'll spend four goddamn hours
105 + * after midnight reading source code and manpages and
106 + * frantically googling around and digging up unix lore
107 + * and finally, FINALLY figure out what the batshit FUCK
108 + * is going on, and write this goddamn utility to hack
108 109 * around the suckmore crowd's suckitude.
109 110 *
110 111 * so i figured i'd save you some time.
111 112 *
112 - * i am probably going to submit a PR eventually because
113 + * i am probably going to submit a PR eventually because
113 114 * holy hell this is just so monumentally bozotic.
114 115 *
115 - * in the mean time, you can use this extremely
116 - * no-bullshit wrapper by running `set surfwin (bgrd
117 - * (which surf) surf -x <params>` or whatever the bash
118 - * equivalent is and it will immediately launch surf in
119 - * the background, printing the X window and exiting
120 - * as soon as it hits a newline. it should be adaptable
121 - * to similar scenarios if you find yourself dealing with
116 + * in the mean time, you can use this extremely
117 + * no-bullshit wrapper by running `set surfwin (bgrd
118 + * (which surf) surf -x <params>` or whatever the bash
119 + * equivalent is and it will immediately launch surf in
120 + * the background, printing the X window and exiting as
121 + * soon as it hits a newline. it should be adaptable to
122 + * similar scenarios if you find yourself dealing with
122 123 * similarly broken software tho.
123 124 *
124 125 * in conclusion, read lenin. */
125 126
126 127 #include <stdio.h>
127 128 #include <unistd.h>
128 129 #include <fcntl.h>