util  Diff

Differences From Artifact [1814ca81a5]:

To Artifact [d69c7e1283]:


     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>