git.y1.nz

bro

URI-based multiplexer
download: http://git.y1.nz/archives/bro.tar.gz
README | Files | Log | Refs

main.c

      1 #include <stdio.h> /* printf */
      2 #include <string.h> /* strlen */
      3 #include <unistd.h> /* execlp, access */
      4 #include <sys/wait.h> /* waitpid */
      5 #include <stdlib.h> /* exit */
      6 #include <errno.h> /* errno */
      7 #include <fcntl.h> /* creat */
      8 
      9 #include "okra.h"
     10 #include "config.h"
     11 
     12 #define FATAL(message) { \
     13 	printf("\033[1;31m" "Fatal: " message "\033[0m" "\n"); \
     14 	exit(1); \
     15 }
     16 #define FORKEXEC(arg1, ...)  { \
     17 	pid = fork(); \
     18 	if (!pid) { \
     19 		int result; \
     20 		result = execlp(arg1, arg1, __VA_ARGS__, NULL); \
     21 		exit(0); \
     22 	} \
     23 	waitpid(pid, &child_status, 0); \
     24 }
     25 #define FFORKEXEC(fname, arg1, ...)  { \
     26 	pid = fork(); \
     27 	if (!pid) { \
     28 		int result; \
     29 		int fd = creat( \
     30 			fname, \
     31 			O_CREAT | O_TRUNC | O_WRONLY | \
     32 			S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH \
     33 		); \
     34 		if (fd == -1) { \
     35 			printf("Failed to create [%s]" "\n", fname); \
     36 			FATAL("couldnt open/create file :("); \
     37 		} \
     38 		dup2(fd, STDOUT_FILENO); \
     39 		result = execlp(arg1, arg1, __VA_ARGS__, NULL); \
     40 		if (result == -1) { \
     41 			int err = errno; \
     42 			FATAL("Uh oh exec dint work :(("); \
     43 		} \
     44 		exit(0); \
     45 	} \
     46 	waitpid(pid, &child_status, 0); \
     47 }
     48 
     49 pid_t pid;
     50 int child_status;
     51 
     52 void
     53 ask_to_continue()
     54 {
     55 	char ch;
     56 
     57 	// TODO set termios so it's "press y to %s, n or q to quit"
     58 	printf("Try again?"); fflush(stdout);
     59 	for (;;) {
     60 		switch (getchar()) {
     61 		case 'y': return;
     62 		case 'n':
     63 		case 'q': FATAL("Cancelled.");
     64 		}
     65 	}
     66 }
     67 
     68 void
     69 ensure_file_exists(const char *path)
     70 {
     71 	if (!access(path, O_RDONLY)) return;
     72 	printf("Couldn't access local file [%s]" "\n", path);
     73 	FATAL("File is inaccessible");
     74 }
     75 
     76 int
     77 streq(const char *a, const char *b)
     78 {
     79 	if (a == NULL && b == NULL) return 1;
     80 	if (a == NULL || b == NULL) return 0;
     81 	int i = 0;
     82 	for (;;) {
     83 		if (a[i] != b[i]) return 0;
     84 		if (a[i] == '\0') return 1;
     85 		i++;
     86 	}
     87 }
     88 
     89 const char *
     90 get_extension(const char *filename)
     91 {
     92 	int length = strlen(filename);
     93 	int i = length-1;
     94 	for (;;) {
     95 		i--;
     96 		if (i < 0) return NULL;
     97 		if (filename[i] == '.')
     98 			return filename + (i+1);
     99 	}
    100 }
    101 
    102 const char *
    103 get_raw_file(OkraUri *uri)
    104 {
    105 	const char *ret = NULL;
    106 
    107 	/* default to "file" scheme */
    108 	if (uri->scheme == NULL || streq(uri->scheme, "file"))
    109 		return uri->path;
    110 
    111 	if (streq(uri->scheme, "mailto"))
    112 		FATAL("TODO open a mail client then exit?");
    113 
    114 	if (streq(uri->scheme, "http") || streq(uri->scheme, "https")) {
    115 		child_status = 1;
    116 		ret = DEFAULT_SESSION_DIR "/current.html";
    117 		for (;;) {
    118 			if (child_status == 0) break;
    119 			FFORKEXEC(ret, "wget", "-O", "-", uri->uri);
    120 			if (child_status != 0) {
    121 				printf("Exit status was %d" "\n", child_status);
    122 				ask_to_continue();
    123 			}
    124 		}
    125 		return ret;
    126 	}
    127 
    128 	if (streq(uri->scheme, "gopher")) {
    129 		ret = DEFAULT_SESSION_DIR "/current.gph";
    130 		FFORKEXEC(ret, "hurl", uri->uri);
    131 		return ret;
    132 	}
    133 
    134 	if (streq(uri->scheme, "ftp"))
    135 		FATAL("TODO retrieve ftp page.");
    136 
    137 	printf("Scheme: [%s]" "\n", uri->scheme);
    138 	FATAL("Unhandled scheme.");
    139 	exit(1);
    140 }
    141 
    142 const char *
    143 get_digested_file(OkraUri *uri, const char *raw_file)
    144 {
    145 	const char *ret = NULL;
    146 	const char *ext = get_extension(uri->uri);
    147 
    148 	if (streq(ext, "txt")) return raw_file;
    149 
    150 	if (streq(ext, "html")) {
    151 		ret = DEFAULT_SESSION_DIR "/current.md";
    152 		FORKEXEC(
    153 			"digest-html",
    154 			"-b", uri->uri,
    155 			"-o", ret,
    156 			raw_file
    157 		);
    158 		if (child_status != 0) FATAL("Failed to digest HTML.");
    159 		return ret;
    160 	}
    161 
    162 	if (streq(ext, "gph")) {
    163 		ret = DEFAULT_SESSION_DIR "/current.md";
    164 		FORKEXEC("digest-gopher", "-o", ret, raw_file);
    165 		if (child_status != 0) FATAL("Failed to digest gohper.");
    166 		return ret;
    167 	}
    168 
    169 	/* default based on scheme */
    170 	// TODO is there a better way?
    171 	if (streq(uri->scheme, "http") || streq(uri->scheme, "https")) {
    172 		ret = DEFAULT_SESSION_DIR "/current.md";
    173 		FORKEXEC(
    174 			"digest-html",
    175 			"-b", uri->uri,
    176 			"-o", ret,
    177 			raw_file
    178 		);
    179 		if (child_status != 0) FATAL("Failed to digest HTML.");
    180 		return ret;
    181 	}
    182 	if (streq(uri->scheme, "gopher")) {
    183 		ret = DEFAULT_SESSION_DIR "/current.md";
    184 		FORKEXEC("digest-gopher", "-o", ret, raw_file);
    185 		if (child_status != 0) FATAL("Failed to digest gopher.");
    186 		return ret;
    187 	}
    188 
    189 	printf("No digester, defaulting to raw" "\n");
    190 	return raw_file;
    191 }
    192 
    193 int
    194 main(int argc, const char *argv[])
    195 {
    196 	if (argc != 2) {
    197 		printf("Usage: %s URI" "\n", argv[0]);
    198 		return 1;
    199 	}
    200 
    201 	OkraUri *uri = okra_parse(argv[1]);
    202 	if (uri == NULL) FATAL("Invalid URI.");
    203 
    204 	FORKEXEC("rm", "-f", "current.md", "current.gph", "current.html");
    205 
    206 	const char *raw_file = get_raw_file(uri);
    207 	if (raw_file == NULL) FATAL("No file to view.");
    208 	ensure_file_exists(raw_file);
    209 
    210 	const char *lwl_file = get_digested_file(uri, raw_file);
    211 	ensure_file_exists(lwl_file);
    212 	FORKEXEC("lwl", lwl_file);
    213 
    214 	okra_free(uri);
    215 }

This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.