static void test_elektraMalloc (void) { char * buffer = 0; buffer = elektraMalloc (50); exit_if_fail (buffer, "buffer must not be 0 after allocation"); elektraRealloc ((void **)&buffer, 100); exit_if_fail (buffer, "buffer must not be 0 after reallocation"); elektraRealloc ((void **)&buffer, 20); exit_if_fail (buffer, "buffer must not be 0 after reallocation"); elektraFree (buffer); buffer = elektraCalloc (50); exit_if_fail (buffer, "buffer must not be 0 after allocation"); for (int i = 0; i < 50; ++i) { succeed_if (buffer[i] == 0, "elektraCalloc did not initialize buffer with zeros"); } elektraRealloc ((void **)&buffer, 100); exit_if_fail (buffer, "buffer must not be 0 after reallocation"); elektraRealloc ((void **)&buffer, 20); exit_if_fail (buffer, "buffer must not be 0 after reallocation"); char * dup = elektraStrNDup (buffer, 20); exit_if_fail (dup, "could not duplicate buffer"); elektraFree (buffer); buffer = 0; for (int i = 0; i < 20; ++i) { succeed_if (dup[i] == 0, "elektraStrNDup did not correctly copy zero-buffer"); } elektraFree (dup); }
char * elektraMetaArrayToString (Key * key, const char * metaName, const char * delim) { char * result = NULL; Key * lookupElem = keyDup (keyGetMeta (key, metaName)); keyAddBaseName (lookupElem, "#0"); Key * elem = (Key *)keyGetMeta (key, keyName (lookupElem)); if (elem != NULL) { elektraRealloc ((void **)&result, keyGetValueSize (elem)); snprintf (result, keyGetValueSize (elem), "%s", keyString (elem)); } elektraArrayIncName (lookupElem); elem = (Key *)keyGetMeta (key, keyName (lookupElem)); while (elem != NULL) { elektraRealloc ((void **)&result, elektraStrLen (result) + keyGetValueSize (elem) + 1); // String (incl. +2 times \0) + delimiter + whitespace strcat (result, delim); strcat (result, keyString (elem)); elektraArrayIncName (lookupElem); elem = (Key *)keyGetMeta (key, keyName (lookupElem)); } keyDel (lookupElem); return result; }
/** * Doubles the size of how many parts of keysets can be appended. * * @param split the split object to work with * @ingroup split */ void elektraSplitResize (Split * split) { split->alloc *= 2; elektraRealloc ((void **)&split->keysets, split->alloc * sizeof (KeySet *)); elektraRealloc ((void **)&split->handles, split->alloc * sizeof (KDB *)); elektraRealloc ((void **)&split->parents, split->alloc * sizeof (Key *)); elektraRealloc ((void **)&split->syncbits, split->alloc * sizeof (int)); }
/** * @brief Add an already escaped name to the keyname. * * The same way as in keySetName() this method finds the canonical pathname: * - it will ignore /./ * - it will remove a level when /../ is used * - it will remove multiple slashes //// * * For example: * @snippet keyName.c add name * * Unlike keySetName() it adds relative to the previous name and * cannot change the namespace of a key. * For example: * @snippet keyName.c namespace * * The passed name needs to be valid according the @link keyname key name rules @endlink. * It is not allowed to: * - be empty * - end with unequal number of \\ * * @param key the key where a name should be added * @param newName the new name to append * * @since 0.8.11 * * @retval size of the new key * @retval -1 if key is a null pointer or did not have a valid name before * @retval -1 if newName is not a valid escaped name * @retval -1 on allocation errors * @retval -1 if key was inserted to a keyset before * @retval 0 if nothing was done because newName had only slashes, is too short, is empty or is null * @ingroup keyname */ ssize_t keyAddName (Key * key, const char * newName) { if (!key) return -1; if (test_bit (key->flags, KEY_FLAG_RO_NAME)) return -1; if (!key->key) return -1; if (!strcmp (key->key, "")) return -1; if (!newName) return 0; size_t const nameSize = elektraStrLen (newName); if (nameSize < 2) return 0; if (!elektraValidateKeyName (newName, nameSize)) return -1; const size_t origSize = key->keySize; const size_t newSize = origSize + nameSize; elektraRealloc ((void **)&key->key, newSize * 2); if (!key->key) return -1; size_t size = 0; const char * p = newName; int avoidSlash = 0; if (*key->key == '/') avoidSlash = key->keySize == 2; --key->keySize; // loop assumes that key->key[key->keySize] is last character and not NULL /* iterate over each single folder name removing repeated '/', . and .. */ while (*(p = keyNameGetOneLevel (p + size, &size))) { if (size == 1 && strncmp (p, ".", 1) == 0) { continue; /* just ignore current directory */ } else if (size == 2 && strncmp (p, "..", 2) == 0) /* give away one level*/ { elektraRemoveOneLevel (key, &avoidSlash); continue; } if (!avoidSlash) { /* Add a '/' to the end of key name */ key->key[key->keySize] = KDB_PATH_SEPARATOR; key->keySize++; } else { avoidSlash = 0; } /* carefully append basenames */ char * d = key->key + key->keySize; memcpy (d, p, size); key->keySize += size; } ++key->keySize; /*for \\0 ending*/ elektraFinalizeName (key); return origSize == key->keySize ? 0 : key->keySize; }
static void elektraResolveSystemXDGHelper (char ** filename, const char * path, const char * result) { size_t configDirSize = elektraStrLen (result); size_t pathSize = elektraStrLen (path); size_t filenameSize = configDirSize + pathSize + sizeof ("/") + 1; elektraRealloc ((void **) filename, filenameSize); strcpy (*filename, result); strcat (*filename, "/"); strcat (*filename, path); }
/** * Sets @c baseName as the new basename for @c key. * * Only the baseName will be affected and no other part of the key. * * All text after the last @c '/' in the @p key keyname is erased and * @p baseName is appended. * * So let us suppose @p key has name @c "system/dir1/dir2/key1". If @p baseName * is @c "key2", the resulting key name will be @c "system/dir1/dir2/key2". * If @p baseName is empty or NULL, the resulting key name will * be @c "system/dir1/dir2". * * This function does proper escaping on the supplied name argument. * * You can use all names to set as basename (e.g. . (dot), .. * (dot-dot), % and "" (empty)). They will be properly escaped. * * A simple example is: * @snippet basename.c set base basic * * If you want to add and not change the basename, use keyAddBaseName() * instead. If you do not want escaping, use keyAddName() instead. * * To add an inactive key name, use: * @snippet testabi_key.c base1 * * When you want to add an array item, use: * @snippet testabi_key.c base2 * * @see keyname for more details on special names * * @param key the key object to work with * @param baseName the string used to overwrite the basename of the key * @return the size in bytes of the new key name * @retval -1 on NULL pointers * @retval -1 if key was inserted to a keyset before * @see keyAddBaseName() * @see keySetName() to set a new name * @ingroup keyname */ ssize_t keySetBaseName(Key *key, const char *baseName) { if (!key) return -1; if (test_bit(key->flags, KEY_FLAG_RO_NAME)) return -1; if (!key->key) return -1; size_t size=0; char *searchBaseName=0; size_t searchBaseSize=0; char *p = key->key; while (*(p=keyNameGetOneLevel(p+size,&size))) { searchBaseName=p; searchBaseSize=size+1; } if (!searchBaseName || searchBaseName==key->key) { return -1; } // truncate the key key->keySize -= searchBaseSize; if (!baseName) { // just remove base name, so we are finished elektraFinalizeName(key); return key->keySize; } char *escaped = elektraMalloc (strlen (baseName) * 2 + 2); elektraEscapeKeyNamePart(baseName, escaped); size_t sizeEscaped = elektraStrLen (escaped); elektraRealloc((void**)&key->key, (key->keySize+sizeEscaped)*2); if (!key->key) { elektraFree (escaped); return -1; } key->key [key->keySize - 1] = KDB_PATH_SEPARATOR; memcpy (key->key + key->keySize, escaped, sizeEscaped); elektraFree (escaped); key->keySize += sizeEscaped; elektraFinalizeName(key); return key->keySize; }
static void elektraResolveSystemXDGHelper (resolverHandle * p, const char * result) { size_t configDirSize = elektraStrLen (result); size_t pathSize = elektraStrLen (p->path); size_t filenameSize = configDirSize + pathSize + sizeof ("/") + 1; elektraRealloc ((void *)&p->filename, filenameSize); strcpy (p->filename, result); strcat (p->filename, "/"); strcat (p->filename, p->path); }
/** * @brief Does string formatting in fresh allocated memory * * @param format as in vprintf() * @param arg_list as in vprintf() * * @return new allocated memory (free with elektraFree) */ char * elektraVFormat (const char * format, va_list arg_list) { ELEKTRA_ASSERT (format, "Got null pointer"); static int const default_size = 512; char * buffer = elektraMalloc (default_size); if (!buffer) return 0; va_list arg_list_adj; va_copy (arg_list_adj, arg_list); int const calculated_length = vsnprintf (buffer, default_size, format, arg_list); if (calculated_length == -1) { va_end (arg_list_adj); elektraFree (buffer); // before Glibc 2.0.6, always -1 is returned // we won't do Glibc job, please upgrade return 0; } if (calculated_length < default_size) { va_end (arg_list_adj); // content was written successfully into // default sized buffer return buffer; } // String is longer than default_size. // Allocate an intermediate buffer // according to the calculated length from our last try size_t const adjusted_buffer_size = calculated_length + 1; elektraRealloc ((void **) &buffer, adjusted_buffer_size); if (!buffer) { va_end (arg_list_adj); return 0; } int const ret = vsnprintf (buffer, adjusted_buffer_size, format, arg_list_adj); va_end (arg_list_adj); if (ret == -1) { elektraFree (buffer); return 0; } return buffer; }
/** * @return freshly allocated buffer with current working directory * * @param warningsKey where warnings are added */ static char * elektraGetCwd (Key * warningsKey) { int size = 4096; char * cwd = elektraMalloc (size); if (cwd == NULL) { ELEKTRA_ADD_WARNING (83, warningsKey, "could not alloc for getcwd, defaulting to /"); return 0; } char * ret = NULL; while (ret == NULL) { ret = getcwd (cwd, size); if (ret == NULL) { if (errno != ERANGE) { // give up, we cannot handle the problem elektraFree (cwd); ELEKTRA_ADD_WARNINGF (ELEKTRA_WARNING_NOCWD, warningsKey, "getcwd failed with errno %d \"%s\", defaulting to /", errno, strerror (errno)); return 0; } // try to double the space size *= 2; elektraRealloc ((void **) &cwd, size); if (cwd == NULL) { ELEKTRA_ADD_WARNINGF (83, warningsKey, "could not realloc for getcwd size %d, defaulting to /", size); return 0; } } } return ret; }
/** * Adds @p baseName (that will be escaped) to the current key name. * * A new baseName will be added, no other part of the key name will be * affected. * * Assumes that @p key is a directory and will append @p baseName to it. * The function adds the path separator for concatenating. * * So if @p key has name @c "system/dir1/dir2" and this method is called with * @p baseName @c "mykey", the resulting key will have the name * @c "system/dir1/dir2/mykey". * * When @p baseName is 0 nothing will happen and the size of the name is returned. * * The escaping rules apply as in @link keyname above @endlink. * * A simple example is: * @snippet basename.c add base basic * * E.g. if you add . it will be escaped: * @snippet testabi_key.c base1 add * * @see keySetBaseName() to set a base name * @see keySetName() to set a new name. * * @param key the key object to work with * @param baseName the string to append to the name * @return the size in bytes of the new key name including the ending NULL * @retval -1 if the key had no name * @retval -1 on NULL pointers * @retval -1 if key was inserted to a keyset before * @ingroup keyname * */ ssize_t keyAddBaseName (Key * key, const char * baseName) { if (!key) return -1; if (!baseName) return key->keySize; if (test_bit (key->flags, KEY_FLAG_RO_NAME)) return -1; if (!key->key) return -1; char * escaped = elektraMalloc (strlen (baseName) * 2 + 2); elektraEscapeKeyNamePart (baseName, escaped); size_t len = strlen (escaped); if (!strcmp (key->key, "/")) { key->keySize += len; } else { key->keySize += len + 1; } elektraRealloc ((void **)&key->key, key->keySize * 2); if (!key->key) { elektraFree (escaped); return -1; } if (strcmp (key->key, "/")) { key->key[key->keySize - len - 2] = KDB_PATH_SEPARATOR; } memcpy (key->key + key->keySize - len - 1, escaped, len); elektraFree (escaped); elektraFinalizeName (key); return key->keySize; }
static CondResult evalCondition (const Key * curKey, const char * leftSide, Comparator cmpOp, const char * rightSide, const char * condition, const Key * suffixList, KeySet * ks, Key * parentKey) { char * lookupName = NULL; char * compareTo = NULL; Key * key; int len; long result = 0; if (rightSide) { if (rightSide[0] == '\'') { // right side of the statement is a literal enclosed by '' char * endPos = strchr (rightSide + 1, '\''); if (!endPos) { result = ERROR; goto Cleanup; } if (elektraRealloc ((void **) &compareTo, endPos - rightSide) < 0) { ELEKTRA_SET_ERROR (87, parentKey, "Out of memory"); result = ERROR; goto Cleanup; } memset (compareTo, 0, endPos - rightSide); strncat (compareTo, rightSide + 1, endPos - rightSide - 1); } else if (rightSide && elektraStrLen (rightSide) > 1) { // not a literal, it has to be a key if (rightSide[0] == '@') len = keyGetNameSize (parentKey) + elektraStrLen (rightSide); else if (!strncmp (rightSide, "..", 2) || (rightSide[0] == '.')) len = keyGetNameSize (curKey) + elektraStrLen (rightSide); else len = elektraStrLen (rightSide); if (elektraRealloc ((void **) &lookupName, len) < 0) { ELEKTRA_SET_ERROR (87, parentKey, "Out of memory"); result = ERROR; goto Cleanup; } if (rightSide[0] == '@') snprintf (lookupName, len, "%s/%s", keyName (parentKey), rightSide + 1); else if (rightSide[0] == '.') // either starts with . or .., doesn't matter at this point snprintf (lookupName, len, "%s/%s", keyName (curKey), rightSide); else snprintf (lookupName, len, "%s", rightSide); key = ksLookupByName (ks, lookupName, 0); if (!key) { if (!keyGetMeta (parentKey, "error")) { ELEKTRA_SET_ERRORF (133, parentKey, "Key %s not found but is required for the evaluation of %s", lookupName, condition); } result = FALSE; goto Cleanup; } if (elektraRealloc ((void **) &compareTo, keyGetValueSize (key)) < 0) { ELEKTRA_SET_ERROR (87, parentKey, "Out of memory"); result = ERROR; goto Cleanup; } strcpy (compareTo, keyString (key)); } } if (leftSide[0] == '@') len = keyGetNameSize (parentKey) + elektraStrLen (leftSide); else if (!strncmp (leftSide, "..", 2) || (leftSide[0] == '.')) len = keyGetNameSize (curKey) + elektraStrLen (leftSide); else len = elektraStrLen (leftSide); if (elektraRealloc ((void **) &lookupName, len) < 0) { ELEKTRA_SET_ERROR (87, parentKey, "Out of memory"); result = ERROR; goto Cleanup; } if (leftSide[0] == '@') snprintf (lookupName, len, "%s/%s", keyName (parentKey), leftSide + 1); else if (leftSide[0] == '.') // either . or .., doesn't matter here snprintf (lookupName, len, "%s/%s", keyName (curKey), leftSide); else snprintf (lookupName, len, "%s", leftSide); key = ksLookupByName (ks, lookupName, 0); if (cmpOp == NEX) { if (key) result = FALSE; else result = TRUE; goto Cleanup; } if (!key && cmpOp != OR && cmpOp != AND) { if (!keyGetMeta (parentKey, "error")) { ELEKTRA_SET_ERRORF (133, parentKey, "Key %s not found but is required for the evaluation of %s", lookupName, condition); } result = FALSE; goto Cleanup; } long ret; if (cmpOp == OR || cmpOp == AND) ret = compareStrings (leftSide, rightSide, NULL); else ret = compareStrings (keyString (key), compareTo, suffixList); switch (cmpOp) { case EQU: if (!ret) result = TRUE; break; case NOT: if (ret) result = TRUE; break; case LT: if (ret < 0) result = TRUE; break; case LE: if (ret <= 0) result = TRUE; break; case GT: if (ret > 0) result = TRUE; break; case GE: if (ret >= 0) result = TRUE; break; case SET: keySetString (key, compareTo); result = TRUE; break; case AND: if (ret == 0 && !strcmp (leftSide, "'1'")) result = TRUE; break; case OR: if (!strcmp (leftSide, "'1'") || (rightSide && !strcmp (rightSide, "'1'"))) result = TRUE; break; default: result = ERROR; break; } // freeing allocated heap Cleanup: if (lookupName) elektraFree (lookupName); if (compareTo) elektraFree (compareTo); return result; }
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; }
static int evalCondition(const char *leftSide, Comparator cmpOp, const char *rightSide, KeySet *ks, Key *parentKey) { char *lookupName = NULL; char *compareTo = NULL; Key *key; int len; long result = 0; if(rightSide[0] == '\'') { char *endPos = strchr(rightSide+1, '\''); if(!endPos) { result = -1; goto Cleanup; } if(elektraRealloc((void **)&compareTo, endPos-rightSide) < 0) { ELEKTRA_SET_ERROR(87, parentKey, "Out of memory"); result = -1; goto Cleanup; } memset(compareTo, 0, endPos-rightSide); strncat(compareTo, rightSide+1, endPos-rightSide-1); } else if(rightSide && elektraStrLen(rightSide) > 1) { len = keyGetNameSize(parentKey)+elektraStrLen(rightSide); if(elektraRealloc((void **)&lookupName, len) < 0) { ELEKTRA_SET_ERROR(87, parentKey, "Out of memory"); result = -1; goto Cleanup; } snprintf(lookupName, len, "%s/%s", keyName(parentKey), rightSide); key = ksLookupByName(ks, lookupName, 0); if(!key) { ELEKTRA_SET_ERRORF(133, parentKey, "Key %s doesn't exist", lookupName); result = -1; goto Cleanup; } if(elektraRealloc((void **)&compareTo, keyGetValueSize(key)) < 0) { ELEKTRA_SET_ERROR(87, parentKey, "Out of memory"); result = -1; goto Cleanup; } strcpy(compareTo, keyString(key)); } len = keyGetNameSize(parentKey)+elektraStrLen(leftSide); if(elektraRealloc((void **)&lookupName, len) < 0) { ELEKTRA_SET_ERROR(87, parentKey, "Out of memory"); result = -1; goto Cleanup; } snprintf(lookupName, len, "%s/%s", keyName(parentKey), leftSide); key = ksLookupByName(ks, lookupName, 0); if(!key) { ELEKTRA_SET_ERRORF(133, parentKey, "Key %s doesn't exist", lookupName); result = -1; goto Cleanup; } long ret; ret = compareStrings(keyString(key), compareTo); switch(cmpOp) { case EQU: if(!ret) result = 1; break; case NOT: if(ret) result = 1; break; case LT: if(ret < 0) result = 1; break; case LE: if(ret <= 0) result = 1; break; case GT: if(ret > 0) result = 1; break; case GE: if(ret >= 0) result = 1; break; case SET: keySetString(key, compareTo); result = 1; break; default: result = -1; break; } //freeing allocated heap Cleanup: if(lookupName) elektraFree(lookupName); if(compareTo) elektraFree(compareTo); return result; }