Overview
Comment: | add newtab |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
6b40270f2843f2cbfc588dc51f60abcd |
User & Date: | lexi on 2019-11-05 16:14:39 |
Other Links: | manifest | tags |
Context
2019-11-05
| ||
16:27 | nitpick check-in: 2a975fabe3 user: lexi tags: trunk | |
16:14 | add newtab check-in: 6b40270f28 user: lexi tags: trunk | |
2019-10-17
| ||
20:03 | reorganize dumbass directory structure check-in: c29fe4718a user: lexi tags: trunk | |
Changes
Added newtab.c version [bf8e7ec053].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
/* [ʞ] newtab.c * ~ lexi hale <lexi@hale.su> * $ cc -Ofast newtab.c -onewtab \ * [-D_default_qutebrowser_location=/...] * $ ./newtab [example.net] * © AGPLv3 * ? may god have mercy on my soul. * i wrote this because qutebrowser, being a python * abomination, takes an absurdly fucking long time * to load, even when there's already an instance * running and i just want a new goddamn tab. it * turns out, qutebrowser publishes an inane IPC * mechanism, in which JSON (i know!!) written to a * unix domain socket (I KNOW) can send signals to * a running qutebrowser process. newtab checks if * there's a running qutebrowser process and sends * the appropriate IPC signal if so. otherwise, it * execs a new qutebrowser instance. * * it takes a single argument, the URI of a page to * navigate to. if launched without an argument, * newtab simply opens a blank new tab. simple * enough, right? but why write it in C? to talk to * a goddammned python application, of all things? * well, i was originally going to do this in a * bash script with socat, but then i pulled up the * socat manpage and immediately decided it would * be faster to implement the damn thing in C, and * performance would be better anyway. i think it * is fair to say that i was correct. * * so, that's half the story. the code quality is * the other half. i'm going to be straight with * you: i wrote this sleep-deprived at 7am because * i'd stayed up all night with my boyfriend who's * still remote-working on German time because his * employers are kind of assholes. i'm aware that's * not an excuse and i apologize sincerely. if * anyone wants to submit a MR to tidy up this * abomination without sacrificing performance, i * would welcome it gratefully. */ #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #include <dirent.h> #include <unistd.h> #define _POSIX_C_SOURCE 200809L #include <string.h> #define ssz(str) (str), (sizeof str) #define dupl(x) x,x #ifndef _default_qutebrowser_location # define _default_qutebrowser_location "/usr/bin/qutebrowser" #endif #define jstr(val) "\"" val "\"" #define j(key, val) jstr(#key) ": " val #define json_msg_start "{" \ j(protocol_version, "1") "," \ j(target_arg, jstr("")) "," \ jstr("args")": [\"" #define json_msg_end "\"]}\n" enum status { ok, start_instance, fail_xdg_null, fail_find, }; const char* errors [] = { [ok] = NULL, [start_instance] = NULL, [fail_xdg_null] = "$XDG_RUNTIME_DIR is not set - cannot locate IPC socket", [fail_find] = "cannot find qutebrowser - is your $PATH set correctly?", }; enum status transmit(const char* uri) { const char* const run = getenv("XDG_RUNTIME_DIR"); if (run == NULL) return fail_xdg_null; struct sockaddr_un srv = { .sun_family = AF_UNIX, } ; { /* fuck this fuck this fuck this fuck this */ char* end = stpncpy(srv.sun_path, run, sizeof srv.sun_path); end = stpncpy(end, ssz("/qutebrowser/")); DIR* qb = opendir(srv.sun_path); if (!qb) return start_instance; struct dirent* ent; while (ent = readdir(qb)) { if (ent == NULL) return start_instance; if (ent -> d_name[0] != '.') break; } if (ent == NULL) return start_instance; end = stpncpy(end, ent->d_name, (sizeof srv.sun_path) - (end - srv.sun_path)); closedir(qb); } int sock = socket(AF_UNIX, SOCK_STREAM, 0); if (connect(sock, (struct sockaddr*)&srv, sizeof srv) != 0) return start_instance; const char msg_blank [] = json_msg_start json_msg_end; const size_t extra = uri != NULL ? strlen(uri) : 0; char msg_start [(sizeof json_msg_start) + extra]; const size_t msgsz = sizeof msg_blank + extra - 1; const char* msg; if (uri == NULL) msg = msg_blank; else { strcpy(msg_start, json_msg_start); strcpy(msg_start + (sizeof json_msg_start) - 1, uri); strcpy(msg_start + (sizeof json_msg_start) - 1 + extra, json_msg_end); msg = msg_start; } const char* cur = msg; while(cur < msg + msgsz) cur += write(sock, cur, msgsz - (cur - msg)); close(sock); return ok; } int main(int argc, char** argv) { if (argc > 2) { printf("\x1b[1musage:\x1b[m %s [uri]\n", argv[0]); } else { const char* uri = argc < 2 ? NULL : argv[1]; enum status st = transmit(uri); if (st == start_instance) { if (!fork()) { execl(dupl(_default_qutebrowser_location), uri, NULL); execl(dupl("/usr/local/bin/qutebrowser"), uri, NULL); execlp(dupl("qutebrowser"), uri, NULL); st = fail_find; } else { return start_instance; } } if (errors[st] != NULL) printf("\x1b[1;31m(error)\x1b[m %s\n", errors[st]); return st; } } |