home | blog | art | now | git gpg | email | rss

sopen

Suckless mimeopen alternative
git clone git://pollux.codes/git/sopen.git
Log | Files | Refs | README | LICENSE

sopen.c (3396B)


      1 
      2 /* See LICENSE file for copyright and license details. */
      3 #include <getopt.h>
      4 #include <magic.h>
      5 #include <regex.h>
      6 #include <spawn.h>
      7 #include <stdio.h>
      8 #include <stdlib.h>
      9 #include <unistd.h>
     10 
     11 #define _POSIX_C_SOURCE 200809L
     12 
     13 #define REGEX_PROTOCOL "^[a-z]*://"
     14 #define USAGE "usage: sopen [-h] [-V] [-d] <url/file>"
     15 
     16 #define STR_LITERAL(x) #x
     17 #define STRINGIFY(x) STR_LITERAL(x)
     18 
     19 typedef struct {
     20 	const char     *url_regex;
     21 	const char     *mime_regex;
     22 	const char     *program;
     23 } Rule;
     24 
     25 void            print_help();
     26 void            print_version();
     27 void            parse_args(const int argc, char *const *argv, int *dry_run,
     28                            int *url_ind);
     29 int             match_rule(const Rule rule, const char *url,
     30                            const char *mime_type);
     31 
     32 #include "config.h"
     33 
     34 void
     35 print_help() {
     36 	printf(USAGE "\n");
     37 }
     38 
     39 void
     40 print_version() {
     41 	printf(STRINGIFY(PROGNAME) " " STRINGIFY(VERSION) "\n");
     42 	printf("CFLAGS:  " STRINGIFY(CFLAGS) "\n");
     43 	printf("LDFLAGS: " STRINGIFY(LDFLAGS) "\n");
     44 }
     45 
     46 void
     47 parse_args(const int argc, char *const *argv, int *dry_run, int *url_ind) {
     48 
     49 	char           *cvalue = NULL;
     50 	int             index;
     51 	int             c;
     52 
     53 	opterr = 0;
     54 
     55 	while((c = getopt(argc, argv, "dhV")) != -1) {
     56 		switch (c) {
     57 		case 'd':
     58 			*dry_run = 1;
     59 			break;
     60 		case 'h':
     61 			print_help();
     62 			exit(0);
     63 		case 'V':
     64 			print_version();
     65 			exit(0);
     66 		case '?':
     67 			fprintf(stderr,
     68 			        "Unknown option `%c'. Run `sopen -h' for usage.\n",
     69 			        optopt);
     70 			exit(1);
     71 		default:
     72 			exit(255);
     73 		}
     74 	}
     75 	*url_ind = optind;
     76 }
     77 
     78 int
     79 match_rule(const Rule rule, const char *url, const char *mime_type) {
     80 
     81 	regex_t         regex;
     82 	int             res;
     83 
     84 	int             dry_run = 0;
     85 
     86 	res = regcomp(&regex, rule.url_regex, REG_EXTENDED);
     87 	if(res > 0) {
     88 		printf("Failed to compile url regex: %s\n", rule.url_regex);
     89 		return 1;
     90 	}
     91 	res = regexec(&regex, url, 0, NULL, 0);
     92 	if(res > 0)
     93 		return 1;
     94 
     95 	res = regcomp(&regex, rule.mime_regex, REG_EXTENDED);
     96 	if(res > 0) {
     97 		printf("Failed to compile mime regex: %s\n", rule.mime_regex);
     98 		return 1;
     99 	}
    100 	res = regexec(&regex, mime_type, 0, NULL, 0);
    101 	if(res > 0)
    102 		return 1;
    103 
    104 	return 0;
    105 }
    106 
    107 int
    108 main(int argc, char *const *argv) {
    109 
    110 	int             res;
    111 	int             dry_run;
    112 	int             url_ind;
    113 
    114 	magic_t         cookie;
    115 
    116 	regex_t         has_protocol;
    117 
    118 	const char     *mime_type;
    119 
    120 	const char     *url;
    121 	char            protocol[16];
    122 	char            file[1024];
    123 
    124 	char           *child_args[3];
    125 
    126 	if(argc < 2) {
    127 		print_help();
    128 		exit(0);
    129 	}
    130 
    131 	cookie = magic_open(MAGIC_MIME_TYPE);
    132 	if(cookie == NULL) {
    133 		printf("Failed to open magic cookie.\n");
    134 		goto error;
    135 	}
    136 	magic_load(cookie, NULL);
    137 
    138 	dry_run = 0;
    139 	parse_args(argc, argv, &dry_run, &url_ind);
    140 	url = argv[url_ind];
    141 
    142 	res = regcomp(&has_protocol, REGEX_PROTOCOL, REG_EXTENDED);
    143 	if(res > 0)
    144 		goto error;
    145 
    146 	mime_type = "";
    147 
    148 	res = regexec(&has_protocol, url, 0, NULL, 0);
    149 	if(res > 0)
    150 		mime_type = magic_file(cookie, url);
    151 
    152 	for(int n = 0; n < sizeof(rules) / sizeof(Rule); n++) {
    153 
    154 		res = match_rule(rules[n], url, mime_type);
    155 
    156 		if(res == 0) {
    157 
    158 			child_args[0] = (char *)rules[n].program;
    159 			child_args[1] = (char *)url;
    160 			child_args[2] = NULL;
    161 			if(dry_run) {
    162 				printf("%s %s\n", child_args[0], child_args[1]);
    163 			} else {
    164 				execvp(rules[n].program, child_args);
    165 			}
    166 			return 0;
    167 		}
    168 	}
    169 
    170 	error:
    171 	magic_close(cookie);
    172 	return 1;
    173 }