|
Packit |
8f70b4 |
/*
|
|
Packit |
8f70b4 |
* lftp - file transfer program
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* Copyright (c) 1996-2017 by Alexander V. Lukyanov (lav@yars.free.net)
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
8f70b4 |
* it under the terms of the GNU General Public License as published by
|
|
Packit |
8f70b4 |
* the Free Software Foundation; either version 3 of the License, or
|
|
Packit |
8f70b4 |
* (at your option) any later version.
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* This program is distributed in the hope that it will be useful,
|
|
Packit |
8f70b4 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
8f70b4 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
8f70b4 |
* GNU General Public License for more details.
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* You should have received a copy of the GNU General Public License
|
|
Packit |
8f70b4 |
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
8f70b4 |
*/
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#include <config.h>
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#include <fnmatch.h>
|
|
Packit |
8f70b4 |
#include <ctype.h>
|
|
Packit |
8f70b4 |
#include <unistd.h>
|
|
Packit |
8f70b4 |
#include <stdlib.h>
|
|
Packit |
8f70b4 |
#include <math.h>
|
|
Packit |
8f70b4 |
#include <sys/types.h>
|
|
Packit |
8f70b4 |
#include <sys/stat.h>
|
|
Packit |
8f70b4 |
#include <errno.h>
|
|
Packit |
8f70b4 |
#include <limits.h>
|
|
Packit |
8f70b4 |
CDECL_BEGIN
|
|
Packit |
8f70b4 |
#include "regex.h"
|
|
Packit |
8f70b4 |
CDECL_END
|
|
Packit |
8f70b4 |
#include "ResMgr.h"
|
|
Packit |
8f70b4 |
#include "SMTask.h"
|
|
Packit |
8f70b4 |
#include "misc.h"
|
|
Packit |
8f70b4 |
#include "StringSet.h"
|
|
Packit |
8f70b4 |
#include "log.h"
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
xlist_head<Resource> Resource::all_list;
|
|
Packit |
8f70b4 |
xmap<ResType*> *ResType::types_by_name;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int ResType::VarNameCmp(const char *good_name,const char *name)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int res=EXACT_PREFIX+EXACT_NAME;
|
|
Packit |
8f70b4 |
const char *colon=strchr(good_name,':');
|
|
Packit |
8f70b4 |
if(colon && !strchr(name,':'))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
good_name=colon+1;
|
|
Packit |
8f70b4 |
res|=SUBSTR_PREFIX;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
while(*good_name || *name)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(*good_name==*name
|
|
Packit |
8f70b4 |
|| (*good_name && *name && strchr("-_",*good_name) && strchr("-_",*name)))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
good_name++;
|
|
Packit |
8f70b4 |
name++;
|
|
Packit |
8f70b4 |
continue;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(*name && !*good_name)
|
|
Packit |
8f70b4 |
return DIFFERENT;
|
|
Packit |
8f70b4 |
if((!*name && *good_name)
|
|
Packit |
8f70b4 |
|| (strchr("-_:",*name) && !strchr("-_:",*good_name)))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
good_name++;
|
|
Packit |
8f70b4 |
if(strchr(name,':'))
|
|
Packit |
8f70b4 |
res|=SUBSTR_PREFIX;
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
res|=SUBSTR_NAME;
|
|
Packit |
8f70b4 |
continue;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return DIFFERENT;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return res;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool ResType::IsAlias() const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return closure_valid==ResMgr::AliasValidate;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *ResType::FindVar(const char *name,const ResType **type,const char **re_closure)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const ResType *exact_proto=0;
|
|
Packit |
8f70b4 |
const ResType *exact_name=0;
|
|
Packit |
8f70b4 |
int sub=0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
*type=types_by_name->lookup(name);
|
|
Packit |
8f70b4 |
if(*type)
|
|
Packit |
8f70b4 |
goto found; // exact match
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
for(const ResType *type_scan=types_by_name->each_begin(); type_scan; type_scan=types_by_name->each_next())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
switch(VarNameCmp(type_scan->name,name))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
case EXACT_PREFIX+EXACT_NAME:
|
|
Packit |
8f70b4 |
*type=type_scan;
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
case EXACT_PREFIX+SUBSTR_NAME:
|
|
Packit |
8f70b4 |
if(!exact_proto && !exact_name)
|
|
Packit |
8f70b4 |
sub=0;
|
|
Packit |
8f70b4 |
exact_proto=*type=type_scan;
|
|
Packit |
8f70b4 |
sub++;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case SUBSTR_PREFIX+EXACT_NAME:
|
|
Packit |
8f70b4 |
if(!exact_proto && !exact_name)
|
|
Packit |
8f70b4 |
sub=0;
|
|
Packit |
8f70b4 |
exact_name=*type=type_scan;
|
|
Packit |
8f70b4 |
sub++;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
case SUBSTR_PREFIX+SUBSTR_NAME:
|
|
Packit |
8f70b4 |
if(exact_proto || exact_name)
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
sub++;
|
|
Packit |
8f70b4 |
*type=type_scan;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
default:
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(!*type && sub==0)
|
|
Packit |
8f70b4 |
return _("no such variable");
|
|
Packit |
8f70b4 |
if(sub==1)
|
|
Packit |
8f70b4 |
goto found;
|
|
Packit |
8f70b4 |
*type=0;
|
|
Packit |
8f70b4 |
return _("ambiguous variable name");
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
found:
|
|
Packit |
8f70b4 |
if((*type)->IsAlias()) {
|
|
Packit |
8f70b4 |
const char *alias_c=(*type)->GetAliasTarget();
|
|
Packit |
8f70b4 |
char *alias=alloca_strdup(alias_c);
|
|
Packit |
8f70b4 |
char *slash=strchr(alias,'/');
|
|
Packit |
8f70b4 |
if(slash) {
|
|
Packit |
8f70b4 |
*slash=0;
|
|
Packit |
8f70b4 |
if(re_closure)
|
|
Packit |
8f70b4 |
*re_closure=alias_c+(slash+1-alias);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
*type=types_by_name->lookup(alias);
|
|
Packit |
8f70b4 |
if(!*type)
|
|
Packit |
8f70b4 |
return "invalid compatibility alias";
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const ResType *ResType::FindRes(const char *name)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const ResType *type;
|
|
Packit |
8f70b4 |
const char *msg=FindVar(name,&type);
|
|
Packit |
8f70b4 |
if(msg)
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
return type;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *ResType::Set(const char *name,const char *cclosure,const char *cvalue,bool def)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
ResType *type;
|
|
Packit |
8f70b4 |
// find type of given variable
|
|
Packit |
8f70b4 |
const char *msg=FindVar(name,&type,&cclosure);
|
|
Packit |
8f70b4 |
if(msg)
|
|
Packit |
8f70b4 |
return msg;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
return type->Set(cclosure,cvalue,def);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *ResType::Set(const char *cclosure,const char *cvalue,bool def)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *msg=0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
xstring_c value(cvalue);
|
|
Packit |
8f70b4 |
if(value && val_valid && (msg=val_valid(&value))!=0)
|
|
Packit |
8f70b4 |
return msg;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
xstring_c closure(cclosure);
|
|
Packit |
8f70b4 |
if((closure || closure_valid==ResMgr::HasClosure)
|
|
Packit |
8f70b4 |
&& closure_valid && (msg=closure_valid(&closure))!=0)
|
|
Packit |
8f70b4 |
return msg;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool need_reconfig=false;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
xlist_for_each(Resource,*(type_value_list),node,scan)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// find the old value
|
|
Packit |
8f70b4 |
if(closure==scan->closure || !xstrcmp(scan->closure,closure))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(def)
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
need_reconfig=true;
|
|
Packit |
8f70b4 |
delete scan;
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(value)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
(void)new Resource(this,closure,value,def);
|
|
Packit |
8f70b4 |
need_reconfig=true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(need_reconfig)
|
|
Packit |
8f70b4 |
ResClient::ReconfigAll(name);
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int ResMgr::ResourceCompare(const Resource *ar,const Resource *br)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int diff=strcmp(ar->type->name,br->type->name);
|
|
Packit |
8f70b4 |
if(diff)
|
|
Packit |
8f70b4 |
return diff;
|
|
Packit |
8f70b4 |
if(ar->closure==br->closure)
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
if(ar->closure==0)
|
|
Packit |
8f70b4 |
return -1;
|
|
Packit |
8f70b4 |
if(br->closure==0)
|
|
Packit |
8f70b4 |
return 1;
|
|
Packit |
8f70b4 |
return strcmp(ar->closure,br->closure);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void Resource::Format(xstring& buf) const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
buf.appendf("set %s",type->name);
|
|
Packit |
8f70b4 |
const char *s=closure;
|
|
Packit |
8f70b4 |
if(s)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
buf.append('/');
|
|
Packit |
8f70b4 |
bool par=false;
|
|
Packit |
8f70b4 |
if(strcspn(s," \t>|;&")!=strlen(s))
|
|
Packit |
8f70b4 |
par=true;
|
|
Packit |
8f70b4 |
if(par)
|
|
Packit |
8f70b4 |
buf.append('"');
|
|
Packit |
8f70b4 |
while(*s)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(strchr("\"\\",*s))
|
|
Packit |
8f70b4 |
buf.append('\\');
|
|
Packit |
8f70b4 |
buf.append(*s++);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(par)
|
|
Packit |
8f70b4 |
buf.append('"');
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
buf.append(' ');
|
|
Packit |
8f70b4 |
s=value;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool par=false;
|
|
Packit |
8f70b4 |
if(*s==0 || strcspn(s," \t>|;&")!=strlen(s))
|
|
Packit |
8f70b4 |
par=true;
|
|
Packit |
8f70b4 |
if(par)
|
|
Packit |
8f70b4 |
buf.append('"');
|
|
Packit |
8f70b4 |
while(*s)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(strchr("\"\\",*s))
|
|
Packit |
8f70b4 |
buf.append('\\');
|
|
Packit |
8f70b4 |
buf.append(*s++);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(par)
|
|
Packit |
8f70b4 |
buf.append('"');
|
|
Packit |
8f70b4 |
buf.append('\n');
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
static int PResourceCompare(const Resource *const*a,const Resource *const*b)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return ResMgr::ResourceCompare(*a,*b);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
static int RefResourceCompare(const Ref<Resource> *a,const Ref<Resource> *b)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return ResMgr::ResourceCompare(*a,*b);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
char *ResType::Format(bool with_defaults,bool only_defaults)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
RefArray<Resource> created;
|
|
Packit |
8f70b4 |
if(with_defaults || only_defaults)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
for(ResType *dscan=types_by_name->each_begin(); dscan; dscan=types_by_name->each_next())
|
|
Packit |
8f70b4 |
if((only_defaults || dscan->SimpleQuery(0)==0) && !dscan->IsAlias())
|
|
Packit |
8f70b4 |
created.append(new Resource(dscan,
|
|
Packit |
8f70b4 |
0,xstrdup(dscan->defvalue?dscan->defvalue:"(nil)")));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
xstring buf("");
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!only_defaults)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// just created Resources are also in all_list.
|
|
Packit |
8f70b4 |
xarray<const Resource*> arr;
|
|
Packit |
8f70b4 |
xlist_for_each(Resource,Resource::all_list,node,scan) {
|
|
Packit |
8f70b4 |
if(!scan->def || with_defaults)
|
|
Packit |
8f70b4 |
arr.append(scan);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
arr.qsort(PResourceCompare);
|
|
Packit |
8f70b4 |
for(int i=0; i
|
|
Packit |
8f70b4 |
arr[i]->Format(buf);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
created.qsort(RefResourceCompare);
|
|
Packit |
8f70b4 |
for(int i=0; i
|
|
Packit |
8f70b4 |
created[i]->Format(buf);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
return buf.borrow();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
char **ResType::Generator(void)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
StringSet res;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
for(ResType *dscan=types_by_name->each_begin(); dscan; dscan=types_by_name->each_next())
|
|
Packit |
8f70b4 |
if(!dscan->IsAlias())
|
|
Packit |
8f70b4 |
res.Append(dscan->name);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
res.qsort();
|
|
Packit |
8f70b4 |
return res.borrow();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *ResMgr::BoolValidate(xstring_c *value)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *v=*value;
|
|
Packit |
8f70b4 |
const char *newval=0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
switch(v[0])
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
case 't': newval="true"; break;
|
|
Packit |
8f70b4 |
case 'T': newval="True"; break;
|
|
Packit |
8f70b4 |
case 'f': newval="false"; break;
|
|
Packit |
8f70b4 |
case 'F': newval="False"; break;
|
|
Packit |
8f70b4 |
case 'y': newval="yes"; break;
|
|
Packit |
8f70b4 |
case 'Y': newval="Yes"; break;
|
|
Packit |
8f70b4 |
case 'n': newval="no"; break;
|
|
Packit |
8f70b4 |
case 'N': newval="No"; break;
|
|
Packit |
8f70b4 |
case '1': newval="1"; break;
|
|
Packit |
8f70b4 |
case '0': newval="0"; break;
|
|
Packit |
8f70b4 |
case '+': newval="+"; break;
|
|
Packit |
8f70b4 |
case '-': newval="-"; break;
|
|
Packit |
8f70b4 |
case 'o': newval=(v[1]=='f' || v[1]=='F')?"off":"on"; break;
|
|
Packit |
8f70b4 |
case 'O': newval=(v[1]=='f' || v[1]=='F')?"Off":"On"; break;
|
|
Packit |
8f70b4 |
default:
|
|
Packit |
8f70b4 |
return _("invalid boolean value");
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(strcmp(v,newval))
|
|
Packit |
8f70b4 |
value->set(newval);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *ResMgr::TriBoolValidate(xstring_c *value)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!BoolValidate(value))
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
/* not bool */
|
|
Packit |
8f70b4 |
const char *v=*value;
|
|
Packit |
8f70b4 |
const char *newval=0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
switch(v[0])
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
case 'a': newval="auto"; break;
|
|
Packit |
8f70b4 |
case 'A': newval="Auto"; break;
|
|
Packit |
8f70b4 |
default:
|
|
Packit |
8f70b4 |
return _("invalid boolean/auto value");
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(strcmp(v,newval))
|
|
Packit |
8f70b4 |
value->set(newval);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
static const char power_letter[] =
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
0, /* not used */
|
|
Packit |
8f70b4 |
'K', /* kibi ('k' for kilo is a special case) */
|
|
Packit |
8f70b4 |
'M', /* mega or mebi */
|
|
Packit |
8f70b4 |
'G', /* giga or gibi */
|
|
Packit |
8f70b4 |
'T', /* tera or tebi */
|
|
Packit |
8f70b4 |
'P', /* peta or pebi */
|
|
Packit |
8f70b4 |
'E', /* exa or exbi */
|
|
Packit |
8f70b4 |
'Z', /* zetta or 2**70 */
|
|
Packit |
8f70b4 |
'Y' /* yotta or 2**80 */
|
|
Packit |
8f70b4 |
};
|
|
Packit |
8f70b4 |
static unsigned long long get_power_multiplier(char p)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *scan=power_letter;
|
|
Packit |
8f70b4 |
const int scale=1024;
|
|
Packit |
8f70b4 |
unsigned long long mul=1;
|
|
Packit |
8f70b4 |
p=toupper(p);
|
|
Packit |
8f70b4 |
while(scan
|
|
Packit |
8f70b4 |
if(p==*scan)
|
|
Packit |
8f70b4 |
return mul;
|
|
Packit |
8f70b4 |
mul*=scale;
|
|
Packit |
8f70b4 |
scan++;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *ResMgr::NumberValidate(xstring_c *value)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *v=*value;
|
|
Packit |
8f70b4 |
const char *end=v;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
(void)strtoll(v,const_cast<char**>(&end),0);
|
|
Packit |
8f70b4 |
unsigned long long m=get_power_multiplier(*end);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(v==end || m==0 || end[m>1])
|
|
Packit |
8f70b4 |
return _("invalid number");
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
const char *ResMgr::FloatValidate(xstring_c *value)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *v=*value;
|
|
Packit |
8f70b4 |
const char *end=v;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
(void)strtod(v,const_cast<char**>(&end));
|
|
Packit |
8f70b4 |
unsigned long long m=get_power_multiplier(*end);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(v==end || m==0 || end[m>1])
|
|
Packit |
8f70b4 |
return _("invalid floating point number");
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
const char *ResMgr::UNumberValidate(xstring_c *value)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *v=*value;
|
|
Packit |
8f70b4 |
const char *end=v;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
(void)strtoull(v,const_cast<char**>(&end),0);
|
|
Packit |
8f70b4 |
unsigned long long m=get_power_multiplier(*end);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!isdigit((unsigned char)v[0])
|
|
Packit |
8f70b4 |
|| v==end || m==0 || end[m>1])
|
|
Packit |
8f70b4 |
return _("invalid unsigned number");
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
const char *ResMgr::AliasValidate(xstring_c *)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return "";
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
unsigned long long ResValue::to_unumber(unsigned long long max) const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if (is_nil())
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
const char *end=s;
|
|
Packit |
8f70b4 |
unsigned long long v=strtoull(s,const_cast<char**>(&end),0);
|
|
Packit |
8f70b4 |
unsigned long long m=get_power_multiplier(*end);
|
|
Packit |
8f70b4 |
unsigned long long vm=v*m;
|
|
Packit |
8f70b4 |
if(vm/m!=v || vm>max)
|
|
Packit |
8f70b4 |
return max;
|
|
Packit |
8f70b4 |
return vm;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
long long ResValue::to_number(long long min,long long max) const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if (is_nil())
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
const char *end=s;
|
|
Packit |
8f70b4 |
long long v=strtoll(s,const_cast<char**>(&end),0);
|
|
Packit |
8f70b4 |
long long m=get_power_multiplier(*end);
|
|
Packit |
8f70b4 |
long long vm=v*m;
|
|
Packit |
8f70b4 |
if(vm/m!=v)
|
|
Packit |
8f70b4 |
return v>0?max:min;
|
|
Packit |
8f70b4 |
if(vm>max)
|
|
Packit |
8f70b4 |
return max;
|
|
Packit |
8f70b4 |
if(vm
|
|
Packit |
8f70b4 |
return min;
|
|
Packit |
8f70b4 |
return vm;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
ResValue::operator int() const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return to_number(INT_MIN,INT_MAX);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
ResValue::operator long() const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return to_number(LONG_MIN,LONG_MAX);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
ResValue::operator unsigned() const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return to_unumber(UINT_MAX);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
ResValue::operator unsigned long() const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return to_unumber(ULONG_MAX);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
bool ResValue::to_tri_bool(bool a) const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(*s=='a' || *s=='A')
|
|
Packit |
8f70b4 |
return a;
|
|
Packit |
8f70b4 |
return to_bool();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
Resource::Resource(ResType *type,const char *closure,const char *value,bool def)
|
|
Packit |
8f70b4 |
: type(type), value(value), closure(closure), def(def), all_node(this), type_value_node(this)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
all_list.add_tail(all_node);
|
|
Packit |
8f70b4 |
type->type_value_list->add_tail(type_value_node);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
Resource::~Resource()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
all_node.remove();
|
|
Packit |
8f70b4 |
type_value_node.remove();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool Resource::ClosureMatch(const char *cl_data)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!closure && !cl_data)
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
if(!(closure && cl_data))
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
// a special case for domain name match (i.e. example.org matches *.example.org)
|
|
Packit |
8f70b4 |
if(closure[0]=='*' && closure[1]=='.' && !strcmp(closure+2,cl_data))
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
if(0==fnmatch(closure,cl_data,FNM_PATHNAME))
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
// try to match basename; helps matching torrent metadata url to *.torrent
|
|
Packit |
8f70b4 |
const char *bn=basename_ptr(cl_data);
|
|
Packit |
8f70b4 |
if(bn!=cl_data && 0==fnmatch(closure,bn,FNM_PATHNAME))
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *ResMgr::QueryNext(const char *name,const char **closure,Resource **ptr)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
xlist<Resource> *node=0;
|
|
Packit |
8f70b4 |
if(*ptr==0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const ResType *type=FindRes(name);
|
|
Packit |
8f70b4 |
if(!type) {
|
|
Packit |
8f70b4 |
*ptr=0;
|
|
Packit |
8f70b4 |
*closure=0;
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
node=type->type_value_list->get_next();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
node=(*ptr)->type_value_node.get_next();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
*ptr=node->get_obj();
|
|
Packit |
8f70b4 |
if(*ptr) {
|
|
Packit |
8f70b4 |
*closure=(*ptr)->closure;
|
|
Packit |
8f70b4 |
return (*ptr)->value;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
*closure=0;
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *ResType::SimpleQuery(const char *closure) const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// find the value
|
|
Packit |
8f70b4 |
xlist_for_each(Resource,*(type_value_list),node,scan)
|
|
Packit |
8f70b4 |
if(scan->ClosureMatch(closure))
|
|
Packit |
8f70b4 |
return scan->value;
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
ResValue ResMgr::Query(const char *name,const char *closure)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *msg;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const ResType *type;
|
|
Packit |
8f70b4 |
// find type of given variable
|
|
Packit |
8f70b4 |
msg=FindVar(name,&type);
|
|
Packit |
8f70b4 |
if(msg)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// debug only
|
|
Packit |
8f70b4 |
// fprintf(stderr,_("Query of variable `%s' failed: %s\n"),name,msg);
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
return type->Query(closure);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
ResValue ResType::Query(const char *closure) const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *v=0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(closure)
|
|
Packit |
8f70b4 |
v=SimpleQuery(closure);
|
|
Packit |
8f70b4 |
if(!v)
|
|
Packit |
8f70b4 |
v=SimpleQuery(0);
|
|
Packit |
8f70b4 |
if(!v)
|
|
Packit |
8f70b4 |
v=defvalue;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
return v;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool ResMgr::str2bool(const char *s)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return(strchr("TtYy1+",s[0])!=0 || !strcasecmp(s,"on"));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
ResDecl::ResDecl(const char *a_name,const char *a_defvalue,ResValValid *a_val_valid,ResClValid *a_closure_valid)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
name=a_name;
|
|
Packit |
8f70b4 |
defvalue=a_defvalue;
|
|
Packit |
8f70b4 |
val_valid=a_val_valid;
|
|
Packit |
8f70b4 |
closure_valid=a_closure_valid;
|
|
Packit |
8f70b4 |
Register();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
ResDecls::ResDecls(ResType *array)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
while(array->name)
|
|
Packit |
8f70b4 |
array++->Register();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
ResDecls::ResDecls(ResType *r1,ResType *r2,...)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
r.append(r1);
|
|
Packit |
8f70b4 |
r1->Register();
|
|
Packit |
8f70b4 |
if(!r2)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
r.append(r2);
|
|
Packit |
8f70b4 |
r2->Register();
|
|
Packit |
8f70b4 |
va_list v;
|
|
Packit |
8f70b4 |
va_start(v,r2);
|
|
Packit |
8f70b4 |
while((r1=va_arg(v,ResType *))!=0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
r1->Register();
|
|
Packit |
8f70b4 |
r.append(r1);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
va_end(v);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
ResDecls::~ResDecls()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
for(int i=0; i
|
|
Packit |
8f70b4 |
r[i]->Unregister();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void ResType::Register()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!types_by_name)
|
|
Packit |
8f70b4 |
types_by_name=new xmap<ResType*>;
|
|
Packit |
8f70b4 |
types_by_name->add(name,this);
|
|
Packit |
8f70b4 |
if(!type_value_list)
|
|
Packit |
8f70b4 |
type_value_list=new xlist_head<Resource>();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void ResType::Unregister()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(types_by_name)
|
|
Packit |
8f70b4 |
types_by_name->remove(name);
|
|
Packit |
8f70b4 |
if(type_value_list) {
|
|
Packit |
8f70b4 |
// remove all resources of this type
|
|
Packit |
8f70b4 |
xlist_for_each_safe(Resource,*type_value_list,node,scan,next)
|
|
Packit |
8f70b4 |
delete scan;
|
|
Packit |
8f70b4 |
delete type_value_list;
|
|
Packit |
8f70b4 |
type_value_list=0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void TimeIntervalR::init(const char *s)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
double interval=0;
|
|
Packit |
8f70b4 |
infty=false;
|
|
Packit |
8f70b4 |
error_text=0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!strncasecmp(s,"inf",3)
|
|
Packit |
8f70b4 |
|| !strcasecmp(s,"forever")
|
|
Packit |
8f70b4 |
|| !strcasecmp(s,"never"))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
infty=true;
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
int pos=0;
|
|
Packit |
8f70b4 |
for(;;)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
double prec;
|
|
Packit |
8f70b4 |
char ch='s';
|
|
Packit |
8f70b4 |
int pos1=strlen(s+pos);
|
|
Packit |
8f70b4 |
int n=sscanf(s+pos,"%lf%c%n",&prec,&ch,&pos1);
|
|
Packit |
8f70b4 |
if(n<1)
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
ch=tolower((unsigned char)ch);
|
|
Packit |
8f70b4 |
if(ch=='m')
|
|
Packit |
8f70b4 |
prec*=MINUTE;
|
|
Packit |
8f70b4 |
else if(ch=='h')
|
|
Packit |
8f70b4 |
prec*=HOUR;
|
|
Packit |
8f70b4 |
else if(ch=='d')
|
|
Packit |
8f70b4 |
prec*=DAY;
|
|
Packit |
8f70b4 |
else if(ch!='s')
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
error_text=_("Invalid time unit letter, only [smhd] are allowed.");
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
interval+=prec;
|
|
Packit |
8f70b4 |
pos+=pos1;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(pos==0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
error_text=_("Invalid time format. Format is <time><unit>, e.g. 2h30m.");
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
TimeDiff::Set(interval);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *ResMgr::TimeIntervalValidate(xstring_c *s)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
TimeIntervalR t(*s);
|
|
Packit |
8f70b4 |
if(t.Error())
|
|
Packit |
8f70b4 |
return t.ErrorText();
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void NumberPair::init(char sep1,const char *s)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
sep=sep1;
|
|
Packit |
8f70b4 |
Set(s);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
long long NumberPair::parse1(const char *s)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!s || !*s)
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
const char *end=s;
|
|
Packit |
8f70b4 |
long long v=strtoll(s,const_cast<char**>(&end),0);
|
|
Packit |
8f70b4 |
long long m=get_power_multiplier(*end);
|
|
Packit |
8f70b4 |
if(s==end || m==0 || end[m>1]) {
|
|
Packit |
8f70b4 |
error_text=_("invalid number");
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
long long vm=v*m;
|
|
Packit |
8f70b4 |
if(vm/m!=v) {
|
|
Packit |
8f70b4 |
error_text=_("integer overflow");
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return vm;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void NumberPair::Set(const char *s0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
n1=n2=0;
|
|
Packit |
8f70b4 |
no_n1=no_n2=true;
|
|
Packit |
8f70b4 |
error_text=0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!s0)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
char *s1=alloca_strdup(s0);
|
|
Packit |
8f70b4 |
char *s2=s1;
|
|
Packit |
8f70b4 |
while(*s2 && *s2!=sep && *s2!=':')
|
|
Packit |
8f70b4 |
s2++;
|
|
Packit |
8f70b4 |
if(*s2)
|
|
Packit |
8f70b4 |
*s2++=0;
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
s2=0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
n1=parse1(s1);
|
|
Packit |
8f70b4 |
no_n1=!*s1;
|
|
Packit |
8f70b4 |
n2=(s2?parse1(s2):n1);
|
|
Packit |
8f70b4 |
no_n2=(s2 && !*s2);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!error_text && Log::global) {
|
|
Packit |
8f70b4 |
Log::global->Format(10,"%s translated to pair %lld%c%lld (%d,%d)\n",
|
|
Packit |
8f70b4 |
s0,n1,sep,n2,no_n1,no_n2);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
Range::Range(const char *s) : NumberPair('-')
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!strcasecmp(s,"full") || !strcasecmp(s,"any"))
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
Set(s);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
long long Range::Random()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
random_init();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(no_n1 && no_n2)
|
|
Packit |
8f70b4 |
return random();
|
|
Packit |
8f70b4 |
if(no_n2)
|
|
Packit |
8f70b4 |
return n1+random();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
return n1 + (long long)((n2-n1+1)*random01());
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *ResMgr::RangeValidate(xstring_c *s)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Range r(*s);
|
|
Packit |
8f70b4 |
if(r.Error())
|
|
Packit |
8f70b4 |
return r.ErrorText();
|
|
Packit |
8f70b4 |
char *colon=strchr(s->get_non_const(),':');
|
|
Packit |
8f70b4 |
if(colon)
|
|
Packit |
8f70b4 |
*colon='-';
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *ResMgr::ERegExpValidate(xstring_c *s)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(**s==0)
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
regex_t re;
|
|
Packit |
8f70b4 |
int err=regcomp(&re,*s,REG_EXTENDED|REG_NOSUB);
|
|
Packit |
8f70b4 |
if(err)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const int max_err_len=128;
|
|
Packit |
8f70b4 |
char *err_msg=xstring::tmp_buf(max_err_len);
|
|
Packit |
8f70b4 |
regerror(err,0,err_msg,max_err_len);
|
|
Packit |
8f70b4 |
return err_msg;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
regfree(&re);
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *ResMgr::IPv4AddrValidate(xstring_c *value)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!**value)
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
if(!is_ipv4_address(*value))
|
|
Packit |
8f70b4 |
return _("Invalid IPv4 numeric address");
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#if INET6
|
|
Packit |
8f70b4 |
const char *ResMgr::IPv6AddrValidate(xstring_c *value)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!**value)
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
if(!is_ipv6_address(*value))
|
|
Packit |
8f70b4 |
return _("Invalid IPv6 numeric address");
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *ResMgr::FileAccessible(xstring_c *value,int mode,bool want_dir)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!**value)
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
const char *f=expand_home_relative(*value);
|
|
Packit |
8f70b4 |
xstring_c cwd;
|
|
Packit |
8f70b4 |
const char *error=0;
|
|
Packit |
8f70b4 |
if(f[0]!='/')
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
xgetcwd_to(cwd);
|
|
Packit |
8f70b4 |
if(cwd)
|
|
Packit |
8f70b4 |
f=dir_file(cwd,f);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
struct stat st;
|
|
Packit |
8f70b4 |
if(stat(f,&st)<0)
|
|
Packit |
8f70b4 |
error=strerror(errno);
|
|
Packit |
8f70b4 |
else if(want_dir ^ S_ISDIR(st.st_mode))
|
|
Packit |
8f70b4 |
error=strerror(errno=want_dir?ENOTDIR:EISDIR);
|
|
Packit |
8f70b4 |
else if(access(f,mode)<0)
|
|
Packit |
8f70b4 |
error=strerror(errno);
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
value->set(f);
|
|
Packit |
8f70b4 |
return error;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
const char *ResMgr::FileReadable(xstring_c *value)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return FileAccessible(value,R_OK);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
const char *ResMgr::FileExecutable(xstring_c *value)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return FileAccessible(value,X_OK);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
const char *ResMgr::DirReadable(xstring_c *value)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return FileAccessible(value,R_OK|X_OK,true);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
const char *ResMgr::FileCreatable(xstring_c *value)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!**value)
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
const char *error=FileAccessible(value,W_OK,false);
|
|
Packit |
8f70b4 |
if(!error || (error && errno!=ENOENT))
|
|
Packit |
8f70b4 |
return error;
|
|
Packit |
8f70b4 |
const char *bn=basename_ptr(*value);
|
|
Packit |
8f70b4 |
xstring_c dir(dirname(*value));
|
|
Packit |
8f70b4 |
if(!*dir)
|
|
Packit |
8f70b4 |
xgetcwd_to(dir);
|
|
Packit |
8f70b4 |
error=FileAccessible(&dir,X_OK|W_OK,true);
|
|
Packit |
8f70b4 |
if(!error) // dir may be expanded, combine it with base file name.
|
|
Packit |
8f70b4 |
value->set(dir_file(dir,bn));
|
|
Packit |
8f70b4 |
return error;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#ifdef HAVE_ICONV
|
|
Packit |
8f70b4 |
CDECL_BEGIN
|
|
Packit |
8f70b4 |
# include <iconv.h>
|
|
Packit |
8f70b4 |
CDECL_END
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
const char *ResMgr::CharsetValidate(xstring_c *value)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!**value)
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
#ifdef HAVE_ICONV
|
|
Packit |
8f70b4 |
iconv_t ic=iconv_open(*value,*value);
|
|
Packit |
8f70b4 |
if(ic==(iconv_t)-1)
|
|
Packit |
8f70b4 |
return _("this encoding is not supported");
|
|
Packit |
8f70b4 |
iconv_close(ic);
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
#else
|
|
Packit |
8f70b4 |
return _("this encoding is not supported");
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *ResMgr::NoClosure(xstring_c *)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return _("no closure defined for this setting");
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *ResMgr::HasClosure(xstring_c *c)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!*c || !**c)
|
|
Packit |
8f70b4 |
return _("a closure is required for this setting");
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *ResMgr::UNumberPairValidate(xstring_c *value)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
NumberPair pair(':',*value);
|
|
Packit |
8f70b4 |
if(pair.Error())
|
|
Packit |
8f70b4 |
return pair.ErrorText();
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void ResValue::ToNumberPair(int &a,int &b) const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
NumberPair pair(':',s);
|
|
Packit |
8f70b4 |
if(pair.Error()) {
|
|
Packit |
8f70b4 |
a=b=0;
|
|
Packit |
8f70b4 |
} else {
|
|
Packit |
8f70b4 |
a=pair.N1();
|
|
Packit |
8f70b4 |
b=pair.HasN2()?pair.N2():a;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
xlist_head<ResClient> ResClient::list;
|
|
Packit |
8f70b4 |
ResValue ResClient::Query(const char *name,const char *closure) const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!strchr(name,':'))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *prefix=ResPrefix();
|
|
Packit |
8f70b4 |
name=xstring::cat(prefix,":",name,NULL);
|
|
Packit |
8f70b4 |
name=alloca_strdup(name);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(!closure)
|
|
Packit |
8f70b4 |
closure=ResClosure();
|
|
Packit |
8f70b4 |
return ResMgr::Query(name,closure);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
ResClient::ResClient()
|
|
Packit |
8f70b4 |
: node(this)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
list.add(node);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
ResClient::~ResClient()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
node.remove();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void ResClient::ReconfigAll(const char *r)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
xlist_for_each(ResClient,list,node,scan)
|
|
Packit |
8f70b4 |
scan->Reconfig(r);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool ResType::QueryBool(const char *closure) const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return Query(closure).to_bool();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
bool ResMgr::QueryBool(const char *name,const char *closure)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return Query(name,closure).to_bool();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
bool ResClient::QueryBool(const char *name,const char *closure) const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return Query(name,closure).to_bool();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
bool ResType::QueryTriBool(const char *closure,bool a) const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return Query(closure).to_tri_bool(a);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
bool ResMgr::QueryTriBool(const char *name,const char *closure,bool a)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return Query(name,closure).to_tri_bool(a);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
bool ResClient::QueryTriBool(const char *name,const char *closure,bool a) const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return Query(name,closure).to_tri_bool(a);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void ResType::ClassCleanup()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
xlist_for_each_safe(Resource,Resource::all_list,node,scan,next)
|
|
Packit |
8f70b4 |
delete scan;
|
|
Packit |
8f70b4 |
if(types_by_name) {
|
|
Packit |
8f70b4 |
for(ResType *t=types_by_name->each_begin(); t; t=types_by_name->each_next())
|
|
Packit |
8f70b4 |
t->Unregister();
|
|
Packit |
8f70b4 |
delete types_by_name; types_by_name=0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|