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