/** * Compare 2 keys. * * The returned flags bit array has 1s (differ) or 0s (equal) for each key * meta info compared, that can be logically ORed using @c #keyswitch_t flags. * @link keyswitch_t::KEY_NAME KEY_NAME @endlink, * @link keyswitch_t::KEY_VALUE KEY_VALUE @endlink, * @link keyswitch_t::KEY_OWNER KEY_OWNER @endlink, * @link keyswitch_t::KEY_COMMENT KEY_COMMENT @endlink, * @link keyswitch_t::KEY_UID KEY_UID @endlink, * @link keyswitch_t::KEY_GID KEY_GID @endlink, * @link keyswitch_t::KEY_MODE KEY_MODE @endlink and * * @par A very simple example would be * @code Key *key1, *key; uint32_t changes; // omited key1 and key2 initialization and manipulation changes=keyCompare(key1,key2); if (changes == 0) printf("key1 and key2 are identicall\n"); if (changes & KEY_VALUE) printf("key1 and key2 have different values\n"); if (changes & KEY_UID) printf("key1 and key2 have different UID\n"); * * @endcode * * * @par Example of very powerful specific Key lookup in a KeySet: * @code KDB *handle = kdbOpen(); KeySet *ks=ksNew(0); Key *base = keyNew ("user/sw/MyApp/something", KEY_END); Key *current; uint32_t match; uint32_t interests; kdbGetByName(handle, ks, "user/sw/MyApp", 0); // we are interested only in key type and access permissions interests=(KEY_TYPE | KEY_MODE); ksRewind(ks); // put cursor in the beginning while ((curren=ksNext(ks))) { match=keyCompare(current,base); if ((~match & interests) == interests) printf("Key %s has same type and permissions of base key",keyName(current)); // continue walking in the KeySet.... } // now we want same name and/or value interests=(KEY_NAME | KEY_VALUE); // we don't really need ksRewind(), since previous loop achieved end of KeySet ksRewind(ks); while ((current=ksNext(ks))) { match=keyCompare(current,base); if ((~match & interests) == interests) { printf("Key %s has same name, value, and sync status of base key",keyName(current)); } // continue walking in the KeySet.... } keyDel(base); ksDel(ks); kdbClose (handle); * @endcode * * @return a bit array pointing the differences * @param key1 first key * @param key2 second key * @see #keyswitch_t * @ingroup keytest */ keyswitch_t keyCompare(const Key *key1, const Key *key2) { if (!key1 && !key2) return 0; if (!key1 || !key2) return KEY_NULL; keyswitch_t ret=0; ssize_t nsize1 = keyGetNameSize(key1); ssize_t nsize2 = keyGetNameSize(key2); const char *name1 = keyName(key1); const char *name2 = keyName(key2); const char *comment1 = keyComment(key1); const char *comment2 = keyComment(key2); const char *owner1 = keyOwner(key1); const char *owner2 = keyOwner(key2); const void *value1 = keyValue(key1); const void *value2 = keyValue(key2); ssize_t size1 = keyGetValueSize(key1); ssize_t size2 = keyGetValueSize(key2); if (keyGetUID(key1) != keyGetUID(key2)) ret|=KEY_UID; if (keyGetGID(key1) != keyGetGID(key2)) ret|=KEY_GID; if (keyGetMode(key1)!= keyGetMode(key2)) ret|=KEY_MODE; if (nsize1 != nsize2) ret|=KEY_NAME; if (strcmp(name1, name2)) ret|=KEY_NAME; if (strcmp(comment1, comment2)) ret|=KEY_COMMENT; if (strcmp(owner1, owner2)) ret|=KEY_OWNER; if (size1 != size2) ret|=KEY_VALUE; if (memcmp(value1, value2, size1)) ret|=KEY_VALUE; return ret; }
void test_keyset() { KeySet *ks; Key *cur; int counter; printf("Testing KeySet from xml\n"); ks = ksNew(0, KS_END); exit_if_fail( ksFromXMLfile(ks, srcdir_file("xmltool/keyset.xml")) == 0, "ksFromXMLfile(key.xml) failed."); counter = 0; ksRewind(ks); while ( (cur = ksNext(ks)) ) { counter ++; /* Make tests ... */ // printf ("counter: %d - %s\n", counter, keyName(cur)); switch (counter) { // <key type="43" basename="0-27042916" value="0 216905227"><comment>2551516588474823843</comment></key> case 1: succeed_if (strcmp (keyName(cur),"user/tests/filesys/0-27042916") == 0,"name of first key not correct"); succeed_if (strcmp (keyValue(cur),"0 216905227") == 0,"value of first key not correct"); succeed_if (strcmp (keyComment(cur),"2551516588474823843") == 0,"comment of first key not correct"); break; // <key type="253" basename="1-2449524622" value="1 1679328197"><comment>3246436893195629244</comment></key> case 2: succeed_if (strcmp (keyName(cur),"user/tests/filesys/1-2449524622") == 0,"name of 2. key not correct"); succeed_if (strcmp (keyValue(cur),"1 1679328197") == 0,"value of 2. key not correct"); succeed_if (strcmp (keyComment(cur),"3246436893195629244") == 0,"comment of 2. key not correct"); break; // <key type="string" basename="dir-1-0"> case 3: succeed_if (strcmp (keyName(cur),"user/tests/filesys/dir-1-0") == 0,"name of 3. key not correct"); break; // <key type="114" basename="0-294164813" value="0 216245011"><comment>18454108762891828026</comment></key> case 4: succeed_if (strcmp (keyName(cur),"user/tests/filesys/dir-1-0/0-294164813") == 0,"name of 4. key not correct"); succeed_if (strcmp (keyValue(cur),"0 216245011") == 0,"value of 4. key not correct"); succeed_if (strcmp (keyComment(cur),"18454108762891828026") == 0,"comment of 4. key not correct"); break; // <key type="135" basename="1-1479930365" value="1 2732423037"><comment>24597295372375238</comment></key> case 5: succeed_if (strcmp (keyName(cur),"user/tests/filesys/dir-1-0/1-1479930365") == 0,"name of 4. key not correct"); succeed_if (strcmp (keyValue(cur),"1 2732423037") == 0,"value of 4. key not correct"); succeed_if (strcmp (keyComment(cur),"24597295372375238") == 0,"comment of 4. key not correct"); break; // <key type="string" basename="dir-2-0"> case 6: succeed_if (strcmp (keyName(cur),"user/tests/filesys/dir-1-0/dir-2-0") == 0,"name of 3. key not correct"); break; // <key type="144" basename="0-215571059" value="0 264857705"><comment>2188631490667217086</comment></key> case 7: succeed_if (strcmp (keyName(cur),"user/tests/filesys/dir-1-0/dir-2-0/0-215571059") == 0,"name of 4. key not correct"); succeed_if (strcmp (keyValue(cur),"0 264857705") == 0,"value of 4. key not correct"); succeed_if (strcmp (keyComment(cur),"2188631490667217086") == 0,"comment of 4. key not correct"); break; } } ksDel(ks); }
void test_comment() { Key *key; char ret[10]; succeed_if (key = keyNew(0), "could not create new key"); succeed_if (strcmp (keyComment(key), "") == 0, "Empty comment problem"); succeed_if (keyGetCommentSize(key) == 1, "Empty comment size problem"); succeed_if (keyValue(keyGetMeta(key, "comment")) == 0, "No comment up to now"); succeed_if (keySetComment (key,0) == 1, "could not remove comment"); succeed_if (keyValue(keyGetMeta(key, "comment")) == 0, "There should be an no comment"); succeed_if (!strcmp (keyComment(key), ""), "Empty comment problem"); succeed_if (keyGetCommentSize(key) == 1, "Empty comment size problem"); succeed_if (keyGetComment(key, ret, 0) == -1, "Could not get empty comment"); succeed_if (keyGetComment(key, ret, 1) == 1, "Could not get empty comment"); succeed_if (ret[0] == 0, "keyGetComment did not return empty comment"); succeed_if (keySetComment (key,"") == 1, "could not remove comment"); succeed_if (keyValue(keyGetMeta(key, "comment")) == 0, "There should be an no comment"); succeed_if (!strcmp (keyComment(key), ""), "Empty comment problem"); succeed_if (keyGetCommentSize(key) == 1, "Empty comment size problem"); succeed_if (keyGetComment(key, ret, 0) == -1, "Could not get empty comment"); succeed_if (keyGetComment(key, ret, 1) == 1, "Could not get empty comment"); succeed_if (ret[0] == 0, "keyGetComment did not return empty comment"); succeed_if (keySetComment (key,"mycom") == sizeof("mycom"), "could not set comment"); succeed_if (!strcmp(keyValue(keyGetMeta(key, "comment")), "mycom"), "There should be my comment"); succeed_if (!strcmp (keyComment(key), "mycom"), "My comment problem"); succeed_if (keyGetCommentSize(key) == sizeof("mycom"), "My comment size problem"); succeed_if (keyGetComment(key, ret, 0) == -1, "Could not get my comment"); succeed_if (keyGetComment(key, ret, 1) == -1, "Could not get my comment"); succeed_if (keyGetComment(key, ret, sizeof("mycom")) == sizeof("mycom"), "Could not get my comment"); succeed_if (!strcmp (ret, "mycom"), "keyGetComment did not return my comment"); succeed_if (keyDel (key) == 0, "could not delete key"); }
void test_key () { KeySet * ks; Key * cur; int counter; printf ("Testing Key from xml\n"); ks = ksNew (0, KS_END); exit_if_fail (ksFromXMLfile (ks, srcdir_file ("xmltool/key.xml")) == 0, "ksFromXMLfile(key.xml) failed."); counter = 0; ksRewind (ks); while ((cur = ksNext (ks))) { counter++; /* Prepend key root */ // snprintf(buf, sizeof(buf), "%s/%s", root, keyName(cur)); // keySetName(cur, buf); /* Make tests ... */ // printf ("counter: %d - name: %s - value: %s\n", counter, (char*) keyName(cur), (char*)keyValue(cur)); switch (counter) { case 1: succeed_if (strcmp (keyName (cur), "user/tests/filesys/.HiddenBinaryKey") == 0, "wrong name"); succeed_if (strcmp (keyValue (cur), "BinaryValue") == 0, "value not correct"); succeed_if (strcmp (keyComment (cur), "Binary key with hidden name") == 0, "comment not correct"); succeed_if (keyIsInactive (cur) == 1, "key is inactive"); succeed_if (keyIsBinary (cur) == 1, "key is not binary"); succeed_if (keyGetMode (cur) == 0440, "could not get mode"); break; case 2: succeed_if (strcmp (keyName (cur), "user/tests/filesys/.HiddenDirectoryKey") == 0, "wrong name"); succeed_if (strcmp (keyValue (cur), "DirectoryValue") == 0, "value not correct"); succeed_if (strcmp (keyComment (cur), "Directory key with hidden name") == 0, "comment not correct"); succeed_if (keyIsInactive (cur) == 1, "key is inactive"); succeed_if (keyIsString (cur) == 1, "key is not string"); break; case 3: succeed_if (strcmp (keyName (cur), "user/tests/filesys/.HiddenStringKey") == 0, "wrong name"); succeed_if (strcmp (keyValue (cur), "StringValue") == 0, "value not correct"); succeed_if (strcmp (keyComment (cur), "String key with hidden name") == 0, "comment not correct"); succeed_if (keyIsInactive (cur) == 1, "key is inactive"); succeed_if (keyIsString (cur) == 1, "key is not string"); succeed_if (keyGetUID (cur) == 0, "could not get uid value"); succeed_if (keyGetGID (cur) == 20, "could not get gid value"); break; case 4: succeed_if (strcmp (keyName (cur), "user/tests/filesys/PerfectBinaryKey") == 0, "wrong name"); succeed_if (strcmp (keyValue (cur), "BinaryValue") == 0, "value not correct"); succeed_if (strcmp (keyComment (cur), "Binary key with standard name") == 0, "comment not correct"); succeed_if (keyIsInactive (cur) == 0, "key is active"); succeed_if (keyIsBinary (cur) == 1, "key is not binary"); succeed_if (keyGetGID (cur) == 40, "could not get gid value"); break; case 5: succeed_if (strcmp (keyName (cur), "user/tests/filesys/PerfectDirectoryKey") == 0, "wrong name"); succeed_if (strcmp (keyValue (cur), "DirectoryValue") == 0, "value not correct"); succeed_if (strcmp (keyComment (cur), "Directory key with standard name") == 0, "comment not correct"); succeed_if (keyIsInactive (cur) == 0, "key is active"); succeed_if (keyIsString (cur) == 1, "key is not string"); break; case 6: succeed_if (strcmp (keyName (cur), "user/tests/filesys/PerfectStringKey") == 0, "wrong name"); succeed_if (strcmp (keyValue (cur), "StringValue") == 0, "value not correct"); succeed_if (strcmp (keyComment (cur), "String key with\nstandard name") == 0, "comment not correct"); succeed_if (keyIsInactive (cur) == 0, "key is active"); succeed_if (keyIsString (cur) == 1, "key is not string"); succeed_if (keyGetUID (cur) == 20, "could not get uid value"); break; case 7: succeed_if (strcmp (keyName (cur), "user/tests/filesys/Ug.ly:Bin@a€ry Key") == 0, "wrong name"); succeed_if (keyValue (cur) == 0, "value not correct"); succeed_if (strcmp (keyComment (cur), "Binary key with ugly name") == 0, "comment not correct"); succeed_if (keyIsInactive (cur) == 0, "key is active"); succeed_if (keyIsBinary (cur) == 1, "key is not binary"); succeed_if (keyGetMode (cur) == 230, "could not get mode"); // <key type="binary" basename="Ug.ly:Bin@a€ry Key"><comment>Binary key with ugly name</comment></key> break; case 8: succeed_if (strcmp (keyName (cur), "user/tests/filesys/Ug.ly:Dir@ect€ory Key") == 0, "wrong name"); succeed_if (strcmp (keyValue (cur), "") == 0, "value not correct"); succeed_if (strcmp (keyComment (cur), "Directory with ugly name") == 0, "comment not correct"); succeed_if (keyIsInactive (cur) == 0, "key is active"); succeed_if (keyIsString (cur) == 1, "key is not string"); // <key type="directory" basename="Ug.ly:Dir@ect€ory Key"><comment>Directory with ugly name</comment></key> break; case 9: succeed_if (strcmp (keyName (cur), "user/tests/filesys/Ug.ly:St@ri€n.g Key") == 0, "wrong name"); succeed_if (strcmp (keyValue (cur), "With a string value") == 0, "value not correct"); succeed_if (strcmp (keyComment (cur), "string key with ugly name") == 0, "comment not correct"); succeed_if (keyIsInactive (cur) == 0, "key is active"); succeed_if (keyIsString (cur) == 1, "key is not string"); // <key type="string" basename="Ug.ly:St@ri€n.g Key" value="With a string value"><comment>string key with ugly // name</comment></key> break; } } ksDel (ks); }
/** * Same as keyToStream() but tries to strip @p parentSize bytes from * @p key name if it matches @p parent . * * Taking the example from keyToStream(), if @p parent is * @c "system/sw/xorg", the generated string is of the form: * @verbatim <key basename="Monitor/Monitor0/Name" type="string" uid="root" gid="root" mode="0600"> <value>Samsung TFT panel</value> <comment>My monitor</comment> </key>@endverbatim * * It usefull to produce more human readable XML output of a key when * it is being represented in a context that defines the parent key name. * For example: * * @verbatim <keyset parent="user/sw"> <key basename="kdbedit"..../> <key basename="phototools"..../> <key basename="myapp"..../> </keyset>@endverbatim * * In the bove example, each @p @<key@> entry was generated by a call to * keyToStreamBasename() having @c "user/sw" as @p parent . * * This method is used when ksToStream() is called with * KDBOption::KDB_O_HIER option. * * @param key the key object to work with * @param stream the FILE where to send the stream * @param parentSize the maximum size of @p parent that will be used. * If 0, the entire @p parent will be used. * @param parent the string (or part of it, defined by @p parentSize ) that * will be used to strip from the key name. * @param options Some #option_t ORed: * - @p option_t::KDB_O_NUMBERS \n * Do not convert UID and GID into user and group names * - @p option_t::KDB_O_CONDENSED \n * Less human readable, more condensed output * - @p option_t::KDB_O_FULLNAME \n * The @p user keys are exported with their full names (including * user domains) * * @return number of bytes written to output */ ssize_t keyToStreamBasename(const Key *key, FILE *stream, const char *parent, const size_t parentSize, option_t options) { ssize_t written=0; char buffer[KDB_MAX_PATH_LENGTH]; /* Write key name */ if (parent) { /* some logic to see if we should print only the relative basename */ int found; size_t skip=parentSize ? parentSize : elektraStrLen(parent)-1; found=memcmp(parent,key->key,skip); if (found == 0) { while (*(key->key+skip) == KDB_PATH_SEPARATOR) ++skip; if (*(key->key+skip) != 0) /* we don't want a null basename */ written+=fprintf(stream,"<key basename=\"%s\"", key->key+skip); } } if (written == 0) { /* no "<key basename=..." was written so far */ if (options & KDB_O_FULLNAME) { keyGetFullName(key,buffer,sizeof(buffer)); written+=fprintf(stream,"<key name=\"%s\"", buffer); } else written+=fprintf(stream,"<key name=\"%s\"", key->key); } /* Key type TODO: xml schema does not output type if (options & KDB_O_NUMBERS) { written+=fprintf(stream," type=\"%d\"", key->type); } else { buffer[0]=0; if (key->type & KEY_TYPE_DIR) written+=fprintf(stream, " isdir=\"yes\""); if (key->type & KEY_TYPE_REMOVE) written+=fprintf(stream, " isremove=\"yes\""); if (key->type & KEY_TYPE_BINARY) written+=fprintf(stream, " isbinary=\"yes\""); } */ if (keyGetUID (key) != (uid_t)-1) written+=fprintf(stream," uid=\"%d\"", (int)keyGetUID (key)); if (keyGetGID (key) != (gid_t)-1) written+=fprintf(stream," gid=\"%d\"", (int)keyGetGID (key)); if (keyGetMode(key) != KDB_FILE_MODE) { written+=fprintf(stream," mode=\"0%o\"", keyGetMode(key)); } if (!key->data.v && !keyComment(key)) { /* no data AND no comment */ written+=fprintf(stream,"/>"); if (!(options & KDB_O_CONDENSED)) written+=fprintf(stream,"\n\n"); return written; /* end of <key/> */ } else { if (key->data.v) { if ((key->dataSize <= 16) && keyIsString (key) && /*TODO: is this for string?*/ !strchr(key->data.c,'\n')) { /* we'll use a "value" attribute instead of a <value> node, for readability, so the cut size will be 16, which is the maximum size of an IPv4 address */ if (options & KDB_O_CONDENSED) written+=fprintf(stream," "); else written+=fprintf(stream,"\n\t"); written+=fprintf(stream,"value=\"%s\"",key->data.c); if (keyComment(key)) written+=fprintf(stream,">\n"); else { written+=fprintf(stream,"/>"); if (!(options & KDB_O_CONDENSED)) written+=fprintf(stream,"\n"); return written; } } else { /* value is bigger than 16 bytes: deserves own <value> */ written+=fprintf(stream,">"); if (!(options & KDB_O_CONDENSED)) written+=fprintf(stream,"\n\n "); written+=fprintf(stream,"<value>"); if (keyIsString(key)) { /*TODO: is this for string?*/ written+=fprintf(stream,"<![CDATA["); fflush(stream); /* must chop ending \\0 */ written+=fwrite(key->data.v,sizeof(char),key->dataSize-1,stream); written+=fprintf(stream,"]]>"); } else { /* TODO Binary values char *encoded=elektraMalloc(3*key->dataSize); size_t encodedSize; written+=fprintf(stream,"\n"); encodedSize=kdbbEncode(key->data.c,key->dataSize,encoded); fflush(stream); written+=fwrite(encoded,sizeof(char),encodedSize,stream); elektraFree (encoded); written+=fprintf(stream,"\n"); */ } /* fflush(stream); */ written+=fprintf(stream,"</value>"); } } else { /* we have no data */ if (keyComment(key)) { written+=fprintf(stream,">"); if (!(options & KDB_O_CONDENSED)) written+=fprintf(stream,"\n"); } else { written+=fprintf(stream,"/>"); if (!(options & KDB_O_CONDENSED)) written+=fprintf(stream,"\n\n"); return written; } } } if (!(options & KDB_O_CONDENSED)) { written+=fprintf(stream,"\n"); if (keyComment(key)) written+=fprintf(stream," "); } if (keyComment(key)) { written+=fprintf(stream,"<comment><![CDATA[%s]]></comment>", keyComment(key)); if (!(options & KDB_O_CONDENSED)) written+=fprintf(stream,"\n"); } written+=fprintf(stream,"</key>"); if (!(options & KDB_O_CONDENSED)) written+=fprintf(stream,"\n\n"); return written; }