/* ARISA - polymorphic value functions * Copyright (C) 2004 Carl Ritson * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include "arisa.h" #include static value_t *alloc_value(const char *name, size_t stringlen) { size_t namelen = (name != NULL ? strlen(name) + 1 : 0); value_t *v = xalloc(sizeof(value_t) + namelen + stringlen); v->name = name != NULL ? ((char *)v) + sizeof(value_t) : NULL; v->flags = 0; if(v->name != NULL) xstrncpy(v->name,name,namelen); if(strlen > 0) v->val.str = v->name + namelen; return v; } value_t *value_int32(const char *name, int32_t i32) { value_t *v = alloc_value(name,0); v->flags = VALUE_INT32; v->val.i32 = i32; return v; } value_t *value_uint32(const char *name, uint32_t ui32) { value_t *v = alloc_value(name,0); v->flags = VALUE_INT32 | VALUE_UNSIGNED; v->val.ui32 = ui32; return v; } value_t *value_int64(const char *name, int64_t i64) { value_t *v = alloc_value(name,0); v->flags = VALUE_INT64; v->val.i64 = i64; return v; } value_t *value_uint64(const char *name, uint64_t ui64) { value_t *v = alloc_value(name,0); v->flags = VALUE_INT64 | VALUE_UNSIGNED; v->val.ui64 = ui64; return v; } value_t *value_string(const char *name, const char *string) { size_t stringlen= string != NULL ? strlen(string) + 1 : 0; value_t *v = alloc_value(name,stringlen); v->flags = VALUE_STRING; if(stringlen > 0) xstrncpy(v->val.str,string,stringlen); else v->val.str = NULL; return v; } value_t *value_float(const char *name, float f) { return value_double(name, (double) f); } value_t *value_double(const char *name, double d) { value_t *v = alloc_value(name,0); v->flags = VALUE_DOUBLE; v->val.d = d; return v; } value_t *value_bool(const char *name, int flags, int b) { value_t *v = value_int32(name,(int32_t)b); v->flags |= VALUE_BOOL | (flags & (VALUE_BOOL_ONOFF | VALUE_BOOL_YESNO)); return v; } value_t *value_enum_str(const char *name, const char *str, int (*en)(const char *)) { value_t *v = value_string(name,str); assert(en != NULL); v->flags |= VALUE_ENUM; v->num.en = en; return v; } value_t *value_enum_val(const char *name, int val, const char *(*de)(int)) { value_t *v = value_int32(name,(int32_t)val); assert(de != NULL); v->flags |= VALUE_ENUM; v->num.de = de; return v; } static uint64_t int64_multiplier(const char *str) { uint64_t unit = 1024; uint64_t ret; int mult = 0; if(str == NULL) return 1; if(*str == '\0') return 1; switch(*str) { case 'k': case 'K': mult = 1; break; case 'm': case 'M': mult = 2; break; case 'g': case 'G': mult = 3; break; case 't': case 'T': mult = 4; break; case 'p': case 'P': mult = 5; break; default: return 1; } str++; if(*str == 'b' || *str == 'B') unit = 1000; for(ret = 1ULL; mult > 0; --mult) // note pre-deincrement ret *= unit; return ret; } static int32_t str_to_int32_t(const char *str, int32_t def) { int32_t ret = def; if(str != NULL) { char *p; ret = (int32_t)strtol(str,&p,10); ret *= (int32_t)int64_multiplier(p); } return ret; } static uint32_t str_to_uint32_t(const char *str, uint32_t def) { uint32_t ret = def; if(str != NULL) { char *p; ret = (uint32_t)strtoul(str,&p,10); ret *= (uint32_t)int64_multiplier(p); } return ret; } static int64_t str_to_int64_t(const char *str, int64_t def) { int64_t ret = def; if(str != NULL) { char *p; ret = (int64_t)strtoll(str,&p,10); ret *= (int64_t)int64_multiplier(p); } return ret; } static uint64_t str_to_uint64_t(const char *str, uint64_t def) { uint64_t ret = def; if(str != NULL) { char *p; ret = (uint64_t)strtoull(str,&p,10); ret *= (uint64_t)int64_multiplier(p); } return ret; } static float str_to_float(const char *str, float def) { if(str == NULL) return def; else return (float)strtof(str,NULL); } static double str_to_double(const char *str, double def) { if(str == NULL) return def; else return (double)strtod(str,NULL); } #define TYPE_CONVERTER(type) \ type ret = flags & VALUE_USE_DEFAULT ? def : 0; \ \ if(v->flags & VALUE_INT32) { \ ret = (type) (v->flags & VALUE_UNSIGNED \ ? v->val.ui32 : v->val.i32); \ } else if(v->flags & VALUE_INT64) { \ ret = (type) (v->flags & VALUE_UNSIGNED \ ? v->val.ui64 : v->val.i64); \ } else if(v->flags & VALUE_DOUBLE) { \ ret = (type) v->val.d; \ } else if(v->flags & VALUE_STRING) { \ if(!(v->flags & VALUE_ENUM)) { \ ret = (type) str_to_##type(v->val.str, \ flags & VALUE_USE_DEFAULT ? def : 0); \ } else { \ ret = (type) v->num.en(v->val.str); \ } \ } \ \ if(flags & VALUE_USE_MIN && ret < min) \ ret = flags & VALUE_USE_DEFAULT ? def : min; \ else if(flags & VALUE_USE_MAX && ret > max) \ ret = flags & VALUE_USE_DEFAULT ? def : max; \ \ return ret; int32_t value_as_int32(value_t *v, int flags, int32_t min, int32_t max, int32_t def) { TYPE_CONVERTER(int32_t) } uint32_t value_as_uint32(value_t *v, int flags, uint32_t min, uint32_t max, uint32_t def) { TYPE_CONVERTER(uint32_t) } int64_t value_as_int64(value_t *v, int flags, int64_t min, int64_t max, int64_t def) { TYPE_CONVERTER(int64_t) } uint64_t value_as_uint64(value_t *v, int flags, uint64_t min, uint64_t max, uint64_t def) { TYPE_CONVERTER(uint64_t) } float value_as_float(value_t *v, int flags, float min, float max, float def) { TYPE_CONVERTER(float) } double value_as_double(value_t *v, int flags, double min, double max, double def) { TYPE_CONVERTER(double) } char *value_as_string(value_t *v, int flags, char *buffer, size_t bufsize, char *def) { char *ret = NULL; if(v->flags & VALUE_STRING) { if(v->val.str != NULL && buffer != NULL) { xstrncpy(buffer,v->val.str,bufsize); ret = buffer; } else if(v->val.str != NULL && buffer == NULL) { ret = xstrdup(v->val.str); } } else if(v->flags & VALUE_BOOL) { ret = value_as_bool_str(v, v->flags & (VALUE_BOOL_ONOFF | VALUE_BOOL_YESNO), buffer,bufsize); } else if(v->flags & VALUE_INT32) { if(!(v->flags & VALUE_ENUM)) { if(buffer == NULL) { bufsize = 12; buffer = xalloc(bufsize); } snprintf(buffer,bufsize, v->flags & VALUE_UNSIGNED ? "%u" : "%d", v->flags & VALUE_UNSIGNED ? v->val.ui32 : v->val.i32); ret = buffer; } else { if(buffer != NULL) { xstrncpy(buffer,v->num.de((int)v->val.i32), bufsize); ret = buffer; } else ret = xstrdup(v->num.de((int)v->val.i32)); } } else if(v->flags & VALUE_INT64) { if(buffer == NULL) { bufsize = 24; buffer = xalloc(bufsize); } snprintf(buffer,bufsize, v->flags & VALUE_UNSIGNED ? "%llu" : "%lld", v->flags & VALUE_UNSIGNED ? v->val.ui64 : v->val.i64); ret = buffer; } else if(v->flags & VALUE_DOUBLE) { if(buffer == NULL) { bufsize = 64; buffer = xalloc(bufsize); } snprintf(buffer,bufsize, flags & VALUE_NICE_FLOATS ? "%.2f" : "%.10e", v->val.d); ret = buffer; } if(ret == NULL && !(flags & VALUE_ALLOW_NULL)) { if(flags & VALUE_USE_DEFAULT) ret = def; if(ret == NULL) { if(buffer != NULL) { xstrncpy(buffer,"",bufsize); ret = buffer; } else ret = xstrdup(""); } } if(ret != def && (flags && VALUE_FREE_DEFAULT)) { if(def != NULL) xfree(def); } return ret; } int str_to_bool(char *str) { if(str == NULL) return -1; switch(tolower(str[0])) { case 'f': return 0; case 'n': return 0; case 'o': if(strcasecmp(str,"on") == 0) return 1; else if(strncasecmp(str,"of",2) == 0) return 0; break; case 't': return 1; case 'y': return 1; case '0': return 0; case '1': return 1; default: break; } return -1; } int value_as_bool(value_t *v, int flags, int def) { if(!(v->flags & VALUE_BOOL)) { char buffer[32]; int ret; value_as_string(v,flags & ~VALUE_ALLOW_NULL, buffer,sizeof(buffer),NULL); if((ret = str_to_bool(buffer)) != -1) return ret; } else return v->val.i32; if(flags & VALUE_USE_DEFAULT) return def; else return 0; } char *value_as_bool_str(value_t *v, int flags, char *buffer, size_t bufsize) { int val = value_as_bool(v,flags,0); if(buffer == NULL) { bufsize = 8; buffer = xalloc(bufsize); } if(flags & VALUE_BOOL_ONOFF) { if(val) xstrncpy(buffer,"on",bufsize); else xstrncpy(buffer,"off",bufsize); } else if(flags & VALUE_BOOL_YESNO) { if(val) xstrncpy(buffer,"yes",bufsize); else xstrncpy(buffer,"no",bufsize); } else { if(val) xstrncpy(buffer,"true",bufsize); else xstrncpy(buffer,"false",bufsize); } return buffer; } int value_as_enum(value_t *v, int flags, int def) { int ret = value_as_int32(v,0,0,0,0); if(ret == -1 && (flags & VALUE_USE_DEFAULT)) ret = def; return ret; } int value_set_enumeration(value_t *v, int (*en)(const char *), const char *(*de)(int)) { if(v->flags & VALUE_STRING) { if(en == NULL) return -1; v->num.en = en; } else { if(de == NULL) return -1; v->num.de = de; } v->flags |= VALUE_ENUM; return 0; } /** enum specific functions **/ const char *interfacetype_to_str(int type) { switch(type) { case INTERFACE_SEND: return "SEND"; case INTERFACE_RECV: return "RECV"; case INTERFACE_CHAT: return "CHAT"; default: return NULL; } } int str_to_interfacetype(const char *str) { if(str == NULL) return -1; switch(tolower(str[0]) == 0) { case 's': return INTERFACE_SEND; case 'r': return INTERFACE_RECV; case 'c': return INTERFACE_CHAT; default: return -1; } } const char *interfacemode_to_str(int mode) { switch(mode) { case IMODE_DCCSERVER: return "dccserver"; case IMODE_NORMAL: return "normal"; case IMODE_REVERSE: return "reverse"; default: return NULL; } } int str_to_interfacemode(const char *str) { if(str == NULL) return -1; switch(tolower(str[0])) { case 'd': return IMODE_DCCSERVER; case 'n': return IMODE_NORMAL; case 'r': return IMODE_REVERSE; default: return -1; } } const char *listtype_to_str(int type) { switch(type) { case LIST_NORMAL: return "NORMAL"; case LIST_NOPACKS: return "NOPACKS"; case LIST_TAGONLY: return "TAGONLY"; case LIST_CHAT: return "CHAT"; default: return NULL; } } int str_to_listtype(const char *str) { if(str == NULL) return -1; switch(tolower(str[0])) { case 'c': return LIST_CHAT; case 'n': if(strncasecmp(str,"nor",3) == 0) return LIST_NORMAL; else if(strncasecmp(str,"nop",3) == 0) return LIST_NOPACKS; else return -1; case 't': return LIST_TAGONLY; default: return -1; } } const char *pformat_to_str(int pformat) { switch(pformat) { case PFORMAT_MINIMAL: return "Minimal"; case PFORMAT_SUMMARY: return "Summary"; case PFORMAT_FULL: return "Full"; case PFORMAT_TAGONLY: return "Tagonly"; default: return NULL; } } int str_to_pformat(const char *str) { if(str == NULL) return -1; switch(tolower(str[0])) { case 'f': return PFORMAT_FULL; case 'm': return PFORMAT_MINIMAL; case 's': return PFORMAT_SUMMARY; case 't': return PFORMAT_TAGONLY; default: return -1; } } const char *networkstate_to_str(int ns) { switch(ns) { case NETWORK_OFFLINE: return "OFFLINE"; case NETWORK_RUNNING: return "RUNNING"; case NETWORK_LOGIN: return "LOGGING IN"; case NETWORK_CONNECTING:return "CONNECTING"; case NETWORK_CONNECTED: return "CONNECTED"; default: return NULL; } } const char *chattype_to_str(int ct) { switch(ct) { case CHAT_ADMIN: return "ADMIN"; case CHAT_LIST: return "LIST"; default: return NULL; } } const char *colourtype_to_str(int ct) { switch(ct) { case COLOUR_NONE: return "NONE"; case COLOUR_IRC: return "IRC"; case COLOUR_INT: return "INTERNAL"; default: return NULL; } } int str_to_colourtype(const char *str) { switch(tolower(str[0])) { case 'n': return COLOUR_NONE; case 'i': if(tolower(str[1]) == 'r') return COLOUR_IRC; else if(tolower(str[1]) == 'n') return COLOUR_INT; break; default: break; } return -1; } const char *state_to_str(int s) { switch(s) { case STATE_UNKNOWN: return "UNKNOWN"; case STATE_QUEUED: return "QUEUED"; case STATE_RESOLVING: return "RESOLVING"; case STATE_CONNECTING: return "CONNECTING"; case STATE_NEGOTIATING: return "NEGOTIATING"; case STATE_LISTENING: return "LISTENING"; case STATE_ACTIVE: return "ACTIVE"; case STATE_COMPLETING: return "COMPLETING"; case STATE_COMPLETE: return "COMPLETE"; case STATE_SLOW: return "SLOW"; case STATE_TIMEOUT: return "TIMEOUT"; case STATE_DELETED: return "DELETED"; case STATE_PURGING: return "PURGING"; case STATE_PURGEREQUEUE:return "REQUEUE"; case STATE_ERROR: return "ERROR"; case STATE_RETRY: return "RETRY"; case STATE_RESUME: return "RESUME"; case STATE_RESUMED: return "RESUMED"; default: return NULL; } } int str_to_sorttype(const char *str) { switch(tolower(str[0])) { case 'a': return SORT_AZ; case 'z': return SORT_ZA; case 'i': switch(tolower(str[1])) { case 'a': return SORT_I_AZ; case 'z': return SORT_I_ZA; default: break; } break; } return SORT_NONE; } const char *sorttype_to_str(int st) { switch(st) { case SORT_NONE: return "none"; case SORT_AZ: return "az"; case SORT_ZA: return "za"; case SORT_I_AZ: return "iaz"; case SORT_I_ZA: return "iza"; default: return NULL; } } int str_to_hashtype(const char *str) { if(strncasecmp(str,"crc+",4) == 0 || strcasecmp(str,"c+m") == 0) { return HASH_CRC_AND_MD5; } else if(tolower(str[0]) == 'c') { return HASH_CRC; } else if(tolower(str[0]) == 'm') { return HASH_MD5; } else { return HASH_NONE; } } const char *hashtype_to_str(int ht) { switch(ht) { case HASH_NONE: return "none"; case HASH_CRC: return "crc"; case HASH_MD5: return "md5"; case HASH_CRC_AND_MD5: return "crc+md5"; default: return NULL; } } int str_to_responsetype(const char *str) { switch(tolower(str[0])) { case 'n': return RESPONSE_NOTICE; case 'p': return RESPONSE_PRIVMSG; default: return -1; } } const char *responsetype_to_str(int rt) { switch(rt) { case RESPONSE_NOTICE: return "notice"; case RESPONSE_PRIVMSG: return "privmsg"; default: return NULL; } }