@@ -2,124 +2,125 @@ * ~ lexi hale * $ cc -Ofast bgrd.c -lutil -obgrd * © affero general public license 3.0 - * i am angry beyond words that this program had to - * be written + * i am angry beyond words that this program had to be + * written * - * bgrd "background read" is a tool for launching an - * application and retrieving the first line of output. - * this is a nontrivial task for a number of reasons, - * all of which are incredibly stupid, however, most + * bgrd "background read" is a tool for launching an + * application and retrieving the first line of output. + * this is a nontrivial task for a number of reasons, + * all of which are incredibly stupid, however, most * saliently: buffered io. * - * the suckmore web browser `surf` has an option '-x' - * which is intended to print the X window id of the - * window it opens, so it can be captured and used in + * the suckmore web browser `surf` has an option '-x' + * which is intended to print the X window id of the + * window it opens, so it can be captured and used in * scripts. so far so good. * - * except unix has two distinctly different concepts - * of IO. there's POSIX IO, and then there's libc IO. + * except unix has two distinctly different concepts of + * IO. there's POSIX IO, and then there's libc IO. * - * POSIX IO uses the shit in and ; - * syscalls like read(2), write(2), and pipe(2) - the - * good, simple shit God made unix for. this is really - * bare-metal; these are basically C wrappers over - * kernel syscalls. POSIX IO uses plain old ints as - * file descriptors, and it doesn't fuck around. when - * you say "write," god dammit, it WRITES. + * POSIX IO uses the shit in and ; + * syscalls like read(2), write(2), and pipe(2) - the + * good, simple shit God made unix for. this is really + * bare-metal; these are basically C wrappers over kernel + * syscalls. POSIX IO uses plain old ints as file + * descriptors, and it doesn't fuck around. when you say + * "write," god dammit, it WRITES. * - * libc is a very different beast. libc has opinions. - * libc has abstractions. libc has its own entire - * goddamn DSL by which to specify format strings, - * because apparently someone felt called to reinvent - * FORTRAN except worse. printf(), you know, the first - * function they ever teach you in C 101? (more like CS - * 403 these days, but aghhh) it's actually a heinously + * libc is a very different beast. libc has opinions. + * libc has abstractions. libc has its own entire goddamn + * DSL by which to specify format strings, because + * apparently someone felt called to reinvent FORTRAN + * except worse. printf(), you know, the first function + * they ever teach you in C 101? (more like CS 403 + * these days, but aghhh) it's actually a heinously * complicated, dangerous, slow, insecure mess that drags - * a ridiculous amount of background bullshit into the + * a ridiculous amount of background bullshit into the * frame. such as BUFFERING. * - * libc, you see, is too good to just wrap write() and - * read(). no, it also has to decide when to SEND them. - * this is responsible for that behavior every c coder - * trips over eventually - you know the one, where if - * you don't end your format string in '\n' it isn't - * printed, sometimes even if the program exits. this - * is not actually a POSIX thing; it's a libc thing. + * libc, you see, is too good to just wrap write() and + * read(). no, it also has to decide when to SEND them. + * this is responsible for that behavior every c coder + * trips over eventually - you know the one, where if you + * don't end your format string in '\n' it isn't printed, + * sometimes even if the program exits. this is not + * actually a POSIX thing; it's a libc thing. * * libc has a couple different kinds of buffering tactics - * (set with setvbuf(), a function nobody seems to know - * exists) that it uses in different circumstances. - * the printf \n gotcha behavior is what's known as - * "line buffering." however, because libc thinks it's - * fucking smart or something, it's not content to just - * pick one predictable behavior and stick to it. oh no. + * (set with setvbuf(), a function nobody seems to know + * exists) that it uses in different circumstances. the + * printf \n gotcha behavior is what's known as "line + * buffering." however, because libc thinks it's fucking + * smart or something, it's not content to just pick one + * predictable behavior and stick to it. oh no. * - * ever noticed how programs can seem to tell whether - * they're connected to a terminal (and thus can output - * all those fancy ansi formatting codes), or whether - * you're redirecting their stdout to a file? that's - * because there's more than one kind of pipe. the kind + * ever noticed how programs can seem to tell whether + * they're connected to a terminal (and thus can output + * all those fancy ansi formatting codes), or whether + * you're redirecting their stdout to a file? that's + * because there's more than one kind of pipe. the kind * you create with pipe(2) - and the kind you create with * openpty(2). * - * a pty is, essentially, a kind of pipe that carries - * extra information around, the information you access + * a pty is, essentially, a kind of pipe that carries + * extra information around, the information you access * via ioctl and termios. it's designed to imitate a TTY, - * so that a shell can create one, aim a process at it, - * and then that process can draw TUIs and shit on it. - * and some programs are designed to behave differently - * depending on whether they're hooked up to a pipe or a + * so that a shell can create one, aim a process at it, + * and then that process can draw TUIs and shit on it. + * and some programs are designed to behave differently + * depending on whether they're hooked up to a pipe or a * pty. * * libc, tragically, is among them. * - * if libc notices it's hooked up to a pipe instead of a pty, - * it will change its default buffering strategy. newlines - * will suddenly cease flushing stdout, and libc will - * only print its buffer in one of two circumstances: the - * buffer is filled up, or the program exits. + * if libc notices it's hooked up to a pipe instead of a + * pty, it will change its default buffering strategy. + * newlines will suddenly cease flushing stdout, and + * libc will only print its buffer in one of two + * circumstances: the buffer is filled up, or the program + * exits. * - * this is a problem if you are, say, trying to output a - * handle that scripts can use to control the running + * this is a problem if you are, say, trying to output a + * handle that scripts can use to control the running * program. * - * the `surf` developers had a couple of options. they - * could have simply broken out the POSIX headers and - * sent the X id to stdout with a call to write(2), the - * correct thing to do. they could have thrown in a call - * to setvbuf(3) to explicitly pick a buffering strategy - * compatible with their usecase, the sensibly wrong + * the `surf` developers had a couple of options. they + * could have simply broken out the POSIX headers and + * sent the X id to stdout with a call to write(2), the + * correct thing to do. they could have thrown in a call + * to setvbuf(3) to explicitly pick a buffering strategy + * compatible with their usecase, the sensibly wrong * thing to do. they could have explicitly flushed stdout - * after printf(3)'ing to it, the dumb and error-pront + * after printf(3)'ing to it, the dumb and error-pront * thing to do. * * instead, they did *nothing.* * - * so if you run `surf -x` from a terminal, great! - * you'll see it print the x window id first thing. - * you'll then try to capture it via any number of - * increasing desperate means, all of which will fail - * hilariously. finally, you'll spend four goddamn hours - * after midnight reading source code and manpages and - * frantically googling around and digging up unix lore - * and finally, FINALLY figure out what the batshit FUCK - * is going on, and write this goddamn utility to hack + * so if you run `surf -x` from a terminal, great! + * you'll see it print the x window id first thing. + * you'll then try to capture it via any number of + * increasing desperate means, all of which will fail + * hilariously. finally, you'll spend four goddamn hours + * after midnight reading source code and manpages and + * frantically googling around and digging up unix lore + * and finally, FINALLY figure out what the batshit FUCK + * is going on, and write this goddamn utility to hack * around the suckmore crowd's suckitude. * * so i figured i'd save you some time. * - * i am probably going to submit a PR eventually because + * i am probably going to submit a PR eventually because * holy hell this is just so monumentally bozotic. * - * in the mean time, you can use this extremely - * no-bullshit wrapper by running `set surfwin (bgrd - * (which surf) surf -x ` or whatever the bash - * equivalent is and it will immediately launch surf in - * the background, printing the X window and exiting - * as soon as it hits a newline. it should be adaptable - * to similar scenarios if you find yourself dealing with + * in the mean time, you can use this extremely + * no-bullshit wrapper by running `set surfwin (bgrd + * (which surf) surf -x ` or whatever the bash + * equivalent is and it will immediately launch surf in + * the background, printing the X window and exiting as + * soon as it hits a newline. it should be adaptable to + * similar scenarios if you find yourself dealing with * similarly broken software tho. * * in conclusion, read lenin. */