Main Page | Modules | Data Structures | File List | Data Fields

keyset.c

00001 /***************************************************************************
00002                           keyset.c  -  Methods for KeySet manipulation
00003                              -------------------
00004     begin                : Sun Oct 02 2005
00005     copyright            : (C) 2005 by Avi Alkalay
00006     email                : avi@unix.sh
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the BSD License (revised).                      *
00013  *                                                                         *
00014  ***************************************************************************/
00015 
00016 /* Subversion stuff
00017 
00018 $Id: keyset.c 593 2006-02-14 15:25:25Z mraab $
00019 
00020 */
00021 
00022 #ifdef HAVE_CONFIG_H
00023 #include "config.h"
00024 #endif
00025 
00026 #include <stdio.h>
00027 #include <stdlib.h>
00028 #include <errno.h>
00029 #include <string.h>
00030 #ifdef HAVE_LANGINFO_H
00031 #include <langinfo.h>
00032 #endif
00033 
00034 #include "kdb.h"
00035 #include "kdbprivate.h"
00036 
00070 KeySet *ksNew() {
00071     KeySet *new=(KeySet *)malloc(sizeof(KeySet));
00072     ksInit(new);
00073     return new;
00074 }
00075 
00076 
00077 
00089 int ksDel(KeySet *ks) {
00090     int rc;
00091     
00092     rc=ksClose(ks);
00093     free(ks);
00094     
00095     return rc;
00096 }
00097 
00098 
00099 
00103 ssize_t ksGetSize(KeySet *ks) {
00104     return ks->size;
00105 }
00106 
00107 
00108 
00109 
00110 
00111 
00112 
00113 
00114 /******************************************* 
00115  *           KeySet walking methods        *
00116  *******************************************/
00117 
00118 
00127 int ksRewind(KeySet *ks) {
00128     ks->cursor=0;
00129     return 0;
00130 }
00131 
00132 
00133 
00147 Key *ksNext(KeySet *ks) {
00148     if (ks->cursor) ks->cursor=ks->cursor->next;
00149     else ks->cursor=ks->start;
00150 
00151     return ks->cursor;
00152 }
00153 
00154 
00155 
00163 Key *ksCurrent(const KeySet *ks) {
00164     return ks->cursor;
00165 }
00166 
00167 
00168 
00176 Key *ksHead(KeySet *ks) {
00177     return ks->start;
00178 }
00179 
00180 
00181 
00188 Key *ksTail(KeySet *ks) {
00189     return ks->end;
00190 }
00191 
00192 
00193 
00194 
00195 
00196 
00197 
00198 
00199 
00200 
00201 
00202 /******************************************* 
00203  *    Looking up Keys inside KeySets       *
00204  *******************************************/
00205 
00206 
00247 Key *ksLookupByName(KeySet *ks, const char *name, unsigned long options) {
00248     Key *init=0;
00249     Key *current=0;
00250     size_t nameSize;
00251     size_t currentNameSize;
00252     char * keyname;
00253 
00254     nameSize=strblen(name);
00255 
00256     init=ks->cursor;
00257 
00258     while ((current=ksNext(ks))) {
00259         if (current->key == name) return current; /* for NULLs */
00260 
00261 
00266         if (name [0] == '/') {  /*Cascading search*/
00267             keyname = strchr(current->key, '/');
00268         } else {
00269             keyname = keyStealName (current);
00270         }
00271 
00272 #ifdef VERBOSE
00273         fprintf (stderr, "Compare %s with %s\n", keyname, name);
00274 #endif
00275 
00276         if ((current->key && name)) {
00277             if ((options & KDB_O_NOCASE) &&
00278                 !strcasecmp(keyname,name)) return current;
00279             else if (!strcmp(keyname,name)) return current;
00280         }
00281     }
00282 
00283     /* Reached end of KeySet. Put cursor in initial position. */
00284     ks->cursor=init;
00285 
00286     return 0;
00287 }
00288 
00289 
00290 
00378 uint32_t ksLookupRE(KeySet *ks, uint32_t where,
00379         const regex_t *regexp, unsigned long options) {
00380 #ifdef HAVE_REGEX_H
00381     regmatch_t offsets;
00382     uint32_t match=0;
00383     Key *init, *walker;
00384     char *parentName=0;
00385     size_t walkerNameSize=0,parentNameSize=0;
00386     
00387     init=ks->cursor;
00388     if (!init)
00389         /* I don't have a parent to match. Ignore this option. */
00390         options &= options & ~KDB_O_NOSPANPARENT;
00391     
00392     if (options & KDB_O_NOSPANPARENT) {
00393         /* User wants siblings. Prepare context. */
00394         parentNameSize=keyGetParentNameSize(init);
00395         parentName=(char *)malloc(parentNameSize);
00396         keyGetParentName(init,parentName,parentNameSize);
00397     }
00398     
00399     while ((walker=ksNext(ks))) {
00400         walkerNameSize=keyGetNameSize(walker);
00401         
00402         if (options & KDB_O_NOSPANPARENT) {
00403             /* User wants siblings. Check if walker is a sibling of init. */
00404             if (walkerNameSize < parentNameSize)
00405                 /* we're out of out scope, so abort */
00406                 break;
00407             
00408             if (memcmp(parentName,walker->key,parentNameSize))
00409                 /* walker has a different parent, so abort */
00410                 break;
00411         }
00412     
00413         if ((where & KEY_SWITCH_NAME) && walker->key)
00414             if (!regexec(regexp,walker->key,1,&offsets,0))
00415                 match |= KEY_SWITCH_NAME;
00416         
00417         if ((where & KEY_SWITCH_VALUE) && walker->data &&
00418             !(KEY_TYPE_BINARY <= walker->type && walker->type < KEY_TYPE_STRING))
00419             if (!regexec(regexp,(char *)walker->data,1,&offsets,0))
00420                 match |= KEY_SWITCH_VALUE;
00421         
00422         if ((where & KEY_SWITCH_OWNER) && keyIsUser(walker))
00423             if (!regexec(regexp,walker->userDomain,1,&offsets,0))
00424                 match |= KEY_SWITCH_OWNER;
00425         
00426         if ((where & KEY_SWITCH_COMMENT) && walker->comment)
00427             if (!regexec(regexp,walker->comment,1,&offsets,0))
00428                 match |= KEY_SWITCH_OWNER;
00429         
00430         if (match) return match;
00431     }
00432     
00433     if (parentName) free(parentName);
00434     ks->cursor=init;
00435 #endif  
00436     return 0;
00437 }
00438 
00439 
00470 Key *ksLookupByValue(KeySet *ks, const char *value, unsigned long options) {
00471     Key *init=0;
00472     Key *current=0;
00473     size_t size=0;
00474     
00475     size=strblen(value);
00476     init=ks->cursor;
00477     
00478     while ((current=ksNext(ks))) {
00479         if (current->data == value) return current;
00480         
00481         if (size != current->dataSize) continue;
00482         
00483         if (KEY_TYPE_BINARY<= current->type && current->type < KEY_TYPE_STRING)
00484             continue;
00485         
00486         if ((current->data && value)) {
00487             if ((options & KDB_O_NOCASE) && 
00488                 !strcasecmp(current->data,value)) return current;
00489             else if (!strcmp(current->data,value)) return current;
00490         }
00491     }
00492     
00493     /* reached end of KeySet */
00494     ks->cursor=init;
00495     
00496     return 0;
00497 }
00498 
00499 
00500 
00519 Key *ksLookupByBinaryValue(KeySet *ks, void *value, size_t size,
00520         unsigned long options) {
00521     Key *init=0;
00522     Key *current=0;
00523     
00524     init=ks->cursor;
00525     
00526     while ((current=ksNext(ks))) {
00527         if (current->data == value) return current;
00528         
00529         if (size != current->dataSize) continue;
00530         
00531         if ((current->data && value) && 
00532                 !memcmp(current->data,value,size)) return current;
00533     }
00534     
00535     /* reached end of KeySet, so reset cursor */
00536     ks->cursor=init;
00537     
00538     return 0;
00539 }
00540 
00541 
00542 
00543 
00544 
00545 
00546 
00547 /******************************************* 
00548  *           Filling up KeySets            *
00549  *******************************************/
00550 
00551  
00566 ssize_t ksInsert(KeySet *ks, Key *toInsert) {
00567     toInsert->next=ks->start;
00568     ks->start=toInsert;
00569     if (!ks->end) ks->end=toInsert;
00570     return ++ks->size;
00571 }
00572 
00573 
00586 Key *ksPop(KeySet *ks) {
00587     Key *key=0;
00588     
00589     if (ks->start) {
00590         key=ks->start;
00591         ks->start=key->next;
00592         if (ks->end == key) ks->end=0;
00593         ks->size--;
00594         if (ks->cursor == key) ks->cursor=0;
00595     }
00596     
00597     return key;
00598 }
00599 
00600 
00613 Key *ksPopLast(KeySet *ks) {
00614     Key *key=0;
00615     Key *prev=0;
00616     
00617     /* When ks is empty: */
00618     if (ks->end == 0) return 0;
00619     
00620     /* When ks has only one member: */
00621     if (ks->start == ks->end) {
00622         key=ks->end;
00623         ks->cursor=ks->start=ks->end=0;
00624         ks->size=0;
00625         
00626         return key;
00627     }
00628     
00629     prev=ks->start;
00630     while (prev->next!=ks->end) prev=prev->next;
00631     
00632     key=ks->end;
00633     prev->next=0;
00634     ks->end=prev;
00635     ks->size--;
00636     if (ks->cursor == key) ks->cursor=0;
00637     
00638     return key;
00639 }
00640 
00641 
00653 ssize_t ksInsertKeys(KeySet *ks, KeySet *toInsert) {
00654     if (toInsert->size) {
00655         toInsert->end->next=ks->start;
00656         ks->start=toInsert->start;
00657 
00658         ks->size+=toInsert->size;
00659 
00660         /* Invalidate the old KeySet */
00661         toInsert->start=toInsert->end=toInsert->cursor=0;
00662         toInsert->size=0;
00663     }
00664     return ks->size;
00665 }
00666 
00667 
00668 
00683 ssize_t ksAppend(KeySet *ks, Key *toAppend) {
00684     toAppend->next=0;
00685     if (ks->end) ks->end->next=toAppend;
00686     if (!ks->start) ks->start=toAppend;
00687     ks->end=toAppend;
00688     return ++ks->size;
00689 }
00690 
00691 
00692 
00705 ssize_t ksAppendKeys(KeySet *ks, KeySet *toAppend) {
00706     if (toAppend->size) {
00707         if (ks->end) {
00708             ks->end->next=toAppend->start;
00709             ks->end=toAppend->end;
00710         } else {
00711             ks->end=toAppend->end;
00712             ks->start=toAppend->start;
00713         }
00714 
00715         ks->size+=toAppend->size;
00716         
00717         /* Invalidate the old KeySet */
00718         toAppend->start=toAppend->end=toAppend->cursor=0;
00719         toAppend->size=0;
00720     }
00721     return ks->size;
00722 }
00723 
00724 
00725 
00726 
00727 
00728 
00729 
00730 
00731 
00732 
00733 /******************************************* 
00734  *    Other operations                     *
00735  *******************************************/
00736 
00737 
00798 int ksCompare(KeySet *ks1, KeySet *ks2, KeySet *removed) {
00799     int flagRemoved=1;
00800     Key *ks1Cursor=0;
00801     Key *ks2Cursor=0;
00802 
00803     Key *ks1PrevCursor=0;
00804 
00805     ks1Cursor=ks1->start;
00806     while (ks1Cursor) {
00807         Key *ks2PrevCursor=0;
00808         flagRemoved=1;
00809         
00810         for (ks2Cursor=ks2->start; ks2Cursor; ks2Cursor=ks2Cursor->next) {
00811             uint32_t flags=keyCompare(ks1Cursor,ks2Cursor);
00812             
00813             if (!(flags & (KEY_SWITCH_NAME | KEY_SWITCH_DOMAIN))) {
00814                 /* Comparing fullname-equal keys */
00815                 flagRemoved=0; /* key was not removed */
00816                     
00817                 /* First remove from ks2 */
00818                 if (ks2PrevCursor) ks2PrevCursor->next=ks2Cursor->next;
00819                 else ks2->start=ks2Cursor->next;
00820                 if (ks2->end==ks2Cursor) ks2->end=ks2PrevCursor;
00821                 ks2->size--;
00822                     
00823                 if (flags) {
00824                     /* keys are different. Transfer to ks1. */
00825                     
00826                     /* Put in ks1 */
00827                     if (ks1PrevCursor) ks1PrevCursor->next=ks2Cursor;
00828                     else ks1->start=ks2Cursor;
00829                     if (ks1->end==ks1Cursor) ks1->end=ks2Cursor;
00830                     ks2Cursor->next=ks1Cursor->next;
00831                     
00832                     /* delete old version */
00833                     keyDel(ks1Cursor);
00834                     
00835                     /* Reset pointers */
00836                     ks1Cursor=ks2Cursor;
00837                 } else {
00838                     /* Keys are identical. Delete ks2's key. */
00839 
00840                     /* Delete ks2Cusrsor */
00841                     keyDel(ks2Cursor);
00842                 }
00843                 /* Don't need to walk through ks2 anymore */
00844                 break;
00845             }
00846             ks2PrevCursor=ks2Cursor;
00847             
00848         } /* ks2 iteration */
00849         
00850         if (flagRemoved) {
00851             /* This ks1 key was not found in ks2 */
00852             /* Transfer it from ks1 to removed */
00853             
00854             /* Remove from ks1 */
00855             if (ks1PrevCursor) ks1PrevCursor->next=ks1Cursor->next;
00856             else ks1->start=ks1Cursor->next;
00857             if (ks1->end==ks1Cursor) ks1->end=ks1PrevCursor;
00858             ks1->size--;
00859 
00860             /* Append to removed */
00861             ksAppend(removed,ks1Cursor);
00862             
00863             /* Reset pointers */
00864             if (ks1PrevCursor) ks1Cursor=ks1PrevCursor->next;
00865             else ks1Cursor=ks1->start;
00866         } else {
00867             ks1PrevCursor=ks1Cursor;
00868             ks1Cursor=ks1Cursor->next;
00869         }
00870     } /* ks1 iteration */
00871     
00872     /* Now transfer all remaining ks2 keys to ks1 */
00873     ksAppendKeys(ks1,ks2);
00874     
00875     return 0;
00876 }
00877 
00878 
00879 
00880 
00942 ssize_t ksToStream(const KeySet *ks, FILE* stream, unsigned long options) {
00943     size_t written=0;
00944     Key *key=0;
00945     char *codeset;
00946 
00947     /* If nl_langinfo or the CODESET info isn't available we default to UTF-8 
00948      * This might not be a very good default, but I'm not sure how else to do it*/
00949 #if defined(HAVE_NL_LANGINFO) && defined(CODESET)
00950     codeset = nl_langinfo(CODESET);
00951 #else
00952     codeset = "UTF-8";
00953 #endif
00954     if (options & KDB_O_XMLHEADERS) {
00955         written+=fprintf(stream,"<?xml version=\"1.0\" encoding=\"%s\"?>\n",
00956             codeset);
00957         written+=fprintf(stream,
00958             "\n\n<!-- Generated by Elektra API. Total of %d keys. -->\n\n\n\n",ks->size);
00959         
00960         written+=fprintf(stream,"<keyset xmlns=\"http://www.libelektra.org\"\n\
00961         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\
00962         xsi:schemaLocation=\"http://www.libelektra.org elektra.xsd\"");
00963         
00964         /* written+=fprintf(stream,
00965             "<!DOCTYPE keyset PUBLIC \"-//Avi Alkalay//DTD Elektra 0.1.0//EN\" \"http://elektra.sf.net/dtd/elektra.dtd\">\n\n\n"); */
00966     } else written+=fprintf(stream,"<keyset");
00967 
00968     if (options & KDB_O_HIER) {
00969         Key *smalest=0;
00970         size_t ssmalest=0;
00971 
00972         for (key=ks->start; key; key=key->next) {
00973             if (smalest) {
00974                 size_t size=strblen(key->key);
00975                 if (size<ssmalest) {
00976                     smalest=key;
00977                     ssmalest=size;
00978                 }
00979             } else {
00980                 smalest=key;
00981                 ssmalest=strblen(smalest->key);
00982             }
00983         }
00984 
00985         if (keyIsUser(smalest) && (options & KDB_O_FULLNAME)) {
00986             char buffer[800];
00987             keyGetFullName(smalest,buffer,sizeof(buffer));
00988             written+=fprintf(stream,"\n\n        parent=\"%s\"",buffer);
00989         } else
00990             written+=fprintf(stream,"\n\n        parent=\"%s\"",smalest->key);
00991 
00992         written+=fprintf(stream,">\n\n\n");
00993 
00994         for (key=ks->start; key; key=key->next)
00995             written+=keyToStreamBasename(key,stream,smalest->key,0,options);
00996     } else { /* No KDB_O_HIER*/
00997         written+=fprintf(stream,">\n\n\n");
00998         for (key=ks->start; key; key=key->next)
00999             written+=keyToStream(key,stream,options);
01000     }
01001     
01002     written+=fprintf(stream,"</keyset>\n");
01003     return written;
01004 }
01005 
01006 
01007 
01008 /* Used as a callback by the qsort() function */
01009 int keyCompareByName(const void *p1, const void *p2) {
01010     Key *key1=*(Key **)p1;
01011     Key *key2=*(Key **)p2;
01012 
01013     return strcmp(key1->key, key2->key);
01014 }
01015 
01016 
01022 void ksSort(KeySet *ks) {
01023     Key **keys = NULL;
01024     Key *cursor;
01025     size_t c=0;
01026 
01027     if (ks->size) {
01028         keys = (Key **)calloc(ks->size, sizeof(Key *));
01029 
01030         for (cursor=ks->start; cursor; cursor=cursor->next, c++)
01031             keys[c]=cursor;
01032 
01033         qsort(keys,ks->size,sizeof(Key *),keyCompareByName);
01034 
01035         ks->start=cursor=keys[0];
01036         for (c=1; c<ks->size; c++) {
01037             cursor->next=keys[c];
01038             cursor=cursor->next;
01039         }
01040         cursor->next=0;
01041         ks->end=cursor;
01042         free(keys);
01043     }
01044 }
01045 
01046 
01047 
01048 
01049 
01050 
01063 int ksInit(KeySet *ks) {
01064     ks->start=ks->end=ks->cursor=0;
01065     ks->size=0;
01066     
01067     return 0;
01068 }
01069 
01070 
01082 int ksClose(KeySet *ks) {
01083     if (ks->size) {
01084         while (ks->size) {
01085             Key *destroyer=ks->start;
01086             ks->start=destroyer->next;
01087             keyDel(destroyer);
01088             --ks->size;
01089         }
01090     }
01091     ks->cursor=ks->end=ks->start;
01092     return 0;
01093 }
01094 
01095 
01096 
01097 
01098 
01099 

Generated on Sun Feb 19 10:05:36 2006 for Elektra Project by  doxygen 1.3.9.1