LCOV - code coverage report
Current view: directory - modules/libpref/src - prefapi.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 392 318 81.1 %
Date: 2012-06-02 Functions: 36 31 86.1 %

       1                 : /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is mozilla.org code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Netscape Communications Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *
      24                 :  * Alternatively, the contents of this file may be used under the terms of
      25                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      26                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      27                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      28                 :  * of those above. If you wish to allow use of your version of this file only
      29                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      30                 :  * use your version of this file under the terms of the MPL, indicate your
      31                 :  * decision by deleting the provisions above and replace them with the notice
      32                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      33                 :  * the provisions above, a recipient may use your version of this file under
      34                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      35                 :  *
      36                 :  * ***** END LICENSE BLOCK ***** */
      37                 : 
      38                 : #include "prefapi.h"
      39                 : #include "prefapi_private_data.h"
      40                 : #include "PrefTuple.h"
      41                 : #include "prefread.h"
      42                 : #include "nsReadableUtils.h"
      43                 : #include "nsCRT.h"
      44                 : 
      45                 : #define PL_ARENA_CONST_ALIGN_MASK 3
      46                 : #include "plarena.h"
      47                 : 
      48                 : #ifdef XP_OS2
      49                 :   #include <sys/types.h>
      50                 : #endif
      51                 : #ifdef _WIN32
      52                 :   #include "windows.h"
      53                 : #endif /* _WIN32 */
      54                 : 
      55                 : #include "plstr.h"
      56                 : #include "pldhash.h"
      57                 : #include "plbase64.h"
      58                 : #include "prlog.h"
      59                 : #include "prmem.h"
      60                 : #include "prprf.h"
      61                 : #include "nsQuickSort.h"
      62                 : #include "nsString.h"
      63                 : #include "nsPrintfCString.h"
      64                 : #include "prlink.h"
      65                 : 
      66                 : #ifdef XP_OS2
      67                 : #define INCL_DOS
      68                 : #include <os2.h>
      69                 : #endif
      70                 : 
      71                 : static void
      72         2301301 : clearPrefEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
      73                 : {
      74         2301301 :     PrefHashEntry *pref = static_cast<PrefHashEntry *>(entry);
      75         2301301 :     if (pref->flags & PREF_STRING)
      76                 :     {
      77          774634 :         if (pref->defaultPref.stringVal)
      78          771075 :             PL_strfree(pref->defaultPref.stringVal);
      79          774634 :         if (pref->userPref.stringVal)
      80            5588 :             PL_strfree(pref->userPref.stringVal);
      81                 :     }
      82                 :     // don't need to free this as it's allocated in memory owned by
      83                 :     // gPrefNameArena
      84         2301301 :     pref->key = nsnull;
      85         2301301 :     memset(entry, 0, table->entrySize);
      86         2301301 : }
      87                 : 
      88                 : static bool
      89          322051 : matchPrefEntry(PLDHashTable*, const PLDHashEntryHdr* entry,
      90                 :                const void* key)
      91                 : {
      92                 :     const PrefHashEntry *prefEntry =
      93          322051 :         static_cast<const PrefHashEntry*>(entry);
      94                 : 
      95          322051 :     if (prefEntry->key == key) return true;
      96                 : 
      97          322051 :     if (!prefEntry->key || !key) return false;
      98                 : 
      99          322051 :     const char *otherKey = reinterpret_cast<const char*>(key);
     100          322051 :     return (strcmp(prefEntry->key, otherKey) == 0);
     101                 : }
     102                 : 
     103                 : PLDHashTable        gHashTable = { nsnull };
     104                 : static PLArenaPool  gPrefNameArena;
     105                 : bool                gDirty = false;
     106                 : 
     107                 : static struct CallbackNode* gCallbacks = NULL;
     108                 : static bool         gIsAnyPrefLocked = false;
     109                 : // These are only used during the call to pref_DoCallback
     110                 : static bool         gCallbacksInProgress = false;
     111                 : static bool         gShouldCleanupDeadNodes = false;
     112                 : 
     113                 : 
     114                 : static PLDHashTableOps     pref_HashTableOps = {
     115                 :     PL_DHashAllocTable,
     116                 :     PL_DHashFreeTable,
     117                 :     PL_DHashStringKey,
     118                 :     matchPrefEntry,
     119                 :     PL_DHashMoveEntryStub,
     120                 :     clearPrefEntry,
     121                 :     PL_DHashFinalizeStub,
     122                 :     nsnull,
     123                 : };
     124                 : 
     125                 : // PR_ALIGN_OF_WORD is only defined on some platforms.  ALIGN_OF_WORD has
     126                 : // already been defined to PR_ALIGN_OF_WORD everywhere
     127                 : #ifndef PR_ALIGN_OF_WORD
     128                 : #define PR_ALIGN_OF_WORD PR_ALIGN_OF_POINTER
     129                 : #endif
     130                 : 
     131                 : // making PrefName arena 8k for nice allocation
     132                 : #define PREFNAME_ARENA_SIZE 8192
     133                 : 
     134                 : #define WORD_ALIGN_MASK (PR_ALIGN_OF_WORD - 1)
     135                 : 
     136                 : // sanity checking
     137                 : #if (PR_ALIGN_OF_WORD & WORD_ALIGN_MASK) != 0
     138                 : #error "PR_ALIGN_OF_WORD must be a power of 2!"
     139                 : #endif
     140                 : 
     141                 : // equivalent to strdup() - does no error checking,
     142                 : // we're assuming we're only called with a valid pointer
     143         2301301 : static char *ArenaStrDup(const char* str, PLArenaPool* aArena)
     144                 : {
     145                 :     void* mem;
     146         2301301 :     PRUint32 len = strlen(str);
     147         2301301 :     PL_ARENA_ALLOCATE(mem, aArena, len+1);
     148         2301301 :     if (mem)
     149         2301301 :         memcpy(mem, str, len+1);
     150         2301301 :     return static_cast<char*>(mem);
     151                 : }
     152                 : 
     153                 : /*---------------------------------------------------------------------------*/
     154                 : 
     155                 : #define PREF_IS_LOCKED(pref)            ((pref)->flags & PREF_LOCKED)
     156                 : #define PREF_HAS_USER_VALUE(pref)       ((pref)->flags & PREF_USERSET)
     157                 : #define PREF_TYPE(pref)                 (PrefType)((pref)->flags & PREF_VALUETYPE_MASK)
     158                 : 
     159                 : static bool pref_ValueChanged(PrefValue oldValue, PrefValue newValue, PrefType type);
     160                 : 
     161                 : /* -- Privates */
     162                 : struct CallbackNode {
     163                 :     char*                   domain;
     164                 :     // If someone attempts to remove the node from the callback list while
     165                 :     // pref_DoCallback is running, |func| is set to nsnull. Such nodes will
     166                 :     // be removed at the end of pref_DoCallback.
     167                 :     PrefChangedFunc         func;
     168                 :     void*                   data;
     169                 :     struct CallbackNode*    next;
     170                 : };
     171                 : 
     172                 : /* -- Prototypes */
     173                 : static nsresult pref_DoCallback(const char* changed_pref);
     174                 : 
     175                 : 
     176                 : static nsresult pref_HashPref(const char *key, PrefValue value, PrefType type, bool defaultPref);
     177                 : 
     178                 : #define PREF_HASHTABLE_INITIAL_SIZE     2048
     179                 : 
     180            1420 : nsresult PREF_Init()
     181                 : {
     182            1420 :     if (!gHashTable.ops) {
     183            1420 :         if (!PL_DHashTableInit(&gHashTable, &pref_HashTableOps, nsnull,
     184                 :                                sizeof(PrefHashEntry),
     185            1420 :                                PREF_HASHTABLE_INITIAL_SIZE)) {
     186               0 :             gHashTable.ops = nsnull;
     187               0 :             return NS_ERROR_OUT_OF_MEMORY;
     188                 :         }
     189                 : 
     190                 :         PL_INIT_ARENA_POOL(&gPrefNameArena, "PrefNameArena",
     191            1420 :                            PREFNAME_ARENA_SIZE);
     192                 :     }
     193            1420 :     return NS_OK;
     194                 : }
     195                 : 
     196                 : /* Frees the callback list. */
     197            1419 : void PREF_Cleanup()
     198                 : {
     199            1419 :     NS_ASSERTION(!gCallbacksInProgress,
     200                 :         "PREF_Cleanup was called while gCallbacksInProgress is true!");
     201            1419 :     struct CallbackNode* node = gCallbacks;
     202                 :     struct CallbackNode* next_node;
     203                 : 
     204            2838 :     while (node)
     205                 :     {
     206               0 :         next_node = node->next;
     207               0 :         PL_strfree(node->domain);
     208               0 :         free(node);
     209               0 :         node = next_node;
     210                 :     }
     211            1419 :     gCallbacks = NULL;
     212                 : 
     213            1419 :     PREF_CleanupPrefs();
     214            1419 : }
     215                 : 
     216                 : /* Frees up all the objects except the callback list. */
     217            1420 : void PREF_CleanupPrefs()
     218                 : {
     219            1420 :     if (gHashTable.ops) {
     220            1420 :         PL_DHashTableFinish(&gHashTable);
     221            1420 :         gHashTable.ops = nsnull;
     222            1420 :         PL_FinishArenaPool(&gPrefNameArena);
     223                 :     }
     224            1420 : }
     225                 : 
     226                 : // note that this appends to aResult, and does not assign!
     227              20 : static void str_escape(const char * original, nsAFlatCString& aResult)
     228                 : {
     229                 :     /* JavaScript does not allow quotes, slashes, or line terminators inside
     230                 :      * strings so we must escape them. ECMAScript defines four line
     231                 :      * terminators, but we're only worrying about \r and \n here.  We currently
     232                 :      * feed our pref script to the JS interpreter as Latin-1 so  we won't
     233                 :      * encounter \u2028 (line separator) or \u2029 (paragraph separator).
     234                 :      *
     235                 :      * WARNING: There are hints that we may be moving to storing prefs
     236                 :      * as utf8. If we ever feed them to the JS compiler as UTF8 then
     237                 :      * we'll have to worry about the multibyte sequences that would be
     238                 :      * interpreted as \u2028 and \u2029
     239                 :      */
     240                 :     const char *p;
     241                 : 
     242              20 :     if (original == NULL)
     243               0 :         return;
     244                 : 
     245                 :     /* Paranoid worst case all slashes will free quickly */
     246             427 :     for  (p=original; *p; ++p)
     247                 :     {
     248             407 :         switch (*p)
     249                 :         {
     250                 :             case '\n':
     251               0 :                 aResult.Append("\\n");
     252               0 :                 break;
     253                 : 
     254                 :             case '\r':
     255               0 :                 aResult.Append("\\r");
     256               0 :                 break;
     257                 : 
     258                 :             case '\\':
     259               0 :                 aResult.Append("\\\\");
     260               0 :                 break;
     261                 : 
     262                 :             case '\"':
     263               0 :                 aResult.Append("\\\"");
     264               0 :                 break;
     265                 : 
     266                 :             default:
     267             407 :                 aResult.Append(*p);
     268             407 :                 break;
     269                 :         }
     270                 :     }
     271                 : }
     272                 : 
     273                 : /*
     274                 : ** External calls
     275                 : */
     276                 : nsresult
     277            9795 : PREF_SetCharPref(const char *pref_name, const char *value, bool set_default)
     278                 : {
     279                 :     PrefValue pref;
     280            9795 :     pref.stringVal = (char*) value;
     281                 : 
     282            9795 :     return pref_HashPref(pref_name, pref, PREF_STRING, set_default);
     283                 : }
     284                 : 
     285                 : nsresult
     286            5461 : PREF_SetIntPref(const char *pref_name, PRInt32 value, bool set_default)
     287                 : {
     288                 :     PrefValue pref;
     289            5461 :     pref.intVal = value;
     290                 : 
     291            5461 :     return pref_HashPref(pref_name, pref, PREF_INT, set_default);
     292                 : }
     293                 : 
     294                 : nsresult
     295            5205 : PREF_SetBoolPref(const char *pref_name, bool value, bool set_default)
     296                 : {
     297                 :     PrefValue pref;
     298            5205 :     pref.boolVal = value;
     299                 : 
     300            5205 :     return pref_HashPref(pref_name, pref, PREF_BOOL, set_default);
     301                 : }
     302                 : 
     303                 : nsresult
     304               0 : pref_SetPrefTuple(const PrefTuple &aPref, bool set_default)
     305                 : {
     306               0 :     switch (aPref.type) {
     307                 :         case PrefTuple::PREF_STRING:
     308               0 :             return PREF_SetCharPref(aPref.key.get(), aPref.stringVal.get(), set_default);
     309                 : 
     310                 :         case PrefTuple::PREF_INT:
     311               0 :             return PREF_SetIntPref(aPref.key.get(), aPref.intVal, set_default);
     312                 : 
     313                 :         case PrefTuple::PREF_BOOL:
     314               0 :             return PREF_SetBoolPref(aPref.key.get(), aPref.boolVal, set_default);
     315                 :     }
     316                 : 
     317               0 :     NS_NOTREACHED("Unknown type");
     318               0 :     return NS_ERROR_INVALID_ARG;
     319                 : }
     320                 : 
     321                 : PLDHashOperator
     322            4865 : pref_savePref(PLDHashTable *table, PLDHashEntryHdr *heh, PRUint32 i, void *arg)
     323                 : {
     324            4865 :     pref_saveArgs *argData = static_cast<pref_saveArgs *>(arg);
     325            4865 :     PrefHashEntry *pref = static_cast<PrefHashEntry *>(heh);
     326                 : 
     327            4865 :     PR_ASSERT(pref);
     328            4865 :     if (!pref)
     329               0 :         return PL_DHASH_NEXT;
     330                 : 
     331            9730 :     nsCAutoString prefValue;
     332            9730 :     nsCAutoString prefPrefix;
     333            4865 :     prefPrefix.Assign(NS_LITERAL_CSTRING("user_pref(\""));
     334                 : 
     335                 :     // where we're getting our pref from
     336                 :     PrefValue* sourcePref;
     337                 : 
     338            4882 :     if (PREF_HAS_USER_VALUE(pref) &&
     339                 :         (pref_ValueChanged(pref->defaultPref,
     340                 :                            pref->userPref,
     341              15 :                            (PrefType) PREF_TYPE(pref)) ||
     342               2 :          !(pref->flags & PREF_HAS_DEFAULT))) {
     343              15 :         sourcePref = &pref->userPref;
     344                 :     } else {
     345            4850 :         if (argData->saveTypes == SAVE_ALL_AND_DEFAULTS) {
     346               0 :             prefPrefix.Assign(NS_LITERAL_CSTRING("pref(\""));
     347               0 :             sourcePref = &pref->defaultPref;
     348                 :         }
     349                 :         else
     350                 :             // do not save default prefs that haven't changed
     351            4850 :             return PL_DHASH_NEXT;
     352                 :     }
     353                 : 
     354                 :     // strings are in quotes!
     355              15 :     if (pref->flags & PREF_STRING) {
     356               5 :         prefValue = '\"';
     357               5 :         str_escape(sourcePref->stringVal, prefValue);
     358               5 :         prefValue += '\"';
     359                 :     }
     360                 : 
     361              10 :     else if (pref->flags & PREF_INT)
     362               5 :         prefValue.AppendInt(sourcePref->intVal);
     363                 : 
     364               5 :     else if (pref->flags & PREF_BOOL)
     365               5 :         prefValue = (sourcePref->boolVal) ? "true" : "false";
     366                 : 
     367              30 :     nsCAutoString prefName;
     368              15 :     str_escape(pref->key, prefName);
     369                 : 
     370              15 :     argData->prefArray[i] = ToNewCString(prefPrefix +
     371                 :                                          prefName +
     372              30 :                                          NS_LITERAL_CSTRING("\", ") +
     373              15 :                                          prefValue +
     374              45 :                                          NS_LITERAL_CSTRING(");"));
     375                 : 
     376              15 :     return PL_DHASH_NEXT;
     377                 : }
     378                 : 
     379                 : PLDHashOperator
     380               0 : pref_MirrorPrefs(PLDHashTable *table,
     381                 :                  PLDHashEntryHdr *heh,
     382                 :                  PRUint32 i,
     383                 :                  void *arg)
     384                 : {
     385               0 :     if (heh) {
     386               0 :         PrefHashEntry *entry = static_cast<PrefHashEntry *>(heh);
     387                 :         PrefTuple *newEntry =
     388               0 :             static_cast<nsTArray<PrefTuple> *>(arg)->AppendElement();
     389                 : 
     390               0 :         pref_GetTupleFromEntry(entry, newEntry);
     391                 :     }
     392               0 :     return PL_DHASH_NEXT;
     393                 : }
     394                 : 
     395                 : void
     396               0 : pref_GetTupleFromEntry(PrefHashEntry *aHashEntry, PrefTuple *aTuple)
     397                 : {
     398               0 :     aTuple->key = aHashEntry->key;
     399                 : 
     400                 :     PrefValue *value = PREF_HAS_USER_VALUE(aHashEntry) ?
     401               0 :         &(aHashEntry->userPref) : &(aHashEntry->defaultPref);
     402                 : 
     403               0 :     switch (aHashEntry->flags & PREF_VALUETYPE_MASK) {
     404                 :         case PREF_STRING:
     405               0 :             aTuple->stringVal = value->stringVal;
     406               0 :             aTuple->type = PrefTuple::PREF_STRING;
     407               0 :             return;
     408                 : 
     409                 :         case PREF_INT:
     410               0 :             aTuple->intVal = value->intVal;
     411               0 :             aTuple->type = PrefTuple::PREF_INT;
     412               0 :             return;
     413                 : 
     414                 :         case PREF_BOOL:
     415               0 :             aTuple->boolVal = !!value->boolVal;
     416               0 :             aTuple->type = PrefTuple::PREF_BOOL;
     417               0 :             return;
     418                 :     }
     419                 : }
     420                 : 
     421                 : 
     422                 : int
     423            4951 : pref_CompareStrings(const void *v1, const void *v2, void *unused)
     424                 : {
     425            4951 :     char *s1 = *(char**) v1;
     426            4951 :     char *s2 = *(char**) v2;
     427                 : 
     428            4951 :     if (!s1)
     429                 :     {
     430            4883 :         if (!s2)
     431            4883 :             return 0;
     432                 :         else
     433               0 :             return -1;
     434                 :     }
     435              68 :     else if (!s2)
     436              16 :         return 1;
     437                 :     else
     438              52 :         return strcmp(s1, s2);
     439                 : }
     440                 : 
     441            4069 : bool PREF_HasUserPref(const char *pref_name)
     442                 : {
     443            4069 :     if (!gHashTable.ops)
     444               0 :         return false;
     445                 : 
     446            4069 :     PrefHashEntry *pref = pref_HashTableLookup(pref_name);
     447            4069 :     if (!pref) return false;
     448                 : 
     449                 :     /* convert PREF_HAS_USER_VALUE to bool */
     450            2686 :     return (PREF_HAS_USER_VALUE(pref) != 0);
     451                 : 
     452                 : }
     453                 : 
     454                 : nsresult
     455           47198 : PREF_CopyCharPref(const char *pref_name, char ** return_buffer, bool get_default)
     456                 : {
     457           47198 :     if (!gHashTable.ops)
     458               0 :         return NS_ERROR_NOT_INITIALIZED;
     459                 : 
     460           47198 :     nsresult rv = NS_ERROR_UNEXPECTED;
     461                 :     char* stringVal;
     462           47198 :     PrefHashEntry* pref = pref_HashTableLookup(pref_name);
     463                 : 
     464           47198 :     if (pref && (pref->flags & PREF_STRING))
     465                 :     {
     466           37556 :         if (get_default || PREF_IS_LOCKED(pref) || !PREF_HAS_USER_VALUE(pref))
     467           23826 :             stringVal = pref->defaultPref.stringVal;
     468                 :         else
     469           13730 :             stringVal = pref->userPref.stringVal;
     470                 : 
     471           37556 :         if (stringVal) {
     472           37556 :             *return_buffer = NS_strdup(stringVal);
     473           37556 :             rv = NS_OK;
     474                 :         }
     475                 :     }
     476           47198 :     return rv;
     477                 : }
     478                 : 
     479           79882 : nsresult PREF_GetIntPref(const char *pref_name,PRInt32 * return_int, bool get_default)
     480                 : {
     481           79882 :     if (!gHashTable.ops)
     482               0 :         return NS_ERROR_NOT_INITIALIZED;
     483                 : 
     484           79882 :     nsresult rv = NS_ERROR_UNEXPECTED;
     485           79882 :     PrefHashEntry* pref = pref_HashTableLookup(pref_name);
     486           79882 :     if (pref && (pref->flags & PREF_INT))
     487                 :     {
     488           51114 :         if (get_default || PREF_IS_LOCKED(pref) || !PREF_HAS_USER_VALUE(pref))
     489                 :         {
     490           46056 :             PRInt32 tempInt = pref->defaultPref.intVal;
     491                 :             /* check to see if we even had a default */
     492           46056 :             if (!(pref->flags & PREF_HAS_DEFAULT))
     493               0 :                 return NS_ERROR_UNEXPECTED;
     494           46056 :             *return_int = tempInt;
     495                 :         }
     496                 :         else
     497            5058 :             *return_int = pref->userPref.intVal;
     498           51114 :         rv = NS_OK;
     499                 :     }
     500           79882 :     return rv;
     501                 : }
     502                 : 
     503          132200 : nsresult PREF_GetBoolPref(const char *pref_name, bool * return_value, bool get_default)
     504                 : {
     505          132200 :     if (!gHashTable.ops)
     506               0 :         return NS_ERROR_NOT_INITIALIZED;
     507                 : 
     508          132200 :     nsresult rv = NS_ERROR_UNEXPECTED;
     509          132200 :     PrefHashEntry* pref = pref_HashTableLookup(pref_name);
     510                 :     //NS_ASSERTION(pref, pref_name);
     511          132200 :     if (pref && (pref->flags & PREF_BOOL))
     512                 :     {
     513          100949 :         if (get_default || PREF_IS_LOCKED(pref) || !PREF_HAS_USER_VALUE(pref))
     514                 :         {
     515           90209 :             bool tempBool = pref->defaultPref.boolVal;
     516                 :             /* check to see if we even had a default */
     517           90209 :             if (pref->flags & PREF_HAS_DEFAULT) {
     518           89677 :                 *return_value = tempBool;
     519           89677 :                 rv = NS_OK;
     520           90209 :             }
     521                 :         }
     522                 :         else {
     523           10740 :             *return_value = pref->userPref.boolVal;
     524           10740 :             rv = NS_OK;
     525                 :         }
     526                 :     }
     527          132200 :     return rv;
     528                 : }
     529                 : 
     530                 : /* Delete a branch. Used for deleting mime types */
     531                 : static PLDHashOperator
     532          310590 : pref_DeleteItem(PLDHashTable *table, PLDHashEntryHdr *heh, PRUint32 i, void *arg)
     533                 : {
     534          310590 :     PrefHashEntry* he = static_cast<PrefHashEntry*>(heh);
     535          310590 :     const char *to_delete = (const char *) arg;
     536          310590 :     int len = PL_strlen(to_delete);
     537                 : 
     538                 :     /* note if we're deleting "ldap" then we want to delete "ldap.xxx"
     539                 :         and "ldap" (if such a leaf node exists) but not "ldap_1.xxx" */
     540          630141 :     if (to_delete && (PL_strncmp(he->key, to_delete, (PRUint32) len) == 0 ||
     541          319551 :         (len-1 == (int)PL_strlen(he->key) && PL_strncmp(he->key, to_delete, (PRUint32)(len-1)) == 0)))
     542               8 :         return PL_DHASH_REMOVE;
     543                 : 
     544          310582 :     return PL_DHASH_NEXT;
     545                 : }
     546                 : 
     547                 : nsresult
     548             192 : PREF_DeleteBranch(const char *branch_name)
     549                 : {
     550             192 :     int len = (int)PL_strlen(branch_name);
     551                 : 
     552             192 :     if (!gHashTable.ops)
     553               0 :         return NS_ERROR_NOT_INITIALIZED;
     554                 : 
     555                 :     /* The following check insures that if the branch name already has a "."
     556                 :      * at the end, we don't end up with a "..". This fixes an incompatibility
     557                 :      * between nsIPref, which needs the period added, and nsIPrefBranch which
     558                 :      * does not. When nsIPref goes away this function should be fixed to
     559                 :      * never add the period at all.
     560                 :      */
     561             384 :     nsCAutoString branch_dot(branch_name);
     562             192 :     if ((len > 1) && branch_name[len - 1] != '.')
     563               2 :         branch_dot += '.';
     564                 : 
     565                 :     PL_DHashTableEnumerate(&gHashTable, pref_DeleteItem,
     566             192 :                            (void*) branch_dot.get());
     567             192 :     gDirty = true;
     568             192 :     return NS_OK;
     569                 : }
     570                 : 
     571                 : 
     572                 : nsresult
     573           34721 : PREF_ClearUserPref(const char *pref_name)
     574                 : {
     575           34721 :     if (!gHashTable.ops)
     576               0 :         return NS_ERROR_NOT_INITIALIZED;
     577                 : 
     578           34721 :     PrefHashEntry* pref = pref_HashTableLookup(pref_name);
     579           34721 :     if (pref && PREF_HAS_USER_VALUE(pref))
     580                 :     {
     581            4020 :         pref->flags &= ~PREF_USERSET;
     582                 : 
     583            4020 :         if (!(pref->flags & PREF_HAS_DEFAULT)) {
     584            3443 :             PL_DHashTableOperate(&gHashTable, pref_name, PL_DHASH_REMOVE);
     585                 :         }
     586                 : 
     587            4020 :         pref_DoCallback(pref_name);
     588            4020 :         gDirty = true;
     589                 :     }
     590           34721 :     return NS_OK;
     591                 : }
     592                 : 
     593                 : static PLDHashOperator
     594               0 : pref_ClearUserPref(PLDHashTable *table, PLDHashEntryHdr *he, PRUint32,
     595                 :                    void *arg)
     596                 : {
     597               0 :     PrefHashEntry *pref = static_cast<PrefHashEntry*>(he);
     598                 : 
     599               0 :     PLDHashOperator nextOp = PL_DHASH_NEXT;
     600                 : 
     601               0 :     if (PREF_HAS_USER_VALUE(pref))
     602                 :     {
     603               0 :         pref->flags &= ~PREF_USERSET;
     604                 : 
     605               0 :         if (!(pref->flags & PREF_HAS_DEFAULT)) {
     606               0 :             nextOp = PL_DHASH_REMOVE;
     607                 :         }
     608                 : 
     609               0 :         pref_DoCallback(pref->key);
     610                 :     }
     611               0 :     return nextOp;
     612                 : }
     613                 : 
     614                 : nsresult
     615               0 : PREF_ClearAllUserPrefs()
     616                 : {
     617               0 :     if (!gHashTable.ops)
     618               0 :         return NS_ERROR_NOT_INITIALIZED;
     619                 : 
     620               0 :     PL_DHashTableEnumerate(&gHashTable, pref_ClearUserPref, nsnull);
     621                 : 
     622               0 :     gDirty = true;
     623               0 :     return NS_OK;
     624                 : }
     625                 : 
     626               9 : nsresult PREF_LockPref(const char *key, bool lockit)
     627                 : {
     628               9 :     if (!gHashTable.ops)
     629               0 :         return NS_ERROR_NOT_INITIALIZED;
     630                 : 
     631               9 :     PrefHashEntry* pref = pref_HashTableLookup(key);
     632               9 :     if (!pref)
     633               2 :         return NS_ERROR_UNEXPECTED;
     634                 : 
     635               7 :     if (lockit) {
     636               4 :         if (!PREF_IS_LOCKED(pref))
     637                 :         {
     638               3 :             pref->flags |= PREF_LOCKED;
     639               3 :             gIsAnyPrefLocked = true;
     640               3 :             pref_DoCallback(key);
     641                 :         }
     642                 :     }
     643                 :     else
     644                 :     {
     645               3 :         if (PREF_IS_LOCKED(pref))
     646                 :         {
     647               2 :             pref->flags &= ~PREF_LOCKED;
     648               2 :             pref_DoCallback(key);
     649                 :         }
     650                 :     }
     651               7 :     return NS_OK;
     652                 : }
     653                 : 
     654                 : /*
     655                 :  * Hash table functions
     656                 :  */
     657         2388326 : static bool pref_ValueChanged(PrefValue oldValue, PrefValue newValue, PrefType type)
     658                 : {
     659         2388326 :     bool changed = true;
     660         2388326 :     if (type & PREF_STRING)
     661                 :     {
     662          790963 :         if (oldValue.stringVal && newValue.stringVal)
     663           12590 :             changed = (strcmp(oldValue.stringVal, newValue.stringVal) != 0);
     664                 :     }
     665         1597363 :     else if (type & PREF_INT)
     666          591131 :         changed = oldValue.intVal != newValue.intVal;
     667         1006232 :     else if (type & PREF_BOOL)
     668         1006232 :         changed = oldValue.boolVal != newValue.boolVal;
     669         2388326 :     return changed;
     670                 : }
     671                 : 
     672         2345562 : static void pref_SetValue(PrefValue* oldValue, PrefValue newValue, PrefType type)
     673                 : {
     674         2345562 :     switch (type & PREF_VALUETYPE_MASK)
     675                 :     {
     676                 :         case PREF_STRING:
     677          781885 :             PR_ASSERT(newValue.stringVal);
     678          781885 :             if (oldValue->stringVal)
     679            5222 :                 PL_strfree(oldValue->stringVal);
     680          781885 :             oldValue->stringVal = newValue.stringVal ? PL_strdup(newValue.stringVal) : NULL;
     681          781885 :             break;
     682                 : 
     683                 :         default:
     684         1563677 :             *oldValue = newValue;
     685                 :     }
     686         2345562 :     gDirty = true;
     687         2345562 : }
     688                 : 
     689          317814 : PrefHashEntry* pref_HashTableLookup(const void *key)
     690                 : {
     691                 :     PrefHashEntry* result =
     692          317814 :         static_cast<PrefHashEntry*>(PL_DHashTableOperate(&gHashTable, key, PL_DHASH_LOOKUP));
     693                 : 
     694          317814 :     if (PL_DHASH_ENTRY_IS_FREE(result))
     695           77255 :         return nsnull;
     696                 : 
     697          240559 :     return result;
     698                 : }
     699                 : 
     700         2379350 : nsresult pref_HashPref(const char *key, PrefValue value, PrefType type, bool set_default)
     701                 : {
     702         2379350 :     if (!gHashTable.ops)
     703               0 :         return NS_ERROR_OUT_OF_MEMORY;
     704                 : 
     705         2379350 :     PrefHashEntry* pref = static_cast<PrefHashEntry*>(PL_DHashTableOperate(&gHashTable, key, PL_DHASH_ADD));
     706                 : 
     707         2379350 :     if (!pref)
     708               0 :         return NS_ERROR_OUT_OF_MEMORY;
     709                 : 
     710                 :     // new entry, better intialize
     711         2379350 :     if (!pref->key) {
     712                 : 
     713                 :         // initialize the pref entry
     714         2301301 :         pref->flags = type;
     715         2301301 :         pref->key = ArenaStrDup(key, &gPrefNameArena);
     716         2301301 :         memset(&pref->defaultPref, 0, sizeof(pref->defaultPref));
     717         2301301 :         memset(&pref->userPref, 0, sizeof(pref->userPref));
     718                 :     }
     719           78049 :     else if ((((PrefType)(pref->flags)) & PREF_VALUETYPE_MASK) !=
     720                 :                  (type & PREF_VALUETYPE_MASK))
     721                 :     {
     722               0 :         NS_WARNING(nsPrintfCString(192, "Trying to set pref %s to with the wrong type!", key).get());
     723               0 :         return NS_ERROR_UNEXPECTED;
     724                 :     }
     725                 : 
     726         2379350 :     bool valueChanged = false;
     727         2379350 :     if (set_default)
     728                 :     {
     729         2358911 :         if (!PREF_IS_LOCKED(pref))
     730                 :         {       /* ?? change of semantics? */
     731         2840484 :             if (pref_ValueChanged(pref->defaultPref, value, type) ||
     732          481573 :                 !(pref->flags & PREF_HAS_DEFAULT))
     733                 :             {
     734         2330318 :                 pref_SetValue(&pref->defaultPref, value, type);
     735         2330318 :                 pref->flags |= PREF_HAS_DEFAULT;
     736         2330318 :                 if (!PREF_HAS_USER_VALUE(pref))
     737         2330317 :                     valueChanged = true;
     738                 :             }
     739                 :         }
     740                 :     }
     741                 :     else
     742                 :     {
     743                 :         /* If new value is same as the default value, then un-set the user value.
     744                 :            Otherwise, set the user value only if it has changed */
     745           20439 :         if (!pref_ValueChanged(pref->defaultPref, value, type) &&
     746                 :             pref->flags & PREF_HAS_DEFAULT)
     747                 :         {
     748             635 :             if (PREF_HAS_USER_VALUE(pref))
     749                 :             {
     750             141 :                 pref->flags &= ~PREF_USERSET;
     751             141 :                 if (!PREF_IS_LOCKED(pref))
     752             141 :                     valueChanged = true;
     753                 :             }
     754                 :         }
     755           28765 :         else if ( !PREF_HAS_USER_VALUE(pref) ||
     756            8961 :                    pref_ValueChanged(pref->userPref, value, type) )
     757                 :         {
     758           15244 :             pref_SetValue(&pref->userPref, value, type);
     759           15244 :             pref->flags |= PREF_USERSET;
     760           15244 :             if (!PREF_IS_LOCKED(pref))
     761           15244 :                 valueChanged = true;
     762                 :         }
     763                 :     }
     764                 : 
     765         2379350 :     nsresult rv = NS_OK;
     766         2379350 :     if (valueChanged) {
     767         2345702 :         gDirty = true;
     768                 : 
     769         2345702 :         nsresult rv2 = pref_DoCallback(key);
     770         2345702 :         if (NS_FAILED(rv2))
     771               0 :             rv = rv2;
     772                 :     }
     773         2379350 :     return rv;
     774                 : }
     775                 : 
     776                 : PrefType
     777           19733 : PREF_GetPrefType(const char *pref_name)
     778                 : {
     779           19733 :     if (gHashTable.ops)
     780                 :     {
     781           19733 :         PrefHashEntry* pref = pref_HashTableLookup(pref_name);
     782           19733 :         if (pref)
     783                 :         {
     784           14864 :             if (pref->flags & PREF_STRING)
     785            7848 :                 return PREF_STRING;
     786            7016 :             else if (pref->flags & PREF_INT)
     787            2504 :                 return PREF_INT;
     788            4512 :             else if (pref->flags & PREF_BOOL)
     789            4512 :                 return PREF_BOOL;
     790                 :         }
     791                 :     }
     792            4869 :     return PREF_INVALID;
     793                 : }
     794                 : 
     795                 : /* -- */
     796                 : 
     797                 : bool
     798            1869 : PREF_PrefIsLocked(const char *pref_name)
     799                 : {
     800            1869 :     bool result = false;
     801            1869 :     if (gIsAnyPrefLocked && gHashTable.ops) {
     802               2 :         PrefHashEntry* pref = pref_HashTableLookup(pref_name);
     803               2 :         if (pref && PREF_IS_LOCKED(pref))
     804               1 :             result = true;
     805                 :     }
     806                 : 
     807            1869 :     return result;
     808                 : }
     809                 : 
     810                 : /* Adds a node to the beginning of the callback list. */
     811                 : void
     812          120644 : PREF_RegisterCallback(const char *pref_node,
     813                 :                        PrefChangedFunc callback,
     814                 :                        void * instance_data)
     815                 : {
     816          120644 :     NS_PRECONDITION(pref_node, "pref_node must not be nsnull");
     817          120644 :     NS_PRECONDITION(callback, "callback must not be nsnull");
     818                 : 
     819          120644 :     struct CallbackNode* node = (struct CallbackNode*) malloc(sizeof(struct CallbackNode));
     820          120644 :     if (node)
     821                 :     {
     822          120644 :         node->domain = PL_strdup(pref_node);
     823          120644 :         node->func = callback;
     824          120644 :         node->data = instance_data;
     825          120644 :         node->next = gCallbacks;
     826          120644 :         gCallbacks = node;
     827                 :     }
     828                 :     return;
     829                 : }
     830                 : 
     831                 : /* Removes |node| from gCallbacks list.
     832                 :    Returns the node after the deleted one. */
     833                 : struct CallbackNode*
     834          120644 : pref_RemoveCallbackNode(struct CallbackNode* node,
     835                 :                         struct CallbackNode* prev_node)
     836                 : {
     837          120644 :     NS_PRECONDITION(!prev_node || prev_node->next == node, "invalid params");
     838          120644 :     NS_PRECONDITION(prev_node || gCallbacks == node, "invalid params");
     839                 : 
     840          120644 :     NS_ASSERTION(!gCallbacksInProgress,
     841                 :         "modifying the callback list while gCallbacksInProgress is true");
     842                 : 
     843          120644 :     struct CallbackNode* next_node = node->next;
     844          120644 :     if (prev_node)
     845          114952 :         prev_node->next = next_node;
     846                 :     else
     847            5692 :         gCallbacks = next_node;
     848          120644 :     PL_strfree(node->domain);
     849          120644 :     free(node);
     850          120644 :     return next_node;
     851                 : }
     852                 : 
     853                 : /* Deletes a node from the callback list or marks it for deletion. */
     854                 : nsresult
     855          120644 : PREF_UnregisterCallback(const char *pref_node,
     856                 :                          PrefChangedFunc callback,
     857                 :                          void * instance_data)
     858                 : {
     859          120644 :     nsresult rv = NS_ERROR_FAILURE;
     860          120644 :     struct CallbackNode* node = gCallbacks;
     861          120644 :     struct CallbackNode* prev_node = NULL;
     862                 : 
     863         5870213 :     while (node != NULL)
     864                 :     {
     865         5749569 :         if ( node->func == callback &&
     866                 :              node->data == instance_data &&
     867          120644 :              strcmp(node->domain, pref_node) == 0)
     868                 :         {
     869          120644 :             if (gCallbacksInProgress)
     870                 :             {
     871                 :                 // postpone the node removal until after
     872                 :                 // gCallbacks enumeration is finished.
     873               2 :                 node->func = nsnull;
     874               2 :                 gShouldCleanupDeadNodes = true;
     875               2 :                 prev_node = node;
     876               2 :                 node = node->next;
     877                 :             }
     878                 :             else
     879                 :             {
     880          120642 :                 node = pref_RemoveCallbackNode(node, prev_node);
     881                 :             }
     882          120644 :             rv = NS_OK;
     883                 :         }
     884                 :         else
     885                 :         {
     886         5508281 :             prev_node = node;
     887         5508281 :             node = node->next;
     888                 :         }
     889                 :     }
     890          120644 :     return rv;
     891                 : }
     892                 : 
     893         2349727 : static nsresult pref_DoCallback(const char* changed_pref)
     894                 : {
     895         2349727 :     nsresult rv = NS_OK;
     896                 :     struct CallbackNode* node;
     897                 : 
     898         2349727 :     bool reentered = gCallbacksInProgress;
     899         2349727 :     gCallbacksInProgress = true;
     900                 :     // Nodes must not be deleted while gCallbacksInProgress is true.
     901                 :     // Nodes that need to be deleted are marked for deletion by nulling
     902                 :     // out the |func| pointer. We release them at the end of this function
     903                 :     // if we haven't reentered.
     904                 : 
     905         4309797 :     for (node = gCallbacks; node != NULL; node = node->next)
     906                 :     {
     907         3920140 :         if ( node->func &&
     908                 :              PL_strncmp(changed_pref,
     909                 :                         node->domain,
     910         1960070 :                         PL_strlen(node->domain)) == 0 )
     911                 :         {
     912            2512 :             nsresult rv2 = (*node->func) (changed_pref, node->data);
     913            2512 :             if (NS_FAILED(rv2))
     914               0 :                 rv = rv2;
     915                 :         }
     916                 :     }
     917                 : 
     918         2349727 :     gCallbacksInProgress = reentered;
     919                 : 
     920         2349727 :     if (gShouldCleanupDeadNodes && !gCallbacksInProgress)
     921                 :     {
     922               2 :         struct CallbackNode* prev_node = NULL;
     923               2 :         node = gCallbacks;
     924                 : 
     925             138 :         while (node != NULL)
     926                 :         {
     927             134 :             if (!node->func)
     928                 :             {
     929               2 :                 node = pref_RemoveCallbackNode(node, prev_node);
     930                 :             }
     931                 :             else
     932                 :             {
     933             132 :                 prev_node = node;
     934             132 :                 node = node->next;
     935                 :             }
     936                 :         }
     937               2 :         gShouldCleanupDeadNodes = false;
     938                 :     }
     939                 : 
     940         2349727 :     return rv;
     941                 : }
     942                 : 
     943         2358889 : void PREF_ReaderCallback(void       *closure,
     944                 :                          const char *pref,
     945                 :                          PrefValue   value,
     946                 :                          PrefType    type,
     947                 :                          bool        isDefault)
     948                 : {
     949         2358889 :     pref_HashPref(pref, value, type, isDefault);
     950         2358889 : }

Generated by: LCOV version 1.7