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(®ex, 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(®ex, url, 0, NULL, 0); 92 if(res > 0) 93 return 1; 94 95 res = regcomp(®ex, 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(®ex, 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 }