1 /* 2 * Command Line Option Parser 3 * 4 * File : optlist.c 5 * Purpose : Provide getopt style command line option parsing 6 * Author : Michael Dipperstein 7 * Date : August 1, 2007 8 * 9 **************************************************************************** 10 * 11 * OptList: A command line option parsing library 12 * Copyright (C) 2007, 2014 2018 by 13 * Michael Dipperstein (mdipperstein@gmail.com) 14 * 15 * This file is part of the OptList library. 16 * 17 * OptList is free software; you can redistribute it and/or modify it 18 * under the terms of the GNU Lesser General Public License as published by 19 * the Free Software Foundation; either version 3 of the License, or (at 20 * your option) any later version. 21 * 22 * OptList is distributed in the hope that it will be useful, but 23 * WITHOUT ANY WARRANTY; without even the implied warranty of 24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 25 * General Public License for more details. 26 * 27 * You should have received a copy of the GNU Lesser General Public License 28 * along with this program. If not, see <http://www.gnu.org/licenses/>. 29 * 30 */ 31 module optlist_d.optlist; 32 33 34 private static import core.memory; 35 private static import core.stdc.stdio; 36 private static import core.stdc.string; 37 38 /* CONSTANTS */ 39 40 /** 41 * this option has no arguement 42 */ 43 public enum OL_NOINDEX = -1; 44 45 /* TYPE DEFINITIONS */ 46 47 /** 48 * The structure for storing one of the command line options. 49 */ 50 public struct option_t 51 { 52 /** 53 * the current character option character 54 */ 55 char option; 56 57 /** 58 * pointer to arguments for this option 59 */ 60 char* argument; 61 62 /** 63 * index into argv[] containing the argument 64 */ 65 int argIndex; 66 67 /** 68 * the next option in the linked list 69 */ 70 .option_t* next; 71 } 72 73 /* FUNCTIONS */ 74 75 /** 76 * This function is similar to the POSIX function getopt. All options and their corresponding arguments are returned in a linked list. This function should only be called once per an option list and it does not modify argv or argc. 77 * 78 * Params: 79 * argc = the number of command line arguments (including the name of the executable) 80 * argv = pointer to the open binary file to write encoded output 81 * options = getopt style option list. A null terminated string of single character options. Follow an option with a colon to indicate that it requires an argument. 82 * 83 * Effects: Creates a link list of command line options and their arguments. 84 * 85 * NOTE: The caller is responsible for freeing up the option list when it is no longer needed. 86 * 87 * Returns: option_t type value where the option and arguement fields contain the next option symbol and its argument (if any). The argument field will be set to null if there are no arguments or if you specify an option with missing arguments or if memory allocation fails. The option field will be set to PO_NO_OPT if no more options are found. 88 */ 89 extern (C) 90 pure nothrow @trusted @nogc 91 public .option_t* GetOptList(const int argc, scope const char** argv, scope const char* options) 92 93 in 94 { 95 if (argc > 1) { 96 assert(argv != null); 97 assert(options != null); 98 } 99 } 100 101 do 102 { 103 /* start with first argument and nothing found */ 104 int nextArg = 1; 105 .option_t* head = null; 106 .option_t* tail = null; 107 108 /* loop through all of the command line arguments */ 109 while (nextArg < argc) { 110 size_t argIndex = 1; 111 112 while ((core.stdc..string.strlen(argv[nextArg]) > argIndex) && (argv[nextArg][0] == '-')) { 113 /* attempt to find a matching option */ 114 size_t optIndex = .MatchOpt(argv[nextArg][argIndex], options); 115 116 if (options[optIndex] == argv[nextArg][argIndex]) { 117 /* we found the matching option */ 118 if (head == null) { 119 head = .MakeOpt(options[optIndex], null, .OL_NOINDEX); 120 121 if (head == null) { 122 return null; 123 } 124 125 tail = head; 126 } else { 127 tail.next = .MakeOpt(options[optIndex], null, .OL_NOINDEX); 128 129 if (tail.next == null) { 130 .FreeOptList(head); 131 132 return null; 133 } 134 135 tail = tail.next; 136 } 137 138 if (options[optIndex + 1] == ':') { 139 /* the option found should have a text arguement */ 140 argIndex++; 141 142 if (core.stdc..string.strlen(argv[nextArg]) > argIndex) { 143 /* no space between argument and option */ 144 tail.argument = cast(char*)(&(argv[nextArg][argIndex])); 145 tail.argIndex = nextArg; 146 } else if (nextArg < argc) { 147 /* there must be space between the argument option */ 148 nextArg++; 149 tail.argument = cast(char*)(argv[nextArg]); 150 tail.argIndex = nextArg; 151 } 152 153 /* done with argv[nextArg] */ 154 break; 155 } 156 } 157 158 argIndex++; 159 } 160 161 nextArg++; 162 } 163 164 return head; 165 } 166 167 /** 168 * This function uses pureMalloc to allocate space for an option_t type structure and initailizes the structure with the values passed as a parameter. 169 * 170 * Params: 171 * option = this option character 172 * argument = pointer string containg the argument for option. Use null for no argument 173 * index = argv[index] contains argument use OL_NOINDEX for no argument 174 * 175 * Effects: A new option_t type variable is created on the heap. 176 * 177 * Returns: Pointer to newly created and initialized option_t type structure. null if space for structure can't be allocated. 178 */ 179 pure nothrow @trusted @nogc 180 private .option_t* MakeOpt(const char option, char* argument, const int index) 181 182 do 183 { 184 .option_t* opt = cast(.option_t*)(core.memory.pureMalloc(.option_t.sizeof)); 185 186 if (opt != null) { 187 opt.option = option; 188 opt.argument = argument; 189 opt.argIndex = index; 190 opt.next = null; 191 } else { 192 return null; 193 } 194 195 return opt; 196 } 197 198 /** 199 * This function will free all the elements in an option_t type linked list starting from the node passed as a parameter. 200 * 201 * Params: 202 * list = head of linked list to be freed 203 * 204 * Effects: All elements of the linked list pointed to by list will be freed and list will be set to null. 205 */ 206 extern (C) 207 pure nothrow @trusted @nogc 208 public void FreeOptList(.option_t* list) 209 210 do 211 { 212 .option_t* head = list; 213 list = null; 214 215 while (head != null) { 216 .option_t* next = head.next; 217 core.memory.pureFree(head); 218 head = next; 219 } 220 } 221 222 /** 223 * This function searches for an arguement in an option list. It will return the index to the option matching the arguement or the index to the null if none is found. 224 * 225 * Params: 226 * arguement = character arguement to be matched to an option in the option list 227 * options = getopt style option list. A null terminated string of single character options. Follow an option with a colon to indicate that it requires an argument. 228 * 229 * Returns: Index of argument in option list. Index of end of string if arguement does not appear in the option list. 230 */ 231 pure nothrow @trusted @nogc @live 232 private size_t MatchOpt(const char argument, scope const char* options) 233 234 in 235 { 236 assert(options != null); 237 } 238 239 do 240 { 241 size_t optIndex = 0; 242 243 /* attempt to find a matching option */ 244 while ((options[optIndex] != '\0') && (options[optIndex] != argument)) { 245 do { 246 optIndex++; 247 } while ((options[optIndex] != '\0') && (options[optIndex] == ':')); 248 } 249 250 return optIndex; 251 } 252 253 /** 254 * This is function accepts a pointer to the name of a file along with path information and returns a pointer to the first character that is not part of the path. 255 * 256 * Params: 257 * fullPath = pointer to an array of characters containing a file name and possible path modifiers. 258 * 259 * Returns: Returns a pointer to the first character after any path information. 260 */ 261 extern (C) 262 pure nothrow @trusted @nogc @live 263 public char* FindFileName(scope const char* fullPath) 264 265 do 266 { 267 /* path deliminators */ 268 static immutable char[3] delim = ['\\', '/', ':']; 269 270 /* start of file name */ 271 const (char)* start = fullPath; 272 273 /* find the first character after all file path delimiters */ 274 for (size_t i = 0; i < 3; i++) { 275 const (char)* tmp = core.stdc..string.strrchr(start, delim[i]); 276 277 if (tmp != null) { 278 start = tmp + 1; 279 } 280 } 281 282 return cast(char*)(start); 283 }