sopen

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

sopen.c (3416B)


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