UNIXworkcode

1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3 * 4 * Copyright 2018 Olaf Wintermann. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <string.h> 32 33 #include "optparser.h" 34 #include "sopt.h" 35 36 #include <cx/hash_map.h> 37 38 39 void cmd_args_free(CmdArgs *args) { 40 if(args) { 41 cxMapDestroy(args->options); 42 if(args->argv) { 43 free(args->argv); 44 } 45 free(args); 46 } 47 } 48 49 static void cmd_map_put(CxMap *map, const char *key, const void *value) { 50 cxMapPut(map, key, (void*)value); 51 } 52 53 CmdArgs* cmd_parse_args(int argc, char **argv) { 54 CmdArgs *a = malloc(sizeof(CmdArgs)); 55 a->options = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, 16); 56 a->argv = argc > 0 ? calloc(argc, sizeof(char*)) : NULL; 57 a->argc = 0; 58 59 const char *NOARG = ""; 60 61 char *option = NULL; 62 char optchar = 0; 63 int optterminated = 0; 64 for(int i=0;i<argc;i++) { 65 char *arg = argv[i]; 66 size_t len = strlen(arg); 67 if(len == 2 && arg[0] == '-' && arg[1] == '-') { 68 optterminated = 1; 69 } else if(!optterminated && len > 1 && arg[0] == '-') { 70 // argument is in next arg but starts with a dash 71 // we assume this is not intended and consider this an error 72 if(option) { 73 fprintf(stderr, 74 "Missing argument for option -%c\n\n", optchar); 75 cmd_args_free(a); 76 return NULL; 77 } 78 for(int c=1;c<len;c++) { 79 // argument is in the same arg 80 if(option) { 81 cxMapPut(a->options, cx_hash_key_str(option), &arg[c]); 82 option = NULL; 83 break; 84 } 85 86 switch(arg[c]) { 87 default: { 88 fprintf(stderr, "Unknown option -%c\n\n", arg[c]); 89 cmd_args_free(a); 90 return NULL; 91 } 92 case 'v': { 93 cmd_map_put(a->options, "verbose", NOARG); 94 break; 95 } 96 case 'k': { 97 option = "key"; 98 optchar = 'k'; 99 break; 100 } 101 case 'p': { 102 cmd_map_put(a->options, "plain", NOARG); 103 break; 104 } 105 case 'c': { 106 cmd_map_put(a->options, "crypt", NOARG); 107 break; 108 } 109 case 'a': { 110 cmd_map_put(a->options, "all", NOARG); 111 break; 112 } 113 case 'l': { 114 cmd_map_put(a->options, "list", NOARG); 115 break; 116 } 117 case 'd': { 118 cmd_map_put(a->options, "date", NOARG); 119 break; 120 } 121 case 't': { 122 cmd_map_put(a->options, "type", NOARG); 123 break; 124 } 125 case 'R': { 126 cmd_map_put(a->options, "recursive", NOARG); 127 break; 128 } 129 case 'O': { 130 cmd_map_put(a->options, "override", NOARG); 131 break; 132 } 133 case 'i': { 134 cmd_map_put(a->options, "insecure", NOARG); 135 break; 136 } 137 case 'N': { 138 cmd_map_put(a->options, "noinput", NOARG); 139 break; 140 } 141 case 'e': { 142 cmd_map_put(a->options, "extended", NOARG); 143 break; 144 } 145 case 'x': { 146 cmd_map_put(a->options, "xml", NOARG); 147 break; 148 } 149 case 'F': { 150 option = "finfo"; 151 optchar = 'F'; 152 break; 153 } 154 case 'S': { 155 // undocumented hidden feature 156 cmd_map_put(a->options, "structure", NOARG); 157 break; 158 } 159 case 'K': { 160 cmd_map_put(a->options, "keep", NOARG); 161 break; 162 } 163 case 'o': { 164 option = "output"; 165 optchar = 'o'; 166 break; 167 } 168 case 'u': { 169 option = "update"; 170 optchar = 'u'; 171 break; 172 } 173 case 'n': { 174 option = "namespace"; 175 optchar = 'n'; 176 break; 177 } 178 case 'L': { 179 option = "lock"; 180 optchar = 'L'; 181 break; 182 } 183 case 'T': { 184 option = "timeout"; 185 optchar = 'T'; 186 break; 187 } 188 /* 189 case 'P': { 190 option = "progressfile"; 191 optchar = 'F'; 192 break; 193 } 194 */ 195 case 'V': { 196 option = "version"; 197 optchar = 'V'; 198 break; 199 } 200 } 201 } 202 } else if(option) { 203 cmd_map_put(a->options, option, arg); 204 option = NULL; 205 } else { 206 a->argv[a->argc++] = arg; 207 } 208 } 209 if(option) { 210 fprintf(stderr, 211 "Missing argument for option -%c\n\n", optchar); 212 cmd_args_free(a); 213 return NULL; 214 } 215 216 return a; 217 } 218 219 char* cmd_getoption(CmdArgs *arg, const char *name) { 220 return cxMapGet(arg->options, cx_hash_key_str(name)); 221 } 222