void kdbGetByName(KDB *kdb, KeySet *conf, Key *parentKey, char *where) { keySetName(parentKey, "system"); keyAddName(parentKey, where); kdbGet(kdb, conf, parentKey); keySetName(parentKey, "user"); keyAddName(parentKey, where); kdbGet(kdb, conf, parentKey); }
/** * @internal * Add plugin at placement to list plugin configuration and apply it. * * @param list List plugin * @param plugin Plugin to add * @param placement Placement name * @retval 0 on error * @retval 0 on success */ static int listAddPlugin (Plugin * list, Plugin * plugin, char * placement) { ELEKTRA_NOT_NULL (list); ELEKTRA_NOT_NULL (plugin); ELEKTRA_NOT_NULL (placement); KeySet * newConfig = ksDup (list->config); // Find name for next item in plugins array Key * configBase = keyNew ("user/plugins", KEY_END); KeySet * array = elektraArrayGet (configBase, newConfig); Key * pluginItem = elektraArrayGetNextKey (array); ELEKTRA_NOT_NULL (pluginItem); keySetString (pluginItem, plugin->name); keyDel (configBase); // Create key with plugin handle Key * pluginHandle = keyDup (pluginItem); keyAddName (pluginHandle, "handle"); keySetBinary (pluginHandle, &plugin, sizeof (plugin)); // Create key with plugin placement char * placementType = placementToListPositionType (placement); if (placementType == NULL) { keyDel (configBase); keyDel (pluginItem); keyDel (pluginHandle); return 0; } Key * pluginPlacements = keyDup (pluginItem); keyAddName (pluginPlacements, "placements/"); keyAddName (pluginPlacements, placementType); keySetString (pluginPlacements, placement); // Append keys to list plugin configuration ksAppendKey (newConfig, pluginItem); ksAppendKey (newConfig, pluginHandle); ksAppendKey (newConfig, pluginPlacements); ksDel (array); ksDel (list->config); // Apply new configuration list->config = newConfig; list->kdbOpen (list, NULL); return 1; }
/** * @brief Takes the first key and cuts off this common part * for all other keys, instead name will be prepended * * @return a new allocated keyset with keys in user namespace. * * The first key is removed in the resulting keyset. */ KeySet* elektraRenameKeys(KeySet *config, const char* name) { Key *root; Key *cur; ssize_t rootSize = 0; ksRewind(config); root = ksNext (config); rootSize = keyGetNameSize(root); keyDel (ksLookup (config, root, KDB_O_POP)); KeySet *newConfig = ksNew(ksGetSize(config), KS_END); if (rootSize == -1) return newConfig; while ((cur = ksPop(config)) != 0) { Key *dupKey = keyDup(cur); keySetName(dupKey, name); keyAddName(dupKey, keyName(cur)+rootSize-1); ksAppendKey(newConfig, dupKey); keyDel(cur); } return newConfig; }
static int elektraResolveEnvUser(resolverHandle *p) { const char* owner = getenv("USER"); if (!owner || !strcmp(owner, "")) { return 0; } Key *canonify = keyNew("user", KEY_END); keyAddName(canonify, owner); size_t dirnameSize = sizeof(KDB_DB_HOME "/") + keyGetNameSize(canonify) + sizeof("/" KDB_DB_USER); p->dirname= elektraMalloc (dirnameSize); strcpy (p->dirname, KDB_DB_HOME "/"); strcat (p->dirname, keyName(canonify) +5); // cut user/ if (p->path[0] != '/') { strcat (p->dirname, "/" KDB_DB_USER); } keyDel(canonify); return 1; }
/** @retval 0 if ksCurrent does not hold an array entry @retval 1 if the array entry will be used because its the first @retval 2 if a new array entry was created @retval -1 error in snprintf */ static int elektraYajlIncrementArrayEntry (KeySet * ks) { Key * current = ksCurrent (ks); const char * baseName = keyBaseName (current); if (baseName && *baseName == '#') { current = keyNew (keyName (current), KEY_END); if (!strcmp (baseName, "###empty_array")) { // get rid of previous key keyDel (ksLookup (ks, current, KDB_O_POP)); // we have a new array entry keySetBaseName (current, 0); keyAddName (current, "#0"); ksAppendKey (ks, current); return 1; } else { // we are in an array elektraArrayIncName (current); ksAppendKey (ks, current); return 2; } } else { // previous entry indicates this is not an array return 0; } }
static KeySet * prepareGlobalKS (KeySet * ks, Key * parentKey) { ksRewind (ks); Key * cutKey = keyNew ("/", KEY_CASCADING_NAME, KEY_END); keyAddName (cutKey, strchr (keyName (parentKey), '/')); KeySet * cutKS = ksCut (ks, cutKey); Key * specCutKey = keyNew ("spec", KEY_END); KeySet * specCut = ksCut (cutKS, specCutKey); ksRewind (specCut); Key * cur; while ((cur = ksNext (specCut)) != NULL) { if (keyGetNamespace (cur) == KEY_NS_CASCADING) { ksAppendKey (cutKS, cur); keyDel (ksLookup (specCut, cur, KDB_O_POP)); } } ksAppend (ks, specCut); ksDel (specCut); keyDel (specCutKey); keyDel (cutKey); ksRewind (cutKS); return cutKS; }
KeySet * elektraMetaArrayToKS (Key * key, const char * metaName) { const Key * meta = keyGetMeta (key, metaName); if (!meta) return NULL; KeySet * result = ksNew (0, KS_END); if (keyString (meta)[0] != '#') { ksAppendKey (result, (Key *)meta); ksRewind (result); return result; } ksAppendKey (result, keyDup (meta)); Key * currentKey = keyDup (meta); keyAddName (currentKey, "#"); elektraArrayIncName (currentKey); Key * curMeta = NULL; while ((curMeta = (Key *)keyGetMeta (key, keyName (currentKey))) != NULL) { ksAppendKey (result, keyDup (curMeta)); elektraArrayIncName (currentKey); } keyDel (currentKey); ksRewind (result); return result; }
/** * @internal * Create a new key with a different root or common name. * * Does not modify `key`. The new key needs to be freed after usage. * * Preconditions: The key name starts with `source`. * * Example: * ``` * Key * source = keyNew("user/plugins/foo/placements/get", KEY_END); * Key * dest = renameKey ("user/plugins/foo", "user/plugins/bar", source); * succeed_if_same_string (keyName(dest), "user/plugins/bar/placements/get"); * ``` * * * @param source Part of the key name to replace * @param dest Replaces `source` * @param key key * @return key with new name */ static Key * renameKey (const char * source, const char * dest, Key * key) { const char * name = keyName (key); char * baseKeyNames = strndup (name + strlen (source), strlen (name)); Key * moved = keyDup (key); keySetName (moved, dest); keyAddName (moved, baseKeyNames); elektraFree (baseKeyNames); return moved; }
void test_checkfile () { printf ("Check file\n"); KeySet * modules = ksNew (0, KS_END); elektraModulesInit (modules, 0); Plugin * plugin = elektraPluginOpen ("resolver", modules, set_pluginconf (), 0); exit_if_fail (plugin, "did not find a resolver"); Key * root = keyNew ("system/elektra/modules", KEY_END); keyAddBaseName (root, plugin->name); KeySet * contract = ksNew (5, KS_END); plugin->kdbGet (plugin, contract, root); keyAddName (root, "/exports/checkfile"); Key * found = ksLookup (contract, root, 0); exit_if_fail (found, "did not find checkfile symbol"); typedef int (*func_t) (const char *); union { func_t f; void * v; } conversation; succeed_if (keyGetBinary (found, &conversation.v, sizeof (conversation)) == sizeof (conversation), "could not get binary"); func_t checkFile = conversation.f; succeed_if (checkFile ("valid") == 1, "valid file not recognised"); succeed_if (checkFile ("/valid") == 0, "valid absolute file not recognised"); succeed_if (checkFile ("/absolute/valid") == 0, "valid absolute file not recognised"); succeed_if (checkFile ("../valid") == -1, "invalid file not recognised"); succeed_if (checkFile ("valid/..") == -1, "invalid file not recognised"); succeed_if (checkFile ("/../valid") == -1, "invalid absolute file not recognised"); succeed_if (checkFile ("/valid/..") == -1, "invalid absolute file not recognised"); succeed_if (checkFile ("very..strict") == -1, "resolver is currently very strict"); succeed_if (checkFile ("very/..strict") == -1, "resolver is currently very strict"); succeed_if (checkFile ("very../strict") == -1, "resolver is currently very strict"); succeed_if (checkFile ("very/../strict") == -1, "resolver is currently very strict"); succeed_if (checkFile ("/") == -1, "invalid absolute file not recognised"); succeed_if (checkFile (".") == -1, "invalid file not recognised"); succeed_if (checkFile ("..") == -1, "invalid file not recognised"); ksDel (contract); keyDel (root); elektraPluginClose (plugin, 0); elektraModulesClose (modules, 0); ksDel (modules); }
ssize_t elektraKeySetName(Key *key, const char *newName, option_t options) { if (!key) return -1; if (test_bit(key->flags, KEY_FLAG_RO_NAME)) return -1; elektraRemoveKeyName(key); if (!(options & KEY_META_NAME)) keySetOwner (key, NULL); switch (keyGetNameNamespace(newName)) { case KEY_NS_NONE: ELEKTRA_ASSERT(0); case KEY_NS_EMPTY: elektraFinalizeEmptyName(key); return 0; // as documented case KEY_NS_CASCADING: key->keyUSize=1;key->keySize=sizeof("/"); break; case KEY_NS_SPEC: key->keyUSize=key->keySize=sizeof("spec"); break; case KEY_NS_PROC: key->keyUSize=key->keySize=sizeof("proc"); break; case KEY_NS_DIR: key->keyUSize=key->keySize=sizeof("dir"); break; case KEY_NS_USER: elektraHandleUserName(key, newName); break; case KEY_NS_SYSTEM: key->keyUSize=key->keySize=sizeof("system"); break; case KEY_NS_META: if (!(options & KEY_META_NAME)) return -1; keyNameGetOneLevel(newName,&key->keySize); key->keyUSize = ++ key->keySize; // for null break; } // Note that we abused keyUSize for cascading and user:owner const size_t length = elektraStrLen(newName); key->key=elektraMalloc(key->keySize*2); memcpy(key->key, newName, key->keySize); if (length == key->keyUSize || length == key->keySize) { // use || because full length is keyUSize in user, but keySize for / // newName consisted of root only elektraFinalizeName(key); return key->keyUSize; } if (elektraOnlySlashes(newName+key->keyUSize-1)) { elektraFinalizeName(key); return key->keySize; } key->key[key->keySize-1] = '\0'; const ssize_t ret = keyAddName(key, newName+key->keyUSize); if (ret == -1) elektraRemoveKeyName(key); else return key->keySize; return ret; }
static void setSectionNumber(Key *parentKey, Key *key, KeySet *ks) { if (!strcmp(keyBaseName(key), INTERNAL_ROOT_SECTION)) { Key *tmpKey = keyDup(key); keySetMeta(tmpKey, "ini/section", "0"); keySetMeta(key, "ini/section", "0"); keySetString(tmpKey, 0); ksAppendKey(ks, tmpKey); keyDel(tmpKey); return; } Key *lookupKey = keyDup(key); Key *lastKey = keyDup(lookupKey); while (1) { if (!strcmp(keyName(lookupKey), keyName(parentKey))) { if (keyGetMeta(parentKey, "ini/lastSection")) { long previousSection = atol(keyString(keyGetMeta(parentKey, "ini/lastSection"))); ++previousSection; char buffer[21]; //20 digits (long) + \0 snprintf(buffer, sizeof (buffer), "%ld", previousSection); keySetMeta(parentKey, "ini/lastSection", buffer); keySetMeta(key, "ini/section", buffer); } else { keySetMeta(parentKey, "ini/lastSection", "1"); keySetMeta(parentKey, "ini/section", "0"); keySetMeta(key, "ini/section", "1"); } keySetMeta(lastKey, "ini/section", keyString(keyGetMeta(key, "ini/section"))); ksAppendKey(ks, lastKey); break; } if (keyGetMeta(ksLookup(ks, lookupKey, KDB_O_NONE), "ini/section")) { keySetMeta(key, "ini/section", keyString(keyGetMeta(ksLookup(ks, lookupKey, KDB_O_NONE), "ini/section"))); break; } keySetName(lastKey, keyName(lookupKey)); keyAddName(lookupKey, ".."); } keyDel(lookupKey); keyDel(lastKey); }
static void elektraResolveUsingHome (ElektraResolved * handle, const char * home, short addPostfix) { Key * canonify = keyNew ("user", KEY_END); keyAddName (canonify, home); size_t dirnameSize = keyGetNameSize (canonify) + sizeof ("/" KDB_DB_USER); char * dir = elektraMalloc (dirnameSize); strcpy (dir, keyName (canonify) + 4); // cut user, leave slash if (addPostfix && handle->relPath[0] != '/') { strcat (dir, "/" KDB_DB_USER); } handle->dirname = dir; keyDel (canonify); }
static void elektraResolveUsingHome (resolverHandle * p, const char * home, bool addPostfix) { size_t dirnameSize = 0; Key * canonify = keyNew ("user", KEY_END); keyAddName (canonify, home); dirnameSize = keyGetNameSize (canonify) + sizeof ("/" KDB_DB_USER); p->dirname = elektraMalloc (dirnameSize); strcpy (p->dirname, keyName (canonify) + 4); // cut user, but leave slash if (addPostfix && p->path[0] != '/') { strcat (p->dirname, "/" KDB_DB_USER); } keyDel (canonify); }
static int elektraYajlParseStartArray (void * ctx) { KeySet * ks = (KeySet *)ctx; elektraYajlIncrementArrayEntry (ks); Key * currentKey = ksCurrent (ks); Key * newKey = keyNew (keyName (currentKey), KEY_END); // add a pseudo element for empty array keyAddName (newKey, "###empty_array"); ksAppendKey (ks, newKey); #ifdef ELEKTRA_YAJL_VERBOSE printf ("elektraYajlParseStartArray with new key %s\n", keyName (newKey)); #endif return 1; }
// keyRel2 helper, turns key into a cascading key ( removes namespace) Key * keyAsCascading (const Key * key) { if (keyName (key)[0] == '/') { return keyDup (key); } else { elektraNamespace ns = keyGetNamespace (key); if (ns == KEY_NS_META || ns == KEY_NS_EMPTY || ns == KEY_NS_NONE) { // For metakeys or keys without namespace just prefix the keyname with a "/" Key * cKey = keyNew ("/", KEY_CASCADING_NAME, KEY_END); keyAddName (cKey, keyName (key)); return cKey; } else { // Skip namespace const char * name = keyName (key); const char * ptr = strchr (name, '/'); if (!ptr) { return keyNew ("/", KEY_CASCADING_NAME, KEY_END); } else { ssize_t length = keyGetNameSize (key); if ((ptr - name) == (length - 1)) { return keyNew ("/", KEY_CASCADING_NAME, KEY_END); } else { return keyNew (ptr, KEY_CASCADING_NAME, KEY_END); } } } } }
static int elektraResolveEnvUser (ElektraResolved * handle) { const char * user = getenv ("USER"); if (!user || !strcmp (user, "")) { return 0; } Key * canonify = keyNew ("user", KEY_END); keyAddName (canonify, user); size_t homeSize = sizeof (KDB_DB_HOME "/") + keyGetNameSize (canonify) + sizeof ("/" KDB_DB_USER); char * homeBuf = elektraMalloc (homeSize); strcpy (homeBuf, KDB_DB_HOME "/"); strcat (homeBuf, keyName (canonify) + 5); // cut user/ if (handle->relPath[0] != '/') { strcat (homeBuf, "/" KDB_DB_USER); } keyDel (canonify); handle->dirname = homeBuf; return 1; }
static const char * isAssign (Key * key, char * expr, Key * parentKey, KeySet * ks) { char * firstPtr = expr + 1; char * lastPtr = expr + elektraStrLen (expr) - 3; while (isspace (*firstPtr)) ++firstPtr; while (isspace (*lastPtr)) --lastPtr; if (*firstPtr != '\'' || *lastPtr != '\'') { if (lastPtr <= firstPtr) { ELEKTRA_SET_ERRORF (134, parentKey, "Invalid syntax: \"%s\". Check kdb info conditionals for additional information", expr); return NULL; } *(lastPtr + 1) = '\0'; Key * lookupKey; if (*firstPtr == '@') { lookupKey = keyDup (parentKey); ++firstPtr; keyAddName (lookupKey, firstPtr); } else if (!strncmp (firstPtr, "..", 2) || !strncmp (firstPtr, ".", 1)) { lookupKey = keyDup (key); keyAddName (lookupKey, firstPtr); } else { lookupKey = keyNew (firstPtr, KEY_END); } Key * assign = ksLookup (ks, lookupKey, KDB_O_NONE); if (!assign) { ELEKTRA_SET_ERRORF (133, parentKey, "Key %s not found", keyName (lookupKey)); keyDel (lookupKey); return NULL; } else { keyDel (lookupKey); return keyString (assign); } } else { if (firstPtr == lastPtr) // only one quote in the assign string, invalid syntax { ELEKTRA_SET_ERRORF (134, parentKey, "Invalid syntax: \"%s\". Check kdb info conditionals for additional information", expr); return NULL; } char * nextMark = strchr (firstPtr + 1, '\''); if (nextMark != lastPtr) // more than two quotes, invalid syntax too { ELEKTRA_SET_ERRORF (134, parentKey, "Invalid syntax: \"%s\". Check kdb info conditionals for additional information", expr); return NULL; } *lastPtr = '\0'; *firstPtr = '\0'; ++firstPtr; return firstPtr; } }
/* * Processes the current <key> node from reader, converting from XML * to a Key object, and ksAppendKey() it to ks. * * See keyToStream() for an example of a <key> node. * * This function is completelly dependent on libxml. * * @param ks where to put the resulting reded key * @param context a prent key name, so a full name can be calculated * if the XML node for the current key only provides a basename * @param reader where to read from */ static int consumeKeyNode(KeySet *ks, const char *context, xmlTextReaderPtr reader) { xmlChar *nodeName=0; xmlChar *keyNodeName=0; xmlChar *buffer=0; xmlChar *privateContext=0; Key *newKey=0; int appended=0; /* printf("%s", KDB_SCHEMA_PATH); */ keyNodeName=xmlTextReaderName(reader); if (!strcmp((char *)keyNodeName,"key")) { mode_t isdir=0; int isbin=0; int end=0; newKey=keyNew(0); /* a <key> must have one of the following: - a "name" attribute, used as an absolute name overriding the context - a "basename" attribute, that will be appended to the current context - a "parent" plus "basename" attributes, both appended to current context - only a "parent", appended to current context */ buffer=xmlTextReaderGetAttribute(reader,(const xmlChar *)"name"); if (buffer) { /* set absolute name */ keySetName(newKey,(char *)buffer); xmlFree(buffer); buffer=0; } else { /* logic for relative name calculation */ privateContext=xmlTextReaderGetAttribute(reader, (const xmlChar *)"parent"); buffer=xmlTextReaderGetAttribute(reader, (const xmlChar *)"basename"); if (context) keySetName(newKey,context); if (privateContext) keyAddName(newKey, (char *)privateContext); if (buffer) keyAddName(newKey,(char *)buffer); xmlFree(privateContext); privateContext=0; xmlFree(buffer); buffer=0; } /* test for a short value attribute, instead of <value> bellow */ buffer=xmlTextReaderGetAttribute(reader,(const xmlChar *)"value"); if (buffer) { keySetRaw(newKey,buffer,elektraStrLen((char *)buffer)); xmlFree(buffer); buffer=0; } /* Parse UID */ buffer=xmlTextReaderGetAttribute(reader,(const xmlChar *)"uid"); if (buffer) { int errsave = errno; char * endptr; long int uid = strtol ((const char *)buffer, &endptr, 10); errno = errsave; if (endptr != '\0' && *endptr == '\0') { keySetUID(newKey,uid); } xmlFree(buffer); buffer=0; } /* Parse GID */ buffer=xmlTextReaderGetAttribute(reader,(const xmlChar *)"gid"); if (buffer) { int errsave = errno; char * endptr; long int gid = strtol ((const char *)buffer, &endptr, 10); errno = errsave; if (endptr != '\0' && *endptr == '\0') { keySetGID(newKey,gid); } xmlFree(buffer); buffer=0; } /* Parse mode permissions */ buffer=xmlTextReaderGetAttribute(reader,(const xmlChar *)"mode"); int errsave = errno; if (buffer) keySetMode(newKey,strtol((char *)buffer,0,0)); errno = errsave; xmlFree(buffer); if (xmlTextReaderIsEmptyElement(reader)) { /* we have a <key ..../> element */ if (newKey && !appended) { ksAppendKey(ks,newKey); appended=1; end=1; } } buffer=xmlTextReaderGetAttribute(reader,(const xmlChar *)"type"); if (buffer) { if (!strcmp((char *)buffer,"binary")) isbin = 1; else if (!strcmp((char *)buffer,"bin")) isbin = 1; } xmlFree(buffer); /* If "isdir" appears, everything different from "0", "false" or "no" marks it as a dir key */ buffer=xmlTextReaderGetAttribute(reader,(const xmlChar *)"isdir"); if (!isdir && buffer) { if ( strcmp((char *)buffer,"0") && strcmp((char *)buffer,"false") && strcmp((char *)buffer,"no")) isdir = 1; else isdir = 0; } xmlFree(buffer); if (isdir) keySetDir(newKey); if (isbin) keySetMeta (newKey, "binary", ""); // TODO: should parse arbitrary attributes as metadata /* Parse everything else */ while (!end) { xmlTextReaderRead(reader); nodeName=xmlTextReaderName(reader); if (!strcmp((char *)nodeName,"value")) { if (xmlTextReaderIsEmptyElement(reader) || xmlTextReaderNodeType(reader)==15) { xmlFree (nodeName); continue; } xmlTextReaderRead(reader); buffer=xmlTextReaderValue(reader); if (buffer) { /* Key's value type was already set above */ if (keyIsBinary(newKey)) { /* TODO binary values char *unencoded=0; size_t unencodedSize; unencodedSize=elektraStrLen((char *)buffer)/2; unencoded=elektraMalloc(unencodedSize); unencodedSize=kdbbDecode((char *)buffer,unencoded); if (!unencodedSize) return -1; keySetRaw(newKey,unencoded,unencodedSize); elektraFree (unencoded); */ } else keySetRaw(newKey,buffer,elektraStrLen((char *)buffer)); } xmlFree(buffer); } else if (!strcmp((char *)nodeName,"comment")) { ssize_t commentSize=0; if (xmlTextReaderIsEmptyElement(reader) || xmlTextReaderNodeType(reader)==15) { xmlFree (nodeName); continue; } xmlTextReaderRead(reader); buffer=xmlTextReaderValue(reader); if ((commentSize=keyGetCommentSize(newKey)) > 1) { /*Multiple line comment*/ char *tmpComment=0; tmpComment=elektraMalloc(commentSize+ xmlStrlen(buffer)*sizeof(xmlChar)+1); if (tmpComment) { keyGetComment(newKey,tmpComment,commentSize); strcat(tmpComment,"\n"); strcat(tmpComment,(char *)buffer); keySetComment(newKey,tmpComment); elektraFree (tmpComment); tmpComment=0; } } else keySetComment(newKey,(char *)buffer); xmlFree(buffer); } else if (!strcmp((char *)nodeName,"key")) { /* Here we found </key> or a sub <key>. So include current key in the KeySet. */ if (newKey && !appended) { ksAppendKey(ks,newKey); appended=1; } if (xmlTextReaderNodeType(reader)==15) /* found a </key> */ end=1; else { /* found a sub <key> */ /* prepare the context (parent) */ consumeKeyNode(ks,newKey->key,reader); } } xmlFree (nodeName); } if (privateContext) xmlFree(privateContext); /* seems like we forgot the key, lets delete it */ if (newKey && !appended) { keyDel (newKey); appended=1; } } xmlFree(keyNodeName); return 0; }
int elektraSimpleiniGet (Plugin * handle, KeySet * returned, Key * parentKey) { /* get all keys */ if (!strcmp (keyName (parentKey), "system/elektra/modules/simpleini")) { KeySet * moduleConfig = ksNew ( 30, keyNew ("system/elektra/modules/simpleini", KEY_VALUE, "simpleini plugin waits for your orders", KEY_END), keyNew ("system/elektra/modules/simpleini/exports", KEY_END), keyNew ("system/elektra/modules/simpleini/exports/get", KEY_FUNC, elektraSimpleiniGet, KEY_END), keyNew ("system/elektra/modules/simpleini/exports/set", KEY_FUNC, elektraSimpleiniSet, KEY_END), #include "readme_simpleini.c" keyNew ("system/elektra/modules/simpleini/infos/version", KEY_VALUE, PLUGINVERSION, KEY_END), keyNew ("system/elektra/modules/simpleini/config/needs", KEY_VALUE, "the needed configuration to work in a backend", KEY_END), keyNew ("system/elektra/modules/simpleini/config/needs/chars", KEY_VALUE, "Characters needed", KEY_END), // space in value now works: // TODO: characters present in format should be escaped /* keyNew ("system/elektra/modules/simpleini/config/needs/chars/20", KEY_VALUE, "61", KEY_END), // space -> a keyNew ("system/elektra/modules/simpleini/config/needs/chars/23", KEY_VALUE, "62", KEY_END), // # -> b keyNew ("system/elektra/modules/simpleini/config/needs/chars/25", KEY_VALUE, "63", KEY_END), // % -> c (escape character) keyNew ("system/elektra/modules/simpleini/config/needs/chars/3B", KEY_VALUE, "64", KEY_END), // ; -> d keyNew ("system/elektra/modules/simpleini/config/needs/chars/3D", KEY_VALUE, "65", KEY_END), // = -> e keyNew ("system/elektra/modules/simpleini/config/needs/chars/5C", KEY_VALUE, "66", KEY_END), // \\ -> f */ keyNew ("system/elektra/modules/simpleini/config/needs/chars/0A", KEY_VALUE, "67", KEY_END), // enter (NL) -> g keyNew ("system/elektra/modules/simpleini/config/needs/chars/0D", KEY_VALUE, "68", KEY_END), // CR -> h keyNew ("system/elektra/modules/simpleini/config/needs/escape", KEY_VALUE, "25", KEY_END), KS_END); ksAppend (returned, moduleConfig); ksDel (moduleConfig); return 1; } char * key = 0; char * value = 0; int errnosave = errno; FILE * fp = fopen (keyString (parentKey), "r"); if (!fp) { ELEKTRA_SET_ERROR_GET (parentKey); errno = errnosave; return -1; } char * format = getFormat (handle, "%ms", "%m[^\n]"); ELEKTRA_LOG ("Read from '%s' with format '%s'", keyString (parentKey), format); int n = 0; size_t size = 0; ssize_t ksize = 0; #pragma GCC diagnostic ignored "-Wformat" // icc warning #269: invalid format string conversion while ((n = fscanf (fp, format, &key, &value)) >= 0) { ELEKTRA_LOG_DEBUG ("Read %d parts: '%s' with value '%s'", n, key, value); if (n == 0) { // discard line getline (&key, &size, fp); ELEKTRA_LOG_DEBUG ("Discard '%s'", key); elektraFree (key); key = 0; continue; } Key * read = keyNew (keyName (parentKey), KEY_END); if (keyAddName (read, key) == -1) { ELEKTRA_ADD_WARNING (ELEKTRA_WARNING_INVALID_KEY, parentKey, key); keyDel (read); continue; } if (n == 2) { keySetString (read, value); elektraFree (value); value = 0; } if (ksAppendKey (returned, read) != ksize + 1) { ELEKTRA_SET_ERROR (ELEKTRA_ERROR_NOEOF, parentKey, "duplicated key"); return -1; } ++ksize; elektraFree (key); key = 0; } if (feof (fp) == 0) { elektraFree (format); fclose (fp); ELEKTRA_SET_ERROR (ELEKTRA_ERROR_NOEOF, parentKey, "not at the end of file"); return -1; } elektraFree (format); fclose (fp); return 1; /* success */ }
static int iniKeyToElektraKey (void *vhandle, const char *section, const char *name, const char *value, unsigned short lineContinuation) { CallbackHandle *handle = (CallbackHandle *)vhandle; Key *appendKey = keyDup (handle->parentKey); keySetMeta(appendKey, "ini/lastSection", 0); if (!section || *section == '\0') { section = INTERNAL_ROOT_SECTION; } appendKey = createUnescapedKey(appendKey, section); short mergeSections = 0; Key *existingKey = NULL; if ((existingKey = ksLookup(handle->result, appendKey, KDB_O_NONE))) { if (keyGetMeta(existingKey, "ini/duplicate")) { mergeSections = 1; } } setSectionNumber(handle->parentKey, appendKey, handle->result); appendKey = createUnescapedKey(appendKey, name); existingKey = ksLookup(handle->result, appendKey, KDB_O_NONE); if (existingKey) { //a key with the same name already exists if (handle->array) { //array support is turned on keySetMeta(appendKey, "ini/section", 0); if (keyGetMeta(existingKey, "ini/array")) { //array already exists, appending new key const char *lastIndex = keyString(keyGetMeta(existingKey, "ini/array")); keyAddBaseName(appendKey, lastIndex); keySetMeta(appendKey, "order/parent", 0); keySetMeta(appendKey, "ini/array", 0); keySetMeta(appendKey, "order", 0); if (elektraArrayIncName(appendKey) == 1) { return -1; } keySetString(appendKey, value); keySetMeta(appendKey, "ini/key", 0); ksAppendKey(handle->result, appendKey); keySetMeta(existingKey, "ini/array", keyBaseName(appendKey)); ksAppendKey(handle->result, existingKey); } else { //creating a new array Key *sectionKey = keyDup(appendKey); keyAddName(sectionKey, ".."); char *origVal = strdup(keyString(existingKey)); keySetString(appendKey, ""); keySetMeta(appendKey, "ini/array", "#1"); keySetMeta(appendKey, "order/parent", keyName(sectionKey)); setSectionNumber(handle->parentKey, appendKey, handle->result); setOrderNumber(handle->parentKey, appendKey); keySetMeta(appendKey, "ini/key", ""); ksAppendKey(handle->result, keyDup(appendKey)); keySetMeta(appendKey, "ini/key", 0); keySetMeta(appendKey, "ini/array", 0); keySetMeta(appendKey, "parent", 0); keyAddName(appendKey, "#"); keySetMeta(appendKey, "order", 0); if (elektraArrayIncName(appendKey) == -1) { free(origVal); return -1; } keySetString(appendKey, origVal); ksAppendKey(handle->result, keyDup(appendKey)); free(origVal); if (elektraArrayIncName(appendKey) == -1) { return -1; } keySetMeta(appendKey, "parent", 0); keySetString(appendKey, value); ksAppendKey(handle->result, keyDup(appendKey)); keyDel(appendKey); keyDel(sectionKey); } return 1; } else if(!lineContinuation) { ELEKTRA_SET_ERRORF(141, handle->parentKey, "Key: %s\n", name); return -1; } } setSectionNumber(handle->parentKey, appendKey, handle->result); if (value == NULL) keySetMeta(appendKey, "ini/empty", ""); if (!lineContinuation) { flushCollectedComment (handle, appendKey); keySetString (appendKey, value); keySetMeta(appendKey, "ini/key", ""); ksAppendKey (handle->result, appendKey); if (mergeSections) { keySetMeta(appendKey, "order", 0); insertNewKeyIntoExistendOrder(appendKey, handle->result); } else { setOrderNumber(handle->parentKey, appendKey); } } else { existingKey = ksLookup (handle->result, appendKey, KDB_O_NONE); keyDel (appendKey); /* something went wrong before because this key should exist */ if (!existingKey) return -1; elektraKeyAppendLine(existingKey, value); } return 1; }
static int csvRead(KeySet *returned, Key *parentKey, char delim, short useHeader, unsigned long fixColumnCount, const char **colNames) { const char *fileName; fileName = keyString(parentKey); FILE *fp = NULL; fp = fopen(fileName, "rb"); if(!fp) { ELEKTRA_SET_ERRORF(116, parentKey, "couldn't open file %s\n", fileName); return -1; } unsigned long length = 0; length = getLineLength(fp); if(length == 0) { ELEKTRA_ADD_WARNING(118, parentKey, "Empty file"); fclose(fp); return -2; } char *lineBuffer; lineBuffer = elektraMalloc((length * sizeof(char))+1); if(!lineBuffer) { ELEKTRA_SET_ERROR(87, parentKey, "Out of memory"); return -1; } if(!fgets(lineBuffer, length, fp)) { ELEKTRA_SET_ERROR(116, parentKey, "Cant read from file"); return -1; } unsigned long columns = 0; columns = getColumnCount(lineBuffer, delim); if(fixColumnCount) { if(columns != fixColumnCount) { ELEKTRA_SET_ERROR(117, parentKey, "illegal number of columns in Header line"); elektraFree(lineBuffer); fclose(fp); return -1; } } unsigned long colCounter = 0; unsigned long lineCounter = 0; unsigned long offset = 0; char *col; char buf[INTSTR_MAX]; int nr_keys = 1; KeySet *header = ksNew(0, KS_END); Key *key; if(useHeader == 1) { colCounter = 0; offset = 0; while((col = parseLine(lineBuffer, delim, offset, parentKey, lineCounter)) != NULL) { offset += elektraStrLen(col); key = keyDup(parentKey); if(colNames && (colNames+colCounter)) { keyAddBaseName(key, colNames[colCounter]); } else { keyAddBaseName(key, col); } keySetMeta(key, "csv/order", itostr(buf, colCounter, sizeof(buf)-1)); ksAppendKey(header, key); ++colCounter; } fseek(fp, 0, SEEK_SET); } else { colCounter = 0; //if no headerline exists name the columns 0..N where N is the number of columns key = keyDup(parentKey); keyAddName(key, "#"); while(colCounter < columns) { if(elektraArrayIncName(key) == -1) { elektraFree(lineBuffer); keyDel(key); ksDel(header); fclose(fp); return -1; } keySetMeta(key, "csv/order", itostr(buf, colCounter, sizeof(buf)-1)); if(colNames && (colNames+colCounter)) keySetBaseName(key, colNames[colCounter]); ksAppendKey(header, keyDup(key)); ++colCounter; } keyDel(key); if(useHeader == 0) fseek(fp, 0, SEEK_SET); } Key *dirKey; Key *cur; dirKey = keyDup(parentKey); keyAddName(dirKey, "#"); while(!feof(fp)) { length = getLineLength(fp); if(length == 0) break; if(elektraRealloc((void **)&lineBuffer, (length * sizeof(char))+1) < 0) { fclose(fp); elektraFree(lineBuffer); ksDel(header); keyDel(dirKey); ELEKTRA_SET_ERROR(87, parentKey, "Out of memory"); return -1; } fgets(lineBuffer, length, fp); if(elektraArrayIncName(dirKey) == -1) { elektraFree(lineBuffer); keyDel(dirKey); ksDel(header); fclose(fp); return -1; } ++nr_keys; offset = 0; colCounter = 0; char *lastIndex = "#0"; while((col = parseLine(lineBuffer, delim, offset, parentKey, lineCounter)) != NULL) { cur = getKeyByOrderNr(header, colCounter); offset += elektraStrLen(col); key = keyDup(dirKey); keyAddBaseName(key, keyBaseName(cur)); keySetString(key, col); keySetMeta(key, "csv/order", itostr(buf, colCounter, sizeof(buf)-1)); ksAppendKey(returned, key); lastIndex = (char *)keyBaseName(key); ++nr_keys; ++colCounter; } keySetString(dirKey, lastIndex); ksAppendKey(returned, keyDup(dirKey)); if(colCounter != columns) { if(fixColumnCount) { ELEKTRA_SET_ERRORF(117, parentKey, "illegal number of columns in line %lu", lineCounter); elektraFree(lineBuffer); fclose(fp); keyDel(dirKey); ksDel(header); return -1; } ELEKTRA_ADD_WARNINGF(118, parentKey, "illegal number of columns in line %lu", lineCounter); } ++lineCounter; } key = keyDup(parentKey); keySetString(key, keyBaseName(dirKey)); ksAppendKey(returned, key); keyDel(dirKey); fclose(fp); elektraFree(lineBuffer); ksDel(header); return 1; }
/** * Walks through kdb->split and adds all backends below parentKey to split. * * Sets syncbits to 2 if it is a default or root backend (which needs splitting). * The information is copied from kdb->split. * * @pre split needs to be empty, directly after creation with elektraSplitNew(). * * @pre there needs to be a valid defaultBackend * but its ok not to have a trie inside KDB. * * @pre parentKey must be a valid key! (could be implemented more generally, * but that would require splitting up of keysets of the same backend) * * @param split will get all backends appended * @param kdb the handle to get information about backends * @param parentKey the information below which key the backends are from interest * @ingroup split * @retval 1 always */ int elektraSplitBuildup (Split * split, KDB * kdb, Key * parentKey) { /* For compatibility reasons invalid names are accepted, too. * This solution is faster than checking the name of parentKey * every time in loop. * The parentKey might be null in some unit tests, so also check * for this. */ const char * name = keyName (parentKey); if (!parentKey || !name || !strcmp (name, "") || !strcmp (name, "/")) { parentKey = 0; } else if (name[0] == '/') { Key * key = keyNew (0, KEY_END); for (elektraNamespace ins = KEY_NS_FIRST; ins <= KEY_NS_LAST; ++ins) { if (!elektraKeySetNameByNamespace (key, ins)) continue; keyAddName (key, keyName (parentKey)); elektraSplitBuildup (split, kdb, key); } keyDel (key); return 1; } /* Returns the backend the key is in or the default backend otherwise */ Backend * backend = elektraMountGetBackend (kdb, parentKey); #if DEBUG && VERBOSE printf (" with parent %s\n", keyName (parentKey)); #endif for (size_t i = 0; i < kdb->split->size; ++i) { #if DEBUG && VERBOSE printf (" %zu with parent %s\n", i, keyName (kdb->split->parents[i])); #endif if (!parentKey) { #if DEBUG && VERBOSE printf (" def add %s\n", keyName (kdb->split->parents[i])); #endif /* Catch all: add all mountpoints */ elektraSplitAppend (split, kdb->split->handles[i], keyDup (kdb->split->parents[i]), kdb->split->syncbits[i]); } else if (backend == kdb->split->handles[i] && keyRel (kdb->split->parents[i], parentKey) >= 0) { #if DEBUG && VERBOSE printf (" exa add %s\n", keyName (kdb->split->parents[i])); #endif /* parentKey is exactly in this backend, so add it! */ elektraSplitAppend (split, kdb->split->handles[i], keyDup (kdb->split->parents[i]), kdb->split->syncbits[i]); } else if (keyRel (parentKey, kdb->split->parents[i]) >= 0) { #if DEBUG && VERBOSE printf (" rel add %s\n", keyName (kdb->split->parents[i])); #endif /* this backend is completely below the parentKey, so lets add it. */ elektraSplitAppend (split, kdb->split->handles[i], keyDup (kdb->split->parents[i]), kdb->split->syncbits[i]); } } return 1; }