void INIFile::Section::setStringValue(const std::string& key, const std::string& newValue) {
	if(hasKey(key)) {
	    getKey(key)->setStringValue(newValue);
	} else {
		// create new key
		if(isValidKeyName(key) == false) {
			std::cerr << "INIFile: Cannot create key with name " << key << "!" << std::endl;
			return;
		}

        Key* curKey = new Key(key, newValue);
        Key* pKey = KeyRoot;
        if(pKey == NULL) {
            // Section has no key yet
            if(nextLine == NULL) {
                // no line after this section declaration
                nextLine = curKey;
                curKey->prevLine = this;
            } else {
                // lines after this section declaration
                nextLine->prevLine = curKey;
                curKey->nextLine = nextLine;
                nextLine = curKey;
                curKey->prevLine = this;
            }
        } else {
            // Section already has some keys
            while(pKey->nextKey != NULL) {
                pKey = pKey->nextKey;
            }

            if(pKey->nextLine == NULL) {
                // no line after this key
                pKey->nextLine = curKey;
                curKey->prevLine = pKey;
            } else {
                // lines after this section declaration
                pKey->nextLine->prevLine = curKey;
                curKey->nextLine = pKey->nextLine;
                pKey->nextLine = curKey;
                curKey->prevLine = pKey;
            }
        }

		InsertKey(curKey);
	}
}
Exemple #2
0
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;
}