// test simple variable passing static void test_variable_passing (void) { printf ("Testing simple variable passing...\n"); KeySet * conf = ksNew (1, keyNew ("user/script", KEY_VALUE, srcdir_file ("lua/lua_plugin.lua"), KEY_END), keyNew ("user/print", KEY_END), KS_END); PLUGIN_OPEN ("lua"); Key * parentKey = keyNew ("user/from_c", KEY_END); KeySet * ks = ksNew (0, KS_END); succeed_if (plugin->kdbGet (plugin, ks, parentKey) >= 1, "call to kdbGet was not successful"); succeed_if (ksGetSize (ks) == 1, "keyset size is still 0"); succeed_if (ksGetSize (ks) == 1 && !strcmp (keyName (ksHead (ks)), "user/from_lua"), "key in keyset has wrong name"); succeed_if (output_warnings (parentKey), "warnings in kdbOpen"); succeed_if (output_error (parentKey), "errors in kdbOpen"); ksDel (ks); keyDel (parentKey); PLUGIN_CLOSE (); }
static void test_reviterate() { printf ("Test reviterate trie\n"); Trie * trie = test_insert (0, "user/tests/hosts/below", "below"); trie = test_insert (trie, "user/tests/hosts", "hosts"); exit_if_fail (trie, "trie was not build up successfully"); Key *searchKey = keyNew("user", KEY_END); Backend *backend = elektraTrieLookup(trie, searchKey); succeed_if (!backend, "there should be no backend"); Key *mp = keyNew("user/tests/hosts", KEY_VALUE, "hosts", KEY_END); keySetName(searchKey, "user/tests/hosts"); backend = elektraTrieLookup(trie, searchKey); succeed_if (backend, "there should be a backend"); compare_key(backend->mountpoint, mp); // printf ("backend: %p\n", (void*)backend); keySetName(searchKey, "user/tests/hosts/other/below"); Backend *b2 = elektraTrieLookup(trie, searchKey); succeed_if (b2, "there should be a backend"); succeed_if (backend == b2, "should be same backend"); compare_key(b2->mountpoint, mp); // printf ("b2: %p\n", (void*)b2); keySetName(searchKey, "user/tests/hosts/other/deep/below"); b2 = elektraTrieLookup(trie, searchKey); succeed_if (b2, "there should be a backend"); succeed_if (backend == b2, "should be same backend"); compare_key(b2->mountpoint, mp); Key *mp2 = keyNew("user/tests/hosts/below", KEY_VALUE, "below", KEY_END); keySetName(searchKey, "user/tests/hosts/below"); Backend *b3 = elektraTrieLookup(trie, searchKey); succeed_if (b3, "there should be a backend"); succeed_if (backend != b3, "should be different backend"); compare_key(b3->mountpoint, mp2); backend = b3; // printf ("b3: %p\n", (void*)b3); keySetName(searchKey, "user/tests/hosts/below/other/deep/below"); b2 = elektraTrieLookup(trie, searchKey); succeed_if (b3, "there should be a backend"); succeed_if (backend == b3, "should be same backend"); compare_key(b3->mountpoint, mp2); KeySet *mps = ksNew(0, KS_END); collect_mountpoints(trie, mps); succeed_if (ksGetSize (mps) == 2, "not both mountpoints collected"); compare_key(ksHead(mps), mp); compare_key(ksTail(mps), mp2); ksDel (mps); elektraTrieClose(trie, 0); keyDel (mp); keyDel (mp2); keyDel (searchKey); }
int elektraSortTopology (KeySet * ks, Key ** array) { if (ks == NULL || array == NULL) return -1; KeySet * done = ksNew (0, KS_END); ksRewind (ks); Key * cur; ssize_t size = ksGetSize (ks); Key * orderCounter = keyNew ("/#", KEY_CASCADING_NAME, KEY_END); elektraArrayIncName (orderCounter); _adjMatrix adjMatrix[size]; int i = 0; int retVal = 1; int depCount = 0; Key ** localArray = elektraMalloc (size * sizeof (Key *)); elektraKsToMemArray (ks, localArray); qsort (localArray, size, sizeof (Key *), topCmpOrder); for (long j = 0; j < size; ++j) { adjMatrix[j].key = localArray[j]; adjMatrix[j].isResolved = 0; adjMatrix[j].deps = elektraCalloc (sizeof (unsigned long) * size); } kdb_octet_t hasOrder = 0; if (keyGetMeta (localArray[0], "order")) hasOrder = 1; unsigned int unresolved = 0; for (int j = 0; j < size; ++j) { cur = localArray[j]; KeySet * deps = elektraMetaArrayToKS (cur, "dep"); keyDel (ksLookupByName (deps, "dep", KDB_O_POP)); Key * tmpDep; switch (ksGetSize (deps)) { case -1: { // key has no dependencies, give it an order number and add it to list of resolved dependencies keySetMeta (cur, "order", keyBaseName (orderCounter)); elektraArrayIncName (orderCounter); ksAppendKey (done, keyDup (cur)); adjMatrix[j].isResolved = 1; ksDel (deps); break; } case 1: { // only 1 dependency: // test if it's reflexive tmpDep = ksHead (deps); if (!strcmp (keyName (cur), keyString (tmpDep))) { keySetMeta (cur, "order", keyBaseName (orderCounter)); elektraArrayIncName (orderCounter); ksAppendKey (done, keyDup (cur)); adjMatrix[j].isResolved = 1; ksDel (deps); break; } // if not, fallthrough to normal dependency handling } default: { int gotUnresolved = 0; while ((tmpDep = ksNext (deps)) != NULL) { if (!isValidKeyName (keyString (tmpDep))) { // invalid keyname -> ERROR retVal = -1; break; } i = getArrayIndex (tmpDep, adjMatrix, size); if (i == -1) { // key doesn't exist yet but has valid name, ignore it. continue; } else if (i == j) { // reflexiv depencency, do nothing } else { if (!adjMatrix[i].isResolved) { // unresolved dependency adjMatrix[j].deps[i] = 1; ++gotUnresolved; // simple cycle detection if (adjMatrix[i].deps[j]) { retVal = 0; break; } } } } if (gotUnresolved) { adjMatrix[j].isResolved = 0; ++unresolved; // cound unresolved dependencies depCount += gotUnresolved; } ksDel (deps); break; } } if (retVal <= 0) break; } if (retVal <= 0) { // error or cycle: goto cleanup goto TopSortCleanup; } // resolve all dependencies that can be resolved immediately for (int j = 0; j < size; ++j) { if (adjMatrix[j].isResolved) depCount -= resolveDep (j, adjMatrix, size); } ssize_t resolved = ksGetSize (done); if (((depCount + resolved) >= size) && (unresolved)) { // more dependencies dependencies than keys: // cycle found ! retVal = 0; goto TopSortCleanup; } if (unresolved) { int found = 1; // we have unresolved dependencies for (int j = 0; j < size + 1; ++j) { // loop until no dependency can be resolved anymore if (j == size) { if (found) { found = 0; j = -1; unresolved = 0; continue; } else break; } if (adjMatrix[j].isResolved) continue; ++unresolved; if (hasOrder) { // resolve by order int ret = resolveDeps (j, adjMatrix, size, done, orderCounter); if (ret == -1) break; j = -1; found = 1; continue; } else { // resolve next possible dependency in keyset if (!hasUnresolvedDependencies (j, adjMatrix, size)) { adjMatrix[j].isResolved = 1; resolveDep (j, adjMatrix, size); keySetMeta (localArray[j], "order", keyBaseName (orderCounter)); elektraArrayIncName (orderCounter); ksAppendKey (done, keyDup (localArray[j])); found = 1; } } } } if (unresolved == 0) { // everything resolved // add dependencies in topological order to array elektraKsToMemArray (ks, array); qsort (array, size, sizeof (Key *), topCmpOrder); retVal = 1; } else { // still unresolved dependencies left: // there must be a cycle somewhere retVal = 0; } TopSortCleanup: ksDel (done); keyDel (orderCounter); elektraFree (localArray); for (ssize_t j = 0; j < size; ++j) { elektraFree (adjMatrix[j].deps); } return retVal; }