📄 keydata.cpp
字号:
// Copyright (C) 1999-2005 Open Source Telecom Corporation.// // 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.// // As a special exception, you may use this file as part of a free software// library without restriction. Specifically, if other files instantiate// templates or use macros or inline functions from this file, or you compile// this file and link it with other files to produce an executable, this// file does not by itself cause the resulting executable to be covered by// the GNU General Public License. This exception does not however // invalidate any other reasons why the executable file might be covered by// the GNU General Public License. //// This exception applies only to the code released under the name GNU// Common C++. If you copy code from other releases into a copy of GNU// Common C++, as the General Public License permits, the exception does// not apply to the code that you add in this way. To avoid misleading// anyone as to the status of such modified files, you must delete// this exception notice from them.//// If you write modifications of your own for GNU Common C++, it is your choice// whether to permit this exception to apply to your modifications.// If you do not wish that, delete this exception notice.//#include <cc++/config.h>#include <cc++/export.h>#include <cc++/file.h>#include <cc++/misc.h>#include <sys/stat.h>#include "private.h"#include <cstdlib>#include <cstdio>#ifndef CAPE_REGISTRY_APPLICATIONS#define CAPE_REGISTRY_APPLICATIONS "SOFTWARE\\CAPE Applications"#define CAPE_REGISTRY_USERSETTINGS "Software\\CAPE Applications"#endif#ifdef WIN32class Registry{public: const char *configdir; Registry();};Registry::Registry(){ configdir = getenv("SystemRoot"); if(!configdir || !*configdir) configdir = getenv("windir"); if(!configdir || !*configdir) configdir = "C:\\WINDOWS";}static Registry registry;#endif#ifdef CCXX_NAMESPACESnamespace ost {using namespace std;#endifint Keydata::count = 0;int Keydata::sequence = 1;ifstream *Keydata::cfgFile = NULL;char Keydata::lastpath[KEYDATA_PATH_SIZE + 1];void endKeydata();Keydata::Keydata() : MemPager(KEYDATA_PAGER_SIZE){ link = 0; memset(&keys, 0, sizeof(keys)); }Keydata::Keydata(const char *path) :MemPager(KEYDATA_PAGER_SIZE){ link = 0; memset(&keys, 0, sizeof(keys)); load(path);}Keydata::Keydata(Define *pairs, const char *path) :MemPager(KEYDATA_PAGER_SIZE){ link = 0; memset(&keys, 0, sizeof(keys)); load(pairs); if(path) load(path);}Keydata::~Keydata(){ unlink(); if(count < 1) endKeydata();}Keydata::Keysym *Keydata::getSymbol(const char *sym, bool create){ unsigned path = getIndex(sym); size_t len = strlen(sym) + 1; Keysym *key = keys[path]; while(key) { if(!stricmp(sym, key->sym)) return key; key = key->next; } if(!create) return NULL; // note: keysym has 1 byte for null character already key = (Keysym *)alloc(sizeof(Keysym) + len - 1); setString(key->sym, len, sym); key->count = 0; key->next = keys[path]; key->data = NULL; key->list = NULL; keys[path] = key; return key;}unsigned Keydata::getIndex(const char *str){ unsigned key = 0; while(*str) key = (key << 1) ^ (*(str++) & 0x1f); return key % KEYDATA_INDEX_SIZE;}int Keydata::getCount(const char *sym){ Keysym *key = getSymbol(sym, false); if(!key) return 0; return key->count;}const char *Keydata::getFirst(const char *sym){ Keysym *key = getSymbol(sym, false); Keyval *val; if(!key) return NULL; val = key->data; if(!val) return NULL; while(val->next) val = val->next; return val->val;}const char *Keydata::getLast(const char *sym){ Keysym *key = getSymbol(sym, false); if(!key) return NULL; if(!key->data) return NULL; return key->data->val;}unsigned Keydata::getCount(void){ unsigned icount = 0; Keysym *key; int idx; for(idx = 0; idx < KEYDATA_INDEX_SIZE; ++idx) { key = keys[idx]; while(key) { ++icount; key = key->next; } } return icount;}unsigned Keydata::getIndex(char **data, unsigned max){ int idx; Keysym *key; unsigned icount = 0; for(idx = 0; idx < KEYDATA_INDEX_SIZE; ++idx) { if(icount >= max) break; key = keys[idx]; while(key && icount < max) { *(data++) = key->sym; ++icount; key = key->next; } } *data = NULL; return icount;}void Keydata::setValue(const char *sym, const char *data){ size_t len = strlen(data) + 1; Keysym *key = getSymbol(sym, true); Keyval *val; if(!data) data = ""; // note keyval has 1 byte for null already val = (Keyval *)alloc(sizeof(Keyval) + len - 1); ++key->count; key->list = NULL; val->next = key->data; key->data = val; setString(val->val, len, data);}const char *const *Keydata::getList(const char *sym){ int icount; Keysym *key = getSymbol(sym, false); Keyval *data; if(!key) return NULL; icount = key->count; if(!icount) return NULL; ++icount; if(!key->list) { key->list =(const char **)first(sizeof(const char**) * icount); key->list[--icount] = NULL; data = key->data; while(icount && data) { key->list[--icount] = data->val; data = data->next; } while(icount) key->list[--icount] = ""; } return key->list;}void Keydata::clrValue(const char *sym){ Keysym *key = getSymbol(sym, false); if(!key) return; key->count = 0; key->list = NULL; key->data = NULL;}void Keydata::load(Define *defs){ Keysym *key; while(defs->keyword) { key = getSymbol(defs->keyword, true); if(!key->data) setValue(defs->keyword, defs->value); ++defs; }}void Keydata::load(const char *keypath){ loadPrefix(NULL, keypath);}void Keydata::loadPrefix(const char *pre, const char *keypath){ // FIXME: use string of dinamic allocation char path[KEYDATA_PATH_SIZE]; char seek[33]; const char *prefix = NULL; const char *ext;#ifdef WIN32 const char *ccp;#endif char *cp; bool etcpath = false, etctest = false;#ifndef WIN32 struct stat ino;#endif path[0] = 0;#ifdef WIN32 HKEY key; LONG value; DWORD keynamelen, keytextlen; TCHAR keyname[256]; TCHAR keytext[256]; DWORD keyindex = 0; char *regprefix = getenv("CONFIG_REGISTRY"); if(!regprefix) regprefix=""; ccp = keypath; if(*ccp == '~') { ++ccp; if(*ccp == '/') ++ccp; snprintf(path, sizeof(path), CAPE_REGISTRY_USERSETTINGS "/%s%s/", regprefix, ccp); } else { if(*ccp == '/') ++ccp; snprintf(path, sizeof(path), CAPE_REGISTRY_APPLICATIONS "/%s%s/", regprefix, ccp); } cp = path; while(NULL != (cp = strchr(cp, '/'))) *cp = '\\'; if(*keypath == '~') value = RegOpenKey(HKEY_CURRENT_USER, path, &key); else value = RegOpenKey(HKEY_LOCAL_MACHINE, path, &key); // if registry key path is found, then we use registry values // and ignore .ini files... if(value == ERROR_SUCCESS) { for(;;) { keynamelen = 256; value = RegEnumKeyEx(key, keyindex, keyname, &keynamelen, NULL, NULL, NULL, NULL); if(value != ERROR_SUCCESS) break; keytextlen = 256; keytext[0] = '\0'; value = RegEnumValue(key, keyindex++, keytext, &keytextlen, NULL, NULL, NULL, NULL); if(value != ERROR_SUCCESS) continue; if(pre) { snprintf(path, sizeof(path), "%s.%s", pre, keyname); setValue(path, keytext); } else setValue(keyname, keytext); } RegCloseKey(key); return; } // windows will not support subdir .ini tree; now if not in // registry, then assume unavailable ccp = strchr(keypath + 3, '/'); if(ccp) ccp = strchr(ccp, '/'); if(ccp) return; if(*keypath == '~') { prefix = getenv("USERPROFILE"); if(!prefix) return; setString(path, sizeof(path) - 8, prefix); addString(path, sizeof(path), "\\"); ++keypath; cp = path; while(NULL != (cp = strchr(cp, '\\'))) *cp = '/'; }#else if(*keypath == '~') { prefix = getenv("HOME"); if(!prefix) return; setString(path, sizeof(path) - 8, prefix); addString(path, sizeof(path), "/."); ++keypath; }#endif if(!prefix) {#ifdef WIN32 if(!prefix || !*prefix) prefix = registry.configdir;#else retry:#ifdef ETC_CONFDIR if(!prefix || !*prefix) { if(etcpath) prefix = ETC_PREFIX; else prefix = ETC_CONFDIR; etctest = true; if(!stricmp(ETC_PREFIX, ETC_CONFDIR)) etcpath = true; } #else if(!prefix || !*prefix) prefix = ETC_PREFIX;#endif#endif setString(path, sizeof(path) - 8, prefix);#ifdef WIN32 cp = path; while(NULL != (cp = strchr(cp, '\\'))) *cp = '/'; cp = cp + strlen(path) - 1; if(*cp != '/') { *(++cp) = '/'; *(++cp) = 0; }#endif prefix = NULL; } if(*keypath == '/' || *keypath == '\\') ++keypath; addString(path, sizeof(path), keypath); cp = strrchr(path, '/'); setString(seek, sizeof(seek), cp + 1); *cp = 0; ext = strrchr(path, '/'); if(ext) ext = strrchr(ext + 2, '.'); else ext = strrchr(path + 1, '.');#ifdef WIN32 if(!ext) addString(path, sizeof(path), ".ini");#else if(!prefix && !ext) addString(path, sizeof(path), ".conf"); else if(prefix && !ext) addString(path, sizeof(path), "rc"); ino.st_uid = (unsigned)-1; if(stat(path, &ino) < 0 && etctest && !etcpath) { etcpath = true; goto retry; } // if root, make sure root owned config... if(!geteuid() && ino.st_uid) return; // if root, make sure from a etc path only... if(!geteuid() && !etctest) return; #endif loadFile(path, seek, pre);}void Keydata::loadFile(const char *path, const char *keys, const char *pre){ char seek[33]; char find[33]; char line[256]; char buffer[256]; char *cp, *ep; int fpos; if(keys) setString(seek, sizeof(seek), keys); else seek[0] = 0; if(strcmp(path, lastpath)) { endKeydata(); if(canAccess(path)) cfgFile->open(path, ios::in); else return; if(!cfgFile->is_open()) return; setString(lastpath, sizeof(lastpath), path); } if(link != sequence) { link = sequence; ++count; } find[0] = 0; cfgFile->seekg(0); while(keys && stricmp(seek, find)) { cfgFile->getline(line, sizeof(line) - 1); if(cfgFile->eof()) { lastpath[0] = 0; cfgFile->close(); cfgFile->clear(); return; } cp = line; while(*cp == ' ' || *cp == '\n' || *cp == '\t') ++cp; if(*cp != '[') continue; ep = strchr(cp, ']'); if(ep) *ep = 0; else continue; setString(find, 32, ++cp); } for(;;) { if(cfgFile->eof()) { lastpath[0] = 0; cfgFile->close(); cfgFile->clear(); return; } cfgFile->getline(line, sizeof(line) - 1); cp = line; while(*cp == ' ' || *cp == '\t' || *cp == '\n') ++cp; if(!*cp || *cp == '#' || *cp == ';' || *cp == '!') continue; if(*cp == '[') return; fpos = 0; while(*cp && *cp != '=') { if(*cp == ' ' || *cp == '\t') { ++cp; continue; } find[fpos] = *(cp++); if(fpos < 32) ++fpos; } find[fpos] = 0; if(*cp != '=') continue; ++cp; while(*cp == ' ' || *cp == '\t' || *cp == '\n') ++cp; ep = cp + strlen(cp); while((--ep) > cp) { if(*ep == ' ' || *ep == '\t' || *ep == '\n') *ep = 0; else break; } if(*cp == *ep && (*cp == '\'' || *cp == '\"')) { ++cp; *ep = 0; } if(pre) {#ifdef HAVE_SNPRINTF snprintf(buffer, 256, "%s.%s", pre, find);#else setString(buffer, 256, pre); addString(buffer, 256, "."); addString(buffer, 256, find);#endif setValue(buffer, cp); } else setValue(find, cp); }}void Keydata::unlink(void){ if(link != sequence) { link = 0; return; } link = 0; --count;} void Keydata::end(void){ Keydata::count = 0; ++Keydata::sequence; if(!Keydata::sequence) ++Keydata::sequence; Keydata::lastpath[0] = 0; if(!Keydata::cfgFile) Keydata::cfgFile = new std::ifstream(); else if(Keydata::cfgFile->is_open()) { Keydata::cfgFile->close(); Keydata::cfgFile->clear(); }}#ifdef CCXX_NAMESPACES}#endif/** EMACS ** * Local variables: * mode: c++ * c-basic-offset: 8 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -