HI Все, я написал этот маленький помощник для работы с командной строкой. Я также обновил его для работы с фанки: --file'thing 'и разделил по мере необходимости спрашивающему.
Чтобы использовать другой тип символа, просто замените тип char тем, что вы используете. Это полностью рабочий пример, который вы можете вставить в main.cpp и запустить.
Код выполняет правильное экранирование, цитирование и: and = '"в качестве разделителей имени / значения для аргументов, поэтому вы можете сделать --flag: 1 или -file" c: \ test ". Пространство примечания используется в качестве разделителя параметров. будет выглядеть примерно так, чтобы использовать его в коде:
optparse opt(argstring);<br>
g_someint = strtoul(opt.get('--debuglevel','0'),0,0);<br>
g_somebool = opt.get('--flag')!=0;<br>
g_somestring = opt.get('--file','default.txt')
Чтобы ответить на вопрос: вы можете видеть, что это делает ваш код обработки аргументов настолько простым, что вам действительно не нужно его модульно модифицировать. Его читабельно и ремонтопригодно.
#include <string.h>
#include <stdio.h>
struct optparse{
optparse(const char *args, size_t len = 0) : first(0) {
size_t i;
if(!args)args = "";
if(!len)for(;args[len];len++);
for(buf=new char[len+1],i=0;i<len;i++)buf[i]=args[i];buf[i]=0;
opt *last = first;
char *c = buf, *b = c, *v = 0, g = 0, e = 0;
do{
if(*c=='\\') e = e?0:1;
else if(e?--e:1){
if(g){ if(*c == g) g = 0; }
else {
if(*c=='"' || *c=='\''){ if(b<c && !v) v = c; g = *c; }
else if(!v && (*c==':' || *c=='=')) v = c;
else if(*c==' '){
if(b<c)last = new opt(last,&first,b,c,v);
b = c+1, v = 0;
}
}
}
if(*c) c++;
if(!*c && b<c) last = new opt(last,&first,b,c,v);
}while(*c);
for(opt *i = first; i; i = i->next) *(i->ne) = 0, *(i->ve) = 0;
}
~optparse(){
delete buf;
while(first){
opt *t = first->next;
delete first;
first = t ;
}
}
const char *get( const char *name, const char *def= 0){
size_t l = strlen(name);
for(opt *i = first;i;i = i->next) if( _strnicmp( i->name, name, l ) == 0)
return i->value;
return def;
}
struct opt{
opt( opt *last, opt **first, char *s, char *e, char *v){
if(!*first) *first = this; if(last) last->next = this;
if(v && (*v=='\'' || *v=='"') && (*(e-1)=='\'' || *(e-1) == '"'))e--;
next = 0, name = s, value = v?v+1:"", ne = v?v:e, ve = e;
}
char *name, *value, *ne, *ve;
opt *next;
};
char *buf;
opt *first;
};
int main(){
const char *v, *test ="--debug:1 -file'c:\\something' --odd=10";
optparse opts(test);
if(v = opts.get("--debug")){
printf("debug flag value is %s\n",v);
}
for(optparse::opt *i=opts.first;i;i=i->next){
printf("name: %s value: %s\n",i->name,i->value);
}
}
Парсер очень легко настраивается для поддержки различных типов обработки аргументов.
Например, если вы замените
if(b<c)last = new opt(last,&first,b,c,v);
b = c+1, v = 0;
с
if(*b=='-' && *(c+1)!='-')v = v?v:c;
else{
if(b<c)last = new opt(last,&first,b,c,v);
b = c+1, v = 0;
}
Вы добавите возможность объединения аргументов, разделенных пробелом, в виде «значения», например: -debug 1
или --files a.txt b.txt c.txt
Также, если вам не нравится параметр: как разделенный параметр (это может быть неудобно в приложениях для Windows), просто удалите == ':'