File: FXRegistry.cpp

package info (click to toggle)
gogglesmm 1.2.5-6
  • links: PTS
  • area: main
  • in suites: forky, sid
  • size: 16,812 kB
  • sloc: cpp: 231,960; ansic: 893; xml: 222; makefile: 33
file content (552 lines) | stat: -rw-r--r-- 17,771 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
/********************************************************************************
*                                                                               *
*                           R e g i s t r y   C l a s s                         *
*                                                                               *
*********************************************************************************
* Copyright (C) 1998,2022 by Jeroen van der Zijp.   All Rights Reserved.        *
*********************************************************************************
* This library is free software; you can redistribute it and/or modify          *
* it under the terms of the GNU Lesser General Public License as published by   *
* the Free Software Foundation; either version 3 of the License, or             *
* (at your option) any later version.                                           *
*                                                                               *
* This library is distributed in the hope that it will be useful,               *
* but WITHOUT ANY WARRANTY; without even the implied warranty of                *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                 *
* GNU Lesser General Public License for more details.                           *
*                                                                               *
* You should have received a copy of the GNU Lesser General Public License      *
* along with this program.  If not, see <http://www.gnu.org/licenses/>          *
********************************************************************************/
#include "xincs.h"
#include "fxver.h"
#include "fxdefs.h"
#include "fxmath.h"
#include "FXArray.h"
#include "FXHash.h"
#include "FXStream.h"
#include "FXObject.h"
#include "FXString.h"
#include "FXSystem.h"
#include "FXProcess.h"
#include "FXPath.h"
#include "FXIO.h"
#include "FXStat.h"
#include "FXFile.h"
#include "FXDir.h"
#include "FXStringDictionary.h"
#include "FXRegistry.h"

/*
  Notes:

  - The FOX settings tree stores configuration data for FOX-based applications; it
    is organized as follows:

    SettingsRoot/foxrc                  The "foxrc" file stores common configuration
                                        settings for all FOX-based applications,
                                        such as colors and file bindings.

    SettingsRoot/Vendor/Vendorrc        The Vendorrc file is common to all applications
                                        from a particular organization, so that common
                                        configurable attributes may be given consistent
                                        values easily.

    SettingsRoot/Vendor/Applicationrc   The Applicationrc file stores configuration data
                                        unique to a specific application only.

    SettingsRoot/Applicationrc          If no Vendor name is specified, the Applicationrc
                                        file is located at the toplevel of the SettingsRoot.

  - A System-Wide SettingsRoot may be located in a read-only, system adminstrator designated
    place, to be shared by all users on a particular installation.  For example, this may store
    license-keys, references to online documentation, and other installation-time parameters.

  - A Per-User SettingsRoot is typically located in a user's home directory.
    Configurations stored in these files will be merged with the System-Wide configurations.
    Parameters given different values in the Per-User files will override those in the
    System-Wide ones.

  - Rationale:

      1)    When installing an application, simply copy "seed" registry files to
            the System-Wide SettingsRoot; having a subdirectory Vendor prevents
            clobbering other people's registry files, even if their application
            has the same name.

      2)    System-Wide registry files are, as a matter of principle, read-only.

      3)    System-Wide registry files are loaded first, and Per-User registry
            files are loaded on top of that.

      4)    Registry files loaded later will take precedence over those loaded
            earlier; i.e. key/value pairs in a later file will override a key/value
            pair with the same key loaded earlier.

      5)    The exception to the rule is that a key/value pair will not be overridden
            if the value of the key was changed since it had been loaded.

      6)    An application reads files in the order:

                System-Wide:
                        fox.rc,
                        Vendor/Vendor.rc,
                        Vendor/Application.rc

                Per-User:
                        fox.rc,
                        Vendor/Vendor.rc,
                        Vendor/Application.rc

      7)    When System-Wide settings files are loaded, entries are not marked as
            changed, and thus not written into the Per-User settings file.  Only
            values changed by the Application will be written into the Per-User file.

      8)    Settings loaded from the Per-User settings file *will* however be written
            back to the Per-User settings file, regarless whether they are changed or
            not (exception is when no single entry was changed at all!).

      9)    ONLY the Per-User, Application-specific settings files ARE WRITTEN!

     10)    Special applications, such as ControlPanel, may change other settings files,
            however.

  - Locations of registry settings files:

      o System-Wide registry files are loaded from the directory defined by user-
        specified environment variable $FOXDIR, if this variable was set.

      o System-Wide registry files are searched in SystemDirectories path-list.
        The path-list may be changed by setSystemDirectories().

      o On UNIX systems, the XDG standard is followed; this means the location
        of System-Wide settings should controlled by $XDG_CONFIG_DIRS.

      o If this environment variable isn't set, then SystemDirectories with only have
        one single directory, the default value: "/etc/xdg".

      o Directories in SystemDirectories will be searched for a subdirectory "foxrc"
        which is the root of the System-Wide settings tree for all FOX applications;
        for example: "/etc/xdg/foxrc/Desktop".

      o Per-User registry files are located from a single toplevel directory in variable
        UserDirectory.  The value of this variable may be changed by setUserDirectory().

      o On UNIX systems, the XDG standard is followed; this means the location of the
        Per-User settings should controlled by $XDG_CONFIG_HOME.   If this environment
        variable set, the root for the Per-User settings tree for all FOX applications
        is $XDG_CONFIG_HOME/fox.rc.

      o Otherwise, it will have the default value: "~/.config".


  - The Freedesktop.org XDG standard is found at:

        http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html

    Important for FOX is:

     $XDG_DATA_HOME     Per-user data files, defaults to "$HOME/.local/share".

     $XDG_CONFIG_HOME   Per-user configuration files, defaults to "$HOME/.config".

     $XDG_DATA_DIRS     Colon separated search path for per-user data files; default
                        paths are "/usr/local/share/:/usr/share/"

     $XDG_CONFIG_DIRS   Colon separated search path for per-user configuration files;
                        defaults to "/etc/xdg".
*/

#define MAXNAME   200
#define MAXVALUE  2000

// Default locations and names
#if defined(WIN32)
#define FOXRC           "fox.ini"
#define SYSTEMDIRS      "C:\\Program Files;C:\\Windows"
#define USERDIR         "%USERPROFILE%\\fox"
#define FILEEXT         ".ini"
#else
#define FOXRC           "fox.rc"
#define SYSTEMDIRS      "/etc/xdg"
#define USERDIR         "~/.config"
#define FILEEXT         ".rc"
#endif

using namespace FX;

/*******************************************************************************/

namespace FX {


// File extension for settings files
const FXchar FXRegistry::ext[]=FILEEXT;


// File name of common settings file
const FXchar FXRegistry::foxrc[]=FOXRC;


// Make registry object
FXRegistry::FXRegistry(const FXString& akey,const FXString& vkey):applicationkey(akey),vendorkey(vkey),systemdirs(SYSTEMDIRS),userdir(USERDIR){
#if defined(WIN32)
  ascii=false;
#else
  ascii=true;
#endif
  }


#if defined(WIN32)

// Read from Windows Registry
FXbool FXRegistry::readFromRegistry(FXptr hroot,FXbool mrk){
  HKEY hsoftware;
  FXbool ok=false;

  FXTRACE((100,"FXRegistry::readFromRegistry(%p,%d)\n",hroot,mrk));

  // Open Software registry section
  if(RegOpenKeyExA((HKEY)hroot,"Software",0,KEY_READ,&hsoftware)==ERROR_SUCCESS){

    // Read Software\FOX
    if(readFromRegistryGroup("FOX",hsoftware,false)) ok=true;

    // Have vendor key
    if(!vendorkey.empty()){
      HKEY hvendor;

      // Open vendor registry sub-section
      if(RegOpenKeyExA(hsoftware,vendorkey.text(),0,KEY_READ,&hvendor)==ERROR_SUCCESS){

        // Read under "Software\Vendor\Vendor"
        if(readFromRegistryGroup(vendorkey,hvendor,false)) ok=true;

        // Have application key
        if(!applicationkey.empty()){

          // Read under "Software\Vendor\Application"
          if(readFromRegistryGroup(applicationkey,hvendor,mrk)) ok=true;
          }
        RegCloseKey(hvendor);
        }
      }

    // No vendor key
    else{

      // Have application key
      if(!applicationkey.empty()){

        // Read under "Software\Application"
        if(readFromRegistryGroup(applicationkey,hsoftware,mrk)) ok=true;
        }
      }
    RegCloseKey(hsoftware);
    }
  return ok;
  }


// Read from given group
FXbool FXRegistry::readFromRegistryGroup(const FXString& group,FXptr hbase,FXbool mrk){
  FXchar section[MAXNAME],name[MAXNAME],value[MAXVALUE];
  HKEY hgroup;

  // Open registry group
  if(RegOpenKeyExA((HKEY)hbase,group.text(),0,KEY_READ,&hgroup)==ERROR_SUCCESS){
    DWORD sectionsize=MAXNAME;
    DWORD sectionindex=0;
    FILETIME writetime;

    // Read sections
    while(RegEnumKeyExA(hgroup,sectionindex,section,&sectionsize,nullptr,nullptr,nullptr,&writetime)==ERROR_SUCCESS){

      // Open section
      HKEY hsection;
      if(RegOpenKeyExA(hgroup,section,0,KEY_READ,&hsection)==ERROR_SUCCESS){
        DWORD namesize=MAXNAME;
        DWORD valuesize=MAXVALUE;
        DWORD index=0;
        DWORD type;

        // Read key-value pairs
        while(RegEnumValueA(hsection,index,name,&namesize,nullptr,&type,(BYTE*)value,&valuesize)!=ERROR_NO_MORE_ITEMS){
          FXASSERT(type==REG_SZ);
          at(section).at(name,mrk)=value;
          namesize=MAXNAME;
          valuesize=MAXVALUE;
          index++;
          }

        // Close section
        RegCloseKey(hsection);
        }
      sectionsize=MAXNAME;
      sectionindex++;
      }

    // Close group
    RegCloseKey(hgroup);
    return true;
    }
  return false;
  }


// Update current user's settings
FXbool FXRegistry::writeToRegistry(FXptr hroot){
  FXbool ok=false;

  FXTRACE((100,"FXRegistry::writeToRegistry(%p)\n",hroot));

  // Have application key
  if(!applicationkey.empty()){
    HKEY hsoftware;

    // Open software registry section
    if(RegOpenKeyExA((HKEY)hroot,"Software",0,KEY_WRITE,&hsoftware)==ERROR_SUCCESS){

      // Have vendor key
      if(!vendorkey.empty()){
        HKEY hvendor;
        DWORD disp;

        // Open vendor registry sub-section
        if(RegCreateKeyExA(hsoftware,vendorkey.text(),0,REG_NONE,REG_OPTION_NON_VOLATILE,KEY_WRITE|KEY_READ,nullptr,&hvendor,&disp)==ERROR_SUCCESS){

          // Have application key
          if(!applicationkey.empty()){

            // Write under "Software\Vendor\Application"
            if(writeToRegistryGroup(applicationkey,hvendor)) ok=true;
            }

          // Done with vendor key
          RegCloseKey(hvendor);
          }
        }

      // No vendor key
      else{

        // Have application key
        if(!applicationkey.empty()){

          // Write under "Software\Application"
          if(writeToRegistryGroup(applicationkey,hsoftware)) ok=true;
          }
        }

      // Done with software key
      RegCloseKey(hsoftware);
      }
    }
  return ok;
  }


// Write to registry group
FXbool FXRegistry::writeToRegistryGroup(const FXString& group,FXptr hbase){
  FXchar section[MAXNAME];
  DWORD sectionsize,sectionindex,disp;
  HKEY hgroup,hsection;
  FXint s,e;
  FILETIME writetime;

  // Open registry group
  if(RegCreateKeyExA((HKEY)hbase,group.text(),0,REG_NONE,REG_OPTION_NON_VOLATILE,KEY_WRITE|KEY_READ,nullptr,&hgroup,&disp)==ERROR_SUCCESS){

    // First, purge all existing sections
    while(1){
      sectionindex=0;
      sectionsize=MAXNAME;
      if(RegEnumKeyExA(hgroup,sectionindex,section,&sectionsize,nullptr,nullptr,nullptr,&writetime)!=ERROR_SUCCESS) break;
      if(RegDeleteKeyA(hgroup,section)!=ERROR_SUCCESS) break;
      }

    // Write sections
    for(s=0; s<no(); ++s){

      // Section is non-empty
      if(!empty(s)){
        hsection=nullptr;

        // Write keys in this section
        for(e=0; e<data(s).no(); ++e){

          // Key is non-empty and marked
          if(!data(s).empty(e) && data(s).mark(e)){

            // Create section in registry upon finding first key in it
            if(hsection==nullptr){
              if(RegCreateKeyExA(hgroup,key(s).text(),0,REG_NONE,REG_OPTION_NON_VOLATILE,KEY_WRITE|KEY_READ,nullptr,&hsection,&disp)!=ERROR_SUCCESS) goto x;
              }

            // Write key-value pair
            if(RegSetValueExA(hsection,data(s).key(e).text(),0,REG_SZ,(BYTE*)data(s).data(e).text(),data(s).data(e).length()+1)!=ERROR_SUCCESS) break;
            }
          }

        // Close section
        if(hsection) RegCloseKey(hsection);
        }

      // Process next registry section
x:    continue;
      }

    // Close group
    RegCloseKey(hgroup);
    return true;
    }
  return false;
  }

#endif


/*******************************************************************************/

// Read registry
FXbool FXRegistry::read(){
  FXbool ok=false;
  if(ascii){
    FXString path;

    // Read system-wide settings from systemdirs
    if(!systemdirs.empty()){

      // Find common settings
      path=FXPath::search(systemdirs,FOXRC);
      if(!path.empty()){
        if(parseFile(path,false)) ok=true;
        }

      // Have vendor subdirectory
      if(!vendorkey.empty()){

        // Find vendor subdirectory
        path=FXPath::search(systemdirs,vendorkey);
        if(!path.empty()){

          // Try read vendor settings
          if(parseFile(path+PATHSEPSTRING+vendorkey+ext,false)) ok=true;

          // Try read application settings
          if(!applicationkey.empty()){
            if(parseFile(path+PATHSEPSTRING+applicationkey+ext,false)) ok=true;
            }
          }
        }

      // Have application settings only
      else if(!applicationkey.empty()){

        // Find applications settings
        path=FXPath::search(systemdirs,applicationkey+ext);

        // Try read application settings
        if(!path.empty()){
          if(parseFile(path,false)) ok=true;
          }
        }
      }

    // Read per-user settings from userdir
    if(!userdir.empty()){

      // Path to settings data
      path=FXPath::absolute(FXPath::expand(userdir));

      // Try read common settings
      if(parseFile(path+PATHSEPSTRING FOXRC,false)) ok=true;

      // Try read vendor settings
      if(!vendorkey.empty()){
        path.append(PATHSEPSTRING+vendorkey);
        if(parseFile(path+PATHSEPSTRING+vendorkey+ext,false)) ok=true;
        }

      // Try read application settings
      if(!applicationkey.empty()){
        if(parseFile(path+PATHSEPSTRING+applicationkey+ext,true)) ok=true;
        }
      }
    }
#if defined(WIN32)
  else{
    // Try read system-wide registry settings from HKEY_LOCAL_MACHINE
    if(readFromRegistry(HKEY_LOCAL_MACHINE,false)) ok=true;

    // Try read per-user registry settings from HKEY_CURRENT_USER
    if(readFromRegistry(HKEY_CURRENT_USER,true)) ok=true;
    }
#endif
  return ok;
  }

/*******************************************************************************/

// Write registry
FXbool FXRegistry::write(){
  FXbool ok=false;
  FXString path;
  if(isModified()){
    if(ascii){

      // Write per-user settings to userdir
      if(!userdir.empty()){

        // Have application key
        if(!applicationkey.empty()){

          // Path to settings data
          path=FXPath::absolute(FXPath::expand(userdir));

          // Have vendor key
          if(!vendorkey.empty()){
            path.append(PATHSEPSTRING+vendorkey);
            }

          // Ensure parent directories exist
          if(FXDir::createDirectories(path)){
            FXString realfile;
            FXString tempfile;

            // Final registry filename
            realfile=path+PATHSEPSTRING+applicationkey+ext;

            // Temporary registry filename
            tempfile=path+PATHSEPSTRING+applicationkey+"_"+FXString::value(FXProcess::current())+ext;

            // Unparse settings into temp file first
            if(unparseFile(tempfile)){

              // Rename ATOMICALLY to proper name
              if(FXFile::move(tempfile,realfile,true)){
                setModified(false);
                ok=true;
                }
              }
            }
          }
        }
      }
#if defined(WIN32)
    else{
      // Write per-user registry settings to HKEY_CURRENT_USER
      if(writeToRegistry(HKEY_CURRENT_USER)) ok=true;
      }
#endif
    }
  return ok;
  }


// Destructor
FXRegistry::~FXRegistry(){
  }

}