1 module aurorafw.core.opt; 2 3 /**************************************************************************** 4 ** ┌─┐┬ ┬┬─┐┌─┐┬─┐┌─┐ ┌─┐┬─┐┌─┐┌┬┐┌─┐┬ ┬┌─┐┬─┐┬┌─ 5 ** ├─┤│ │├┬┘│ │├┬┘├─┤ ├┤ ├┬┘├─┤│││├┤ ││││ │├┬┘├┴┐ 6 ** ┴ ┴└─┘┴└─└─┘┴└─┴ ┴ └ ┴└─┴ ┴┴ ┴└─┘└┴┘└─┘┴└─┴ ┴ 7 ** A Powerful General Purpose Framework 8 ** More information in: https://aurora-fw.github.io/ 9 ** 10 ** Copyright (C) 2018 Aurora Framework, All rights reserved. 11 ** 12 ** This file is part of the Aurora Framework. This framework is free 13 ** software; you can redistribute it and/or modify it under the terms of 14 ** the GNU Lesser General Public License version 3 as published by the 15 ** Free Software Foundation and appearing in the file LICENSE included in 16 ** the packaging of this file. Please review the following information to 17 ** ensure the GNU Lesser General Public License version 3 requirements 18 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 19 ****************************************************************************/ 20 21 import aurorafw.core.debugmanager : debugMsgPrefix; 22 import std.algorithm.searching : find; 23 import std.range.primitives : empty; 24 25 @safe pure struct OptionHandler { 26 struct Element { 27 string opt; 28 string desc; 29 } 30 31 struct SplitedElement { 32 bool active; 33 size_t count; 34 35 private: 36 string optLong; 37 string optShort; 38 string desc; 39 40 ptrdiff_t valpos; 41 } 42 43 enum OptionType { 44 Posix, 45 Windows, 46 None 47 } 48 49 this(string[] args, OptionType type = __currentType) 50 { 51 _args = args; 52 _type = type; 53 } 54 55 void add(Element opte) 56 { 57 import std.array : split; 58 immutable string[] elems = split(opte.opt, "|"); 59 SplitedElement sopte; 60 61 assert(elems.length == 1, "Blank option elements not allowed!"); 62 63 switch(_type) 64 { 65 case OptionType.Posix: 66 if(elems.length > 1) 67 { 68 sopte.optShort = "-" ~ ((elems[0].length < elems[1].length) ? elems[0] : elems[1]); 69 sopte.optLong = "--" ~ ((elems[0].length > elems[1].length) ? elems[0] : elems[1]); 70 } 71 else if (elems[0].length > 1) 72 { 73 sopte.optLong = "--" ~ elems[0]; 74 } 75 else 76 { 77 sopte.optShort = "-" ~ elems[0]; 78 } 79 break; 80 81 case OptionType.Windows: 82 if (elems.length > 1) 83 { 84 sopte.optShort = "/" ~ ((elems[0].length < elems[1].length) ? elems[0] : elems[1]); 85 sopte.optLong = "/" ~ ((elems[0].length > elems[1].length) ? elems[0] : elems[1]); 86 } 87 else 88 { 89 sopte.optLong = "/" ~ elems[0]; 90 } 91 break; 92 93 case OptionType.None: 94 default: 95 if(elems.length > 1) 96 { 97 sopte.optShort = ((elems[0].length < elems[1].length) ? elems[0] : elems[1]); 98 sopte.optLong = ((elems[0].length > elems[1].length) ? elems[0] : elems[1]); 99 } 100 else 101 { 102 sopte.optLong = elems[0]; 103 } 104 break; 105 } 106 sopte.desc = opte.desc; 107 108 foreach(size_t i, string arg; _args) 109 if((find(arg, sopte.optLong).empty && 110 ((arg.length == sopte.optLong.length) || 111 ((arg.length > sopte.optLong.length) && (arg[sopte.optLong.length .. arg.length][0] == '=')) )) 112 || (find(arg, sopte.optShort).empty && (arg.length == sopte.optShort.length )) ) 113 { 114 if(arg.length > sopte.optLong.length) sopte.valpos = sopte.optLong.length; 115 else sopte.valpos = -1; 116 sopte.active = true; 117 sopte.count = i; 118 } 119 else { 120 sopte.active = false; 121 } 122 123 _opts ~= sopte; 124 } 125 126 pragma(inline, true) void add(string opt, string desc) { add(Element(opt, desc)); } 127 128 void add(Element[] mopte) 129 { 130 foreach(Element opte; mopte) 131 add(opte); 132 } 133 134 SplitedElement option(string opt) 135 { 136 foreach(SplitedElement sopte; _opts) 137 if(!find(sopte.optLong, opt).empty || !find(sopte.optShort, opt).empty) 138 return sopte; 139 140 assert(0, "Invalid option name!"); 141 } 142 143 string value(SplitedElement sopte) 144 { 145 if(sopte.valpos == -1) 146 return _args[sopte.count+1]; 147 else 148 return _args[sopte.count][sopte.valpos .. _args[sopte.count].length]; 149 } 150 151 pragma(inline, true) string value(string opt) { return value(option(opt)); } 152 153 void print(string fmt = " %s\t%s\t\t%s") @safe 154 { 155 pragma(msg, debugMsgPrefix, "FIXME: Need to be implemented"); 156 } 157 158 private: 159 string[] _args; 160 SplitedElement[] _opts; 161 OptionType _type; 162 163 version(Windows) enum OptionType __currentType = OptionType.Windows; 164 else enum OptionType __currentType = OptionType.Posix; 165 }