OpenCores
URL https://opencores.org/ocsvn/or1k_old/or1k_old/trunk

Subversion Repositories or1k_old

[/] [or1k_old/] [trunk/] [insight/] [tcl/] [win/] [tclWinReg.c] - Blame information for rev 1782

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/*
2
 * tclWinReg.c --
3
 *
4
 *      This file contains the implementation of the "registry" Tcl
5
 *      built-in command.  This command is built as a dynamically
6
 *      loadable extension in a separate DLL.
7
 *
8
 * Copyright (c) 1997 by Sun Microsystems, Inc.
9
 *
10
 * See the file "license.terms" for information on usage and redistribution
11
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
12
 *
13
 * RCS: @(#) $Id: tclWinReg.c,v 1.1.1.1 2002-01-16 10:25:39 markom Exp $
14
 */
15
 
16
#include <tcl.h>
17
#include <stdlib.h>
18
 
19
#define WIN32_LEAN_AND_MEAN
20
#include <windows.h>
21
#undef WIN32_LEAN_AND_MEAN
22
 
23
/*
24
 * TCL_STORAGE_CLASS is set unconditionally to DLLEXPORT because the
25
 * Registry_Init declaration is in the source file itself, which is only
26
 * accessed when we are building a library.
27
 */
28
 
29
#undef TCL_STORAGE_CLASS
30
#define TCL_STORAGE_CLASS DLLEXPORT
31
 
32
/*
33
 * VC++ has an alternate entry point called DllMain, so we need to rename
34
 * our entry point.
35
 */
36
 
37
#ifdef DLL_BUILD
38
# if defined(_MSC_VER)
39
#  define DllEntryPoint DllMain
40
# endif
41
#endif
42
 
43
/*
44
 * The following macros convert between different endian ints.
45
 */
46
 
47
#define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
48
#define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
49
 
50
/*
51
 * The following flag is used in OpenKeys to indicate that the specified
52
 * key should be created if it doesn't currently exist.
53
 */
54
 
55
#define REG_CREATE 1
56
 
57
/*
58
 * The following tables contain the mapping from registry root names
59
 * to the system predefined keys.
60
 */
61
 
62
static char *rootKeyNames[] = {
63
    "HKEY_LOCAL_MACHINE", "HKEY_USERS", "HKEY_CLASSES_ROOT",
64
    "HKEY_CURRENT_USER", "HKEY_CURRENT_CONFIG", NULL
65
};
66
 
67
static HKEY rootKeys[] = {
68
    HKEY_LOCAL_MACHINE, HKEY_USERS, HKEY_CLASSES_ROOT, HKEY_CURRENT_USER,
69
    HKEY_CURRENT_CONFIG, HKEY_PERFORMANCE_DATA, HKEY_DYN_DATA
70
};
71
 
72
/*
73
 * The following table maps from registry types to strings.  Note that
74
 * the indices for this array are the same as the constants for the
75
 * known registry types so we don't need a separate table to hold the
76
 * mapping.
77
 */
78
 
79
static char *typeNames[] = {
80
    "none", "sz", "expand_sz", "binary", "dword",
81
    "dword_big_endian", "link", "multi_sz", "resource_list", NULL
82
};
83
 
84
static DWORD lastType = REG_RESOURCE_LIST;
85
 
86
 
87
/*
88
 * Declarations for functions defined in this file.
89
 */
90
 
91
static void             AppendSystemError(Tcl_Interp *interp, DWORD error);
92
static DWORD            ConvertDWORD(DWORD type, DWORD value);
93
static int              DeleteKey(Tcl_Interp *interp, Tcl_Obj *keyNameObj);
94
static int              DeleteValue(Tcl_Interp *interp, Tcl_Obj *keyNameObj,
95
                            Tcl_Obj *valueNameObj);
96
static int              GetKeyNames(Tcl_Interp *interp, Tcl_Obj *keyNameObj,
97
                            Tcl_Obj *patternObj);
98
static int              GetType(Tcl_Interp *interp, Tcl_Obj *keyNameObj,
99
                            Tcl_Obj *valueNameObj);
100
static int              GetValue(Tcl_Interp *interp, Tcl_Obj *keyNameObj,
101
                            Tcl_Obj *valueNameObj);
102
static int              GetValueNames(Tcl_Interp *interp, Tcl_Obj *keyNameObj,
103
                            Tcl_Obj *patternObj);
104
static int              OpenKey(Tcl_Interp *interp, Tcl_Obj *keyNameObj,
105
                            REGSAM mode, int flags, HKEY *keyPtr);
106
static DWORD            OpenSubKey(char *hostName, HKEY rootKey,
107
                            char *keyName, REGSAM mode, int flags,
108
                            HKEY *keyPtr);
109
static int              ParseKeyName(Tcl_Interp *interp, char *name,
110
                            char **hostNamePtr, HKEY *rootKeyPtr,
111
                            char **keyNamePtr);
112
static DWORD            RecursiveDeleteKey(HKEY hStartKey, LPTSTR pKeyName);
113
static int              RegistryObjCmd(ClientData clientData,
114
                            Tcl_Interp *interp, int objc, Tcl_Obj * CONST objv[]);
115
static int              SetValue(Tcl_Interp *interp, Tcl_Obj *keyNameObj,
116
                            Tcl_Obj *valueNameObj, Tcl_Obj *dataObj,
117
                            Tcl_Obj *typeObj);
118
 
119
EXTERN int Registry_Init(Tcl_Interp *interp);
120
 
121
/*
122
 *----------------------------------------------------------------------
123
 *
124
 * DllEntryPoint --
125
 *
126
 *      This wrapper function is used by Windows to invoke the
127
 *      initialization code for the DLL.  If we are compiling
128
 *      with Visual C++, this routine will be renamed to DllMain.
129
 *      routine.
130
 *
131
 * Results:
132
 *      Returns TRUE;
133
 *
134
 * Side effects:
135
 *      None.
136
 *
137
 *----------------------------------------------------------------------
138
 */
139
 
140
#ifdef __WIN32__
141
#ifdef DLL_BUILD
142
BOOL APIENTRY
143
DllEntryPoint(
144
    HINSTANCE hInst,            /* Library instance handle. */
145
    DWORD reason,               /* Reason this function is being called. */
146
    LPVOID reserved)            /* Not used. */
147
{
148
    return TRUE;
149
}
150
#endif
151
#endif
152
 
153
/*
154
 *----------------------------------------------------------------------
155
 *
156
 * Registry_Init --
157
 *
158
 *      This procedure initializes the registry command.
159
 *
160
 * Results:
161
 *      A standard Tcl result.
162
 *
163
 * Side effects:
164
 *      None.
165
 *
166
 *----------------------------------------------------------------------
167
 */
168
 
169
int
170
Registry_Init(
171
    Tcl_Interp *interp)
172
{
173
    Tcl_CreateObjCommand(interp, "registry", RegistryObjCmd, NULL, NULL);
174
    return Tcl_PkgProvide(interp, "registry", "1.0");
175
}
176
 
177
/*
178
 *----------------------------------------------------------------------
179
 *
180
 * RegistryObjCmd --
181
 *
182
 *      This function implements the Tcl "registry" command.
183
 *
184
 * Results:
185
 *      A standard Tcl result.
186
 *
187
 * Side effects:
188
 *      None.
189
 *
190
 *----------------------------------------------------------------------
191
 */
192
 
193
static int
194
RegistryObjCmd(
195
    ClientData clientData,      /* Not used. */
196
    Tcl_Interp *interp,         /* Current interpreter. */
197
    int objc,                   /* Number of arguments. */
198
    Tcl_Obj * CONST objv[])     /* Argument values. */
199
{
200
    int index;
201
    char *errString;
202
 
203
    static char *subcommands[] = { "delete", "get", "keys", "set", "type",
204
                                   "values", (char *) NULL };
205
    enum SubCmdIdx { DeleteIdx, GetIdx, KeysIdx, SetIdx, TypeIdx, ValuesIdx };
206
 
207
    if (objc < 2) {
208
        Tcl_WrongNumArgs(interp, objc, objv, "option ?arg arg ...?");
209
        return TCL_ERROR;
210
    }
211
 
212
    if (Tcl_GetIndexFromObj(interp, objv[1], subcommands, "option", 0, &index)
213
            != TCL_OK) {
214
        return TCL_ERROR;
215
    }
216
 
217
    switch (index) {
218
        case DeleteIdx:                 /* delete */
219
            if (objc == 3) {
220
                return DeleteKey(interp, objv[2]);
221
            } else if (objc == 4) {
222
                return DeleteValue(interp, objv[2], objv[3]);
223
            }
224
            errString = "keyName ?valueName?";
225
            break;
226
        case GetIdx:                    /* get */
227
            if (objc == 4) {
228
                return GetValue(interp, objv[2], objv[3]);
229
            }
230
            errString = "keyName valueName";
231
            break;
232
        case KeysIdx:                   /* keys */
233
            if (objc == 3) {
234
                return GetKeyNames(interp, objv[2], NULL);
235
            } else if (objc == 4) {
236
                return GetKeyNames(interp, objv[2], objv[3]);
237
            }
238
            errString = "keyName ?pattern?";
239
            break;
240
        case SetIdx:                    /* set */
241
            if (objc == 3) {
242
                HKEY key;
243
 
244
                /*
245
                 * Create the key and then close it immediately.
246
                 */
247
 
248
                if (OpenKey(interp, objv[2], KEY_ALL_ACCESS, 1, &key)
249
                        != TCL_OK) {
250
                    return TCL_ERROR;
251
                }
252
                RegCloseKey(key);
253
                return TCL_OK;
254
            } else if (objc == 5 || objc == 6) {
255
                Tcl_Obj *typeObj = (objc == 5) ? NULL : objv[5];
256
                return SetValue(interp, objv[2], objv[3], objv[4], typeObj);
257
            }
258
            errString = "keyName ?valueName data ?type??";
259
            break;
260
        case TypeIdx:                   /* type */
261
            if (objc == 4) {
262
                return GetType(interp, objv[2], objv[3]);
263
            }
264
            errString = "keyName valueName";
265
            break;
266
        case ValuesIdx:                 /* values */
267
            if (objc == 3) {
268
                return GetValueNames(interp, objv[2], NULL);
269
            } else if (objc == 4) {
270
                return GetValueNames(interp, objv[2], objv[3]);
271
            }
272
            errString = "keyName ?pattern?";
273
            break;
274
    }
275
    Tcl_WrongNumArgs(interp, 2, objv, errString);
276
    return TCL_ERROR;
277
}
278
 
279
/*
280
 *----------------------------------------------------------------------
281
 *
282
 * DeleteKey --
283
 *
284
 *      This function deletes a registry key.
285
 *
286
 * Results:
287
 *      A standard Tcl result.
288
 *
289
 * Side effects:
290
 *      None.
291
 *
292
 *----------------------------------------------------------------------
293
 */
294
 
295
static int
296
DeleteKey(
297
    Tcl_Interp *interp,         /* Current interpreter. */
298
    Tcl_Obj *keyNameObj)        /* Name of key to delete. */
299
{
300
    char *tail, *buffer, *hostName, *keyName;
301
    HKEY rootKey, subkey;
302
    DWORD result;
303
    int length;
304
    Tcl_Obj *resultPtr;
305
 
306
    /*
307
     * Find the parent of the key being deleted and open it.
308
     */
309
 
310
    keyName = Tcl_GetStringFromObj(keyNameObj, &length);
311
    buffer = ckalloc(length + 1);
312
    strcpy(buffer, keyName);
313
 
314
    if (ParseKeyName(interp, buffer, &hostName, &rootKey, &keyName)
315
            != TCL_OK) {
316
        ckfree(buffer);
317
        return TCL_ERROR;
318
    }
319
 
320
    resultPtr = Tcl_GetObjResult(interp);
321
    if (*keyName == '\0') {
322
        Tcl_AppendToObj(resultPtr, "bad key: cannot delete root keys", -1);
323
        ckfree(buffer);
324
        return TCL_ERROR;
325
    }
326
 
327
    tail = strrchr(keyName, '\\');
328
    if (tail) {
329
        *tail++ = '\0';
330
    } else {
331
        tail = keyName;
332
        keyName = NULL;
333
    }
334
 
335
    result = OpenSubKey(hostName, rootKey, keyName,
336
            KEY_ENUMERATE_SUB_KEYS | DELETE, 0, &subkey);
337
    if (result != ERROR_SUCCESS) {
338
        ckfree(buffer);
339
        if (result == ERROR_FILE_NOT_FOUND) {
340
            return TCL_OK;
341
        } else {
342
            Tcl_AppendToObj(resultPtr, "unable to delete key: ", -1);
343
            AppendSystemError(interp, result);
344
            return TCL_ERROR;
345
        }
346
    }
347
 
348
    /*
349
     * Now we recursively delete the key and everything below it.
350
     */
351
 
352
    result = RecursiveDeleteKey(subkey, tail);
353
 
354
    if (result != ERROR_SUCCESS && result != ERROR_FILE_NOT_FOUND) {
355
        Tcl_AppendToObj(resultPtr, "unable to delete key: ", -1);
356
        AppendSystemError(interp, result);
357
        result = TCL_ERROR;
358
    } else {
359
        result = TCL_OK;
360
    }
361
 
362
    RegCloseKey(subkey);
363
    ckfree(buffer);
364
    return result;
365
}
366
 
367
/*
368
 *----------------------------------------------------------------------
369
 *
370
 * DeleteValue --
371
 *
372
 *      This function deletes a value from a registry key.
373
 *
374
 * Results:
375
 *      A standard Tcl result.
376
 *
377
 * Side effects:
378
 *      None.
379
 *
380
 *----------------------------------------------------------------------
381
 */
382
 
383
static int
384
DeleteValue(
385
    Tcl_Interp *interp,         /* Current interpreter. */
386
    Tcl_Obj *keyNameObj,        /* Name of key. */
387
    Tcl_Obj *valueNameObj)      /* Name of value to delete. */
388
{
389
    HKEY key;
390
    char *valueName;
391
    int length;
392
    DWORD result;
393
    Tcl_Obj *resultPtr;
394
 
395
    /*
396
     * Attempt to open the key for deletion.
397
     */
398
 
399
    if (OpenKey(interp, keyNameObj, KEY_SET_VALUE, 0, &key)
400
            != TCL_OK) {
401
        return TCL_ERROR;
402
    }
403
 
404
    resultPtr = Tcl_GetObjResult(interp);
405
    valueName = Tcl_GetStringFromObj(valueNameObj, &length);
406
    result = RegDeleteValue(key, valueName);
407
    if (result != ERROR_SUCCESS) {
408
        Tcl_AppendStringsToObj(resultPtr, "unable to delete value \"",
409
                Tcl_GetStringFromObj(valueNameObj, NULL), "\" from key \"",
410
                Tcl_GetStringFromObj(keyNameObj, NULL), "\": ", NULL);
411
        AppendSystemError(interp, result);
412
        result = TCL_ERROR;
413
    } else {
414
        result = TCL_OK;
415
    }
416
    RegCloseKey(key);
417
    return result;
418
}
419
 
420
/*
421
 *----------------------------------------------------------------------
422
 *
423
 * GetKeyNames --
424
 *
425
 *      This function enumerates the subkeys of a given key.  If the
426
 *      optional pattern is supplied, then only keys that match the
427
 *      pattern will be returned.
428
 *
429
 * Results:
430
 *      Returns the list of subkeys in the result object of the
431
 *      interpreter, or an error message on failure.
432
 *
433
 * Side effects:
434
 *      None.
435
 *
436
 *----------------------------------------------------------------------
437
 */
438
 
439
static int
440
GetKeyNames(
441
    Tcl_Interp *interp,         /* Current interpreter. */
442
    Tcl_Obj *keyNameObj,        /* Key to enumerate. */
443
    Tcl_Obj *patternObj)        /* Optional match pattern. */
444
{
445
    HKEY key;
446
    DWORD index;
447
    char buffer[MAX_PATH+1], *pattern;
448
    Tcl_Obj *resultPtr;
449
    int result = TCL_OK;
450
 
451
    /*
452
     * Attempt to open the key for enumeration.
453
     */
454
 
455
    if (OpenKey(interp, keyNameObj, KEY_ENUMERATE_SUB_KEYS, 0, &key)
456
            != TCL_OK) {
457
        return TCL_ERROR;
458
    }
459
 
460
    if (patternObj) {
461
        pattern = Tcl_GetStringFromObj(patternObj, NULL);
462
    } else {
463
        pattern = NULL;
464
    }
465
 
466
    /*
467
     * Enumerate over the subkeys until we get an error, indicating the
468
     * end of the list.
469
     */
470
 
471
    resultPtr = Tcl_GetObjResult(interp);
472
    for (index = 0; RegEnumKey(key, index, buffer, MAX_PATH+1)
473
             == ERROR_SUCCESS; index++) {
474
        if (pattern && !Tcl_StringMatch(buffer, pattern)) {
475
            continue;
476
        }
477
        result = Tcl_ListObjAppendElement(interp, resultPtr,
478
                Tcl_NewStringObj(buffer, -1));
479
        if (result != TCL_OK) {
480
            break;
481
        }
482
    }
483
 
484
    RegCloseKey(key);
485
    return result;
486
}
487
 
488
/*
489
 *----------------------------------------------------------------------
490
 *
491
 * GetType --
492
 *
493
 *      This function gets the type of a given registry value and
494
 *      places it in the interpreter result.
495
 *
496
 * Results:
497
 *      Returns a normal Tcl result.
498
 *
499
 * Side effects:
500
 *      None.
501
 *
502
 *----------------------------------------------------------------------
503
 */
504
 
505
static int
506
GetType(
507
    Tcl_Interp *interp,         /* Current interpreter. */
508
    Tcl_Obj *keyNameObj,        /* Name of key. */
509
    Tcl_Obj *valueNameObj)      /* Name of value to get. */
510
{
511
    HKEY key;
512
    Tcl_Obj *resultPtr;
513
    DWORD result;
514
    DWORD type;
515
 
516
    /*
517
     * Attempt to open the key for reading.
518
     */
519
 
520
    if (OpenKey(interp, keyNameObj, KEY_QUERY_VALUE, 0, &key)
521
            != TCL_OK) {
522
        return TCL_ERROR;
523
    }
524
 
525
    /*
526
     * Get the type of the value.
527
     */
528
 
529
    resultPtr = Tcl_GetObjResult(interp);
530
 
531
    result = RegQueryValueEx(key, Tcl_GetStringFromObj(valueNameObj, NULL),
532
            NULL, &type, NULL, NULL);
533
    RegCloseKey(key);
534
 
535
    if (result != ERROR_SUCCESS) {
536
        Tcl_AppendStringsToObj(resultPtr, "unable to get type of value \"",
537
                Tcl_GetStringFromObj(valueNameObj, NULL), "\" from key \"",
538
                Tcl_GetStringFromObj(keyNameObj, NULL), "\": ", NULL);
539
        AppendSystemError(interp, result);
540
        return TCL_ERROR;
541
    }
542
 
543
    /*
544
     * Set the type into the result.  Watch out for unknown types.
545
     * If we don't know about the type, just use the numeric value.
546
     */
547
 
548
    if (type > lastType || type < 0) {
549
        Tcl_SetIntObj(resultPtr, type);
550
    } else {
551
        Tcl_SetStringObj(resultPtr, typeNames[type], -1);
552
    }
553
    return TCL_OK;
554
}
555
 
556
/*
557
 *----------------------------------------------------------------------
558
 *
559
 * GetValue --
560
 *
561
 *      This function gets the contents of a registry value and places
562
 *      a list containing the data and the type in the interpreter
563
 *      result.
564
 *
565
 * Results:
566
 *      Returns a normal Tcl result.
567
 *
568
 * Side effects:
569
 *      None.
570
 *
571
 *----------------------------------------------------------------------
572
 */
573
 
574
static int
575
GetValue(
576
    Tcl_Interp *interp,         /* Current interpreter. */
577
    Tcl_Obj *keyNameObj,        /* Name of key. */
578
    Tcl_Obj *valueNameObj)      /* Name of value to get. */
579
{
580
    HKEY key;
581
    char *valueName;
582
    DWORD result, length, type;
583
    Tcl_Obj *resultPtr;
584
    Tcl_DString data;
585
 
586
    /*
587
     * Attempt to open the key for reading.
588
     */
589
 
590
    if (OpenKey(interp, keyNameObj, KEY_QUERY_VALUE, 0, &key)
591
            != TCL_OK) {
592
        return TCL_ERROR;
593
    }
594
 
595
    /*
596
     * Initialize a Dstring to maximum statically allocated size
597
     * we could get one more byte by avoiding Tcl_DStringSetLength()
598
     * and just setting length to TCL_DSTRING_STATIC_SIZE, but this
599
     * should be safer if the implementation Dstrings changes.
600
     *
601
     * This allows short values to be read from the registy in one call.
602
     * Longer values need a second call with an expanded DString.
603
     */
604
 
605
    Tcl_DStringInit(&data);
606
    Tcl_DStringSetLength(&data, length = TCL_DSTRING_STATIC_SIZE - 1);
607
 
608
    resultPtr = Tcl_GetObjResult(interp);
609
 
610
    valueName = Tcl_GetStringFromObj(valueNameObj, NULL);
611
    result = RegQueryValueEx(key, valueName, NULL, &type,
612
            (LPBYTE) Tcl_DStringValue(&data), &length);
613
    if (result == ERROR_MORE_DATA) {
614
        Tcl_DStringSetLength(&data, length);
615
        result = RegQueryValueEx(key, valueName, NULL, &type,
616
                (LPBYTE) Tcl_DStringValue(&data), &length);
617
    }
618
    RegCloseKey(key);
619
    if (result != ERROR_SUCCESS) {
620
        Tcl_AppendStringsToObj(resultPtr, "unable to get value \"",
621
                Tcl_GetStringFromObj(valueNameObj, NULL), "\" from key \"",
622
                Tcl_GetStringFromObj(keyNameObj, NULL), "\": ", NULL);
623
        AppendSystemError(interp, result);
624
        Tcl_DStringFree(&data);
625
        return TCL_ERROR;
626
    }
627
 
628
    /*
629
     * If the data is a 32-bit quantity, store it as an integer object.  If it
630
     * is a multi-string, store it as a list of strings.  For null-terminated
631
     * strings, append up the to first null.  Otherwise, store it as a binary
632
     * string.
633
     */
634
 
635
    if (type == REG_DWORD || type == REG_DWORD_BIG_ENDIAN) {
636
        Tcl_SetIntObj(resultPtr, ConvertDWORD(type,
637
                *((DWORD*) Tcl_DStringValue(&data))));
638
    } else if (type == REG_MULTI_SZ) {
639
        char *p = Tcl_DStringValue(&data);
640
        char *lastChar = Tcl_DStringValue(&data) + Tcl_DStringLength(&data);
641
 
642
        /*
643
         * Multistrings are stored as an array of null-terminated strings,
644
         * terminated by two null characters.  Also do a bounds check in
645
         * case we get bogus data.
646
         */
647
 
648
        while (p < lastChar && *p != '\0') {
649
            Tcl_ListObjAppendElement(interp, resultPtr,
650
                    Tcl_NewStringObj(p, -1));
651
            while (*p++ != '\0') {}
652
        }
653
    } else if ((type == REG_SZ) || (type == REG_EXPAND_SZ)) {
654
        Tcl_SetStringObj(resultPtr, Tcl_DStringValue(&data), -1);
655
    } else {
656
        Tcl_SetStringObj(resultPtr, Tcl_DStringValue(&data), length);
657
    }
658
    Tcl_DStringFree(&data);
659
    return result;
660
}
661
 
662
/*
663
 *----------------------------------------------------------------------
664
 *
665
 * GetValueNames --
666
 *
667
 *      This function enumerates the values of the a given key.  If
668
 *      the optional pattern is supplied, then only value names that
669
 *      match the pattern will be returned.
670
 *
671
 * Results:
672
 *      Returns the list of value names in the result object of the
673
 *      interpreter, or an error message on failure.
674
 *
675
 * Side effects:
676
 *      None.
677
 *
678
 *----------------------------------------------------------------------
679
 */
680
 
681
static int
682
GetValueNames(
683
    Tcl_Interp *interp,         /* Current interpreter. */
684
    Tcl_Obj *keyNameObj,        /* Key to enumerate. */
685
    Tcl_Obj *patternObj)        /* Optional match pattern. */
686
{
687
    HKEY key;
688
    Tcl_Obj *resultPtr;
689
    DWORD index, size, result;
690
    Tcl_DString buffer;
691
    char *pattern;
692
 
693
    /*
694
     * Attempt to open the key for enumeration.
695
     */
696
 
697
    if (OpenKey(interp, keyNameObj, KEY_QUERY_VALUE, 0, &key)
698
            != TCL_OK) {
699
        return TCL_ERROR;
700
    }
701
 
702
    resultPtr = Tcl_GetObjResult(interp);
703
 
704
    /*
705
     * Query the key to determine the appropriate buffer size to hold the
706
     * largest value name plus the terminating null.
707
     */
708
 
709
    result = RegQueryInfoKey(key, NULL, NULL, NULL, NULL, NULL, NULL, &index,
710
        &size, NULL, NULL, NULL);
711
    if (result != ERROR_SUCCESS) {
712
        Tcl_AppendStringsToObj(resultPtr, "unable to query key \"",
713
                Tcl_GetStringFromObj(keyNameObj, NULL), "\": ", NULL);
714
        AppendSystemError(interp, result);
715
        RegCloseKey(key);
716
        result = TCL_ERROR;
717
        goto done;
718
    }
719
    size++;
720
 
721
 
722
    Tcl_DStringInit(&buffer);
723
    Tcl_DStringSetLength(&buffer, size);
724
    index = 0;
725
    result = TCL_OK;
726
 
727
    if (patternObj) {
728
        pattern = Tcl_GetStringFromObj(patternObj, NULL);
729
    } else {
730
        pattern = NULL;
731
    }
732
 
733
    /*
734
     * Enumerate the values under the given subkey until we get an error,
735
     * indicating the end of the list.  Note that we need to reset size
736
     * after each iteration because RegEnumValue smashes the old value.
737
     */
738
 
739
    while (RegEnumValue(key, index, Tcl_DStringValue(&buffer), &size, NULL,
740
            NULL, NULL, NULL) == ERROR_SUCCESS) {
741
        if (!pattern || Tcl_StringMatch(Tcl_DStringValue(&buffer), pattern)) {
742
            result = Tcl_ListObjAppendElement(interp, resultPtr,
743
                    Tcl_NewStringObj(Tcl_DStringValue(&buffer), size));
744
            if (result != TCL_OK) {
745
                break;
746
            }
747
        }
748
        index++;
749
        size = Tcl_DStringLength(&buffer);
750
    }
751
    Tcl_DStringFree(&buffer);
752
 
753
    done:
754
    RegCloseKey(key);
755
    return result;
756
}
757
 
758
/*
759
 *----------------------------------------------------------------------
760
 *
761
 * OpenKey --
762
 *
763
 *      This function opens the specified key.  This function is a
764
 *      simple wrapper around ParseKeyName and OpenSubKey.
765
 *
766
 * Results:
767
 *      Returns the opened key in the keyPtr argument and a Tcl
768
 *      result code.
769
 *
770
 * Side effects:
771
 *      None.
772
 *
773
 *----------------------------------------------------------------------
774
 */
775
 
776
static int
777
OpenKey(
778
    Tcl_Interp *interp,         /* Current interpreter. */
779
    Tcl_Obj *keyNameObj,        /* Key to open. */
780
    REGSAM mode,                /* Access mode. */
781
    int flags,                  /* 0 or REG_CREATE. */
782
    HKEY *keyPtr)               /* Returned HKEY. */
783
{
784
    char *keyName, *buffer, *hostName;
785
    int length;
786
    HKEY rootKey;
787
    DWORD result;
788
 
789
    keyName = Tcl_GetStringFromObj(keyNameObj, &length);
790
    buffer = ckalloc(length + 1);
791
    strcpy(buffer, keyName);
792
 
793
    result = ParseKeyName(interp, buffer, &hostName, &rootKey, &keyName);
794
    if (result == TCL_OK) {
795
        result = OpenSubKey(hostName, rootKey, keyName, mode, flags, keyPtr);
796
        if (result != ERROR_SUCCESS) {
797
            Tcl_Obj *resultPtr = Tcl_GetObjResult(interp);
798
            Tcl_AppendToObj(resultPtr, "unable to open key: ", -1);
799
            AppendSystemError(interp, result);
800
            result = TCL_ERROR;
801
        } else {
802
            result = TCL_OK;
803
        }
804
    }
805
 
806
    ckfree(buffer);
807
    return result;
808
}
809
 
810
/*
811
 *----------------------------------------------------------------------
812
 *
813
 * OpenSubKey --
814
 *
815
 *      This function opens a given subkey of a root key on the
816
 *      specified host.
817
 *
818
 * Results:
819
 *      Returns the opened key in the keyPtr and a Windows error code
820
 *      as the return value.
821
 *
822
 * Side effects:
823
 *      None.
824
 *
825
 *----------------------------------------------------------------------
826
 */
827
 
828
static DWORD
829
OpenSubKey(
830
    char *hostName,             /* Host to access, or NULL for local. */
831
    HKEY rootKey,               /* Root registry key. */
832
    char *keyName,              /* Subkey name. */
833
    REGSAM mode,                /* Access mode. */
834
    int flags,                  /* 0 or REG_CREATE. */
835
    HKEY *keyPtr)               /* Returned HKEY. */
836
{
837
    DWORD result;
838
 
839
    /*
840
     * Attempt to open the root key on a remote host if necessary.
841
     */
842
 
843
    if (hostName) {
844
        result = RegConnectRegistry(hostName, rootKey, &rootKey);
845
        if (result != ERROR_SUCCESS) {
846
            return result;
847
        }
848
    }
849
 
850
    /*
851
     * Now open the specified key with the requested permissions.  Note
852
     * that this key must be closed by the caller.
853
     */
854
 
855
    if (flags & REG_CREATE) {
856
        DWORD create;
857
        result = RegCreateKeyEx(rootKey, keyName, 0, "",
858
                REG_OPTION_NON_VOLATILE, mode, NULL, keyPtr, &create);
859
    } else {
860
        result = RegOpenKeyEx(rootKey, keyName, 0, mode, keyPtr);
861
    }
862
 
863
    /*
864
     * Be sure to close the root key since we are done with it now.
865
     */
866
 
867
    if (hostName) {
868
        RegCloseKey(rootKey);
869
    }
870
    return result;
871
}
872
 
873
/*
874
 *----------------------------------------------------------------------
875
 *
876
 * ParseKeyName --
877
 *
878
 *      This function parses a key name into the host, root, and subkey
879
 *      parts.
880
 *
881
 * Results:
882
 *      The pointers to the start of the host and subkey names are
883
 *      returned in the hostNamePtr and keyNamePtr variables.  The
884
 *      specified root HKEY is returned in rootKeyPtr.  Returns
885
 *      a standard Tcl result.
886
 *
887
 *
888
 * Side effects:
889
 *      Modifies the name string by inserting nulls.
890
 *
891
 *----------------------------------------------------------------------
892
 */
893
 
894
static int
895
ParseKeyName(
896
    Tcl_Interp *interp,         /* Current interpreter. */
897
    char *name,
898
    char **hostNamePtr,
899
    HKEY *rootKeyPtr,
900
    char **keyNamePtr)
901
{
902
    char *rootName;
903
    int result, index;
904
    Tcl_Obj *rootObj, *resultPtr = Tcl_GetObjResult(interp);
905
 
906
    /*
907
     * Split the key into host and root portions.
908
     */
909
 
910
    *hostNamePtr = *keyNamePtr = rootName = NULL;
911
    if (name[0] == '\\') {
912
        if (name[1] == '\\') {
913
            *hostNamePtr = name;
914
            for (rootName = name+2; *rootName != '\0'; rootName++) {
915
                if (*rootName == '\\') {
916
                    *rootName++ = '\0';
917
                    break;
918
                }
919
            }
920
        }
921
    } else {
922
        rootName = name;
923
    }
924
    if (!rootName) {
925
        Tcl_AppendStringsToObj(resultPtr, "bad key \"", name,
926
                "\": must start with a valid root", NULL);
927
        return TCL_ERROR;
928
    }
929
 
930
    /*
931
     * Split the root into root and subkey portions.
932
     */
933
 
934
    for (*keyNamePtr = rootName; **keyNamePtr != '\0'; (*keyNamePtr)++) {
935
        if (**keyNamePtr == '\\') {
936
            **keyNamePtr = '\0';
937
            (*keyNamePtr)++;
938
            break;
939
        }
940
    }
941
 
942
    /*
943
     * Look for a matching root name.
944
     */
945
 
946
    rootObj = Tcl_NewStringObj(rootName, -1);
947
    result = Tcl_GetIndexFromObj(interp, rootObj, rootKeyNames, "root name",
948
            TCL_EXACT, &index);
949
    Tcl_DecrRefCount(rootObj);
950
    if (result != TCL_OK) {
951
        return TCL_ERROR;
952
    }
953
    *rootKeyPtr = rootKeys[index];
954
    return TCL_OK;
955
}
956
 
957
/*
958
 *----------------------------------------------------------------------
959
 *
960
 * RecursiveDeleteKey --
961
 *
962
 *      This function recursively deletes all the keys below a starting
963
 *      key.  Although Windows 95 does this automatically, we still need
964
 *      to do this for Windows NT.
965
 *
966
 * Results:
967
 *      Returns a Windows error code.
968
 *
969
 * Side effects:
970
 *      Deletes all of the keys and values below the given key.
971
 *
972
 *----------------------------------------------------------------------
973
 */
974
 
975
static DWORD
976
RecursiveDeleteKey(
977
    HKEY startKey,              /* Parent of key to be deleted. */
978
    char *keyName)              /* Name of key to be deleted. */
979
{
980
    DWORD result, subKeyLength;
981
    Tcl_DString subkey;
982
    HKEY hKey;
983
 
984
    /*
985
     * Do not allow NULL or empty key name.
986
     */
987
 
988
    if (!keyName || lstrlen(keyName) == '\0') {
989
        return ERROR_BADKEY;
990
    }
991
 
992
    result = RegOpenKeyEx(startKey, keyName, 0,
993
            KEY_ENUMERATE_SUB_KEYS | DELETE | KEY_QUERY_VALUE, &hKey);
994
    if (result != ERROR_SUCCESS) {
995
        return result;
996
    }
997
    result = RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, &subKeyLength,
998
            NULL, NULL, NULL, NULL, NULL, NULL);
999
    subKeyLength++;
1000
    if (result != ERROR_SUCCESS) {
1001
        return result;
1002
    }
1003
 
1004
    Tcl_DStringInit(&subkey);
1005
    Tcl_DStringSetLength(&subkey, subKeyLength);
1006
 
1007
    while (result == ERROR_SUCCESS) {
1008
        /*
1009
         * Always get index 0 because key deletion changes ordering.
1010
         */
1011
 
1012
        subKeyLength = Tcl_DStringLength(&subkey);
1013
        result=RegEnumKeyEx(hKey, 0, Tcl_DStringValue(&subkey), &subKeyLength,
1014
                NULL, NULL, NULL, NULL);
1015
        if (result == ERROR_NO_MORE_ITEMS) {
1016
            result = RegDeleteKey(startKey, keyName);
1017
            break;
1018
        } else if (result == ERROR_SUCCESS) {
1019
            result = RecursiveDeleteKey(hKey, Tcl_DStringValue(&subkey));
1020
        }
1021
    }
1022
    Tcl_DStringFree(&subkey);
1023
    RegCloseKey(hKey);
1024
    return result;
1025
}
1026
 
1027
/*
1028
 *----------------------------------------------------------------------
1029
 *
1030
 * SetValue --
1031
 *
1032
 *      This function sets the contents of a registry value.  If
1033
 *      the key or value does not exist, it will be created.  If it
1034
 *      does exist, then the data and type will be replaced.
1035
 *
1036
 * Results:
1037
 *      Returns a normal Tcl result.
1038
 *
1039
 * Side effects:
1040
 *      May create new keys or values.
1041
 *
1042
 *----------------------------------------------------------------------
1043
 */
1044
 
1045
static int
1046
SetValue(
1047
    Tcl_Interp *interp,         /* Current interpreter. */
1048
    Tcl_Obj *keyNameObj,        /* Name of key. */
1049
    Tcl_Obj *valueNameObj,      /* Name of value to set. */
1050
    Tcl_Obj *dataObj,           /* Data to be written. */
1051
    Tcl_Obj *typeObj)           /* Type of data to be written. */
1052
{
1053
    DWORD type, result;
1054
    HKEY key;
1055
    int length;
1056
    char *valueName;
1057
    Tcl_Obj *resultPtr;
1058
 
1059
    if (typeObj == NULL) {
1060
        type = REG_SZ;
1061
    } else if (Tcl_GetIndexFromObj(interp, typeObj, typeNames, "type",
1062
            0, (int *) &type) != TCL_OK) {
1063
        if (Tcl_GetIntFromObj(NULL, typeObj, (int*) &type) != TCL_OK) {
1064
            return TCL_ERROR;
1065
        }
1066
        Tcl_ResetResult(interp);
1067
    }
1068
    if (OpenKey(interp, keyNameObj, KEY_ALL_ACCESS, 1, &key) != TCL_OK) {
1069
        return TCL_ERROR;
1070
    }
1071
 
1072
    valueName = Tcl_GetStringFromObj(valueNameObj, &length);
1073
    resultPtr = Tcl_GetObjResult(interp);
1074
 
1075
    if (type == REG_DWORD || type == REG_DWORD_BIG_ENDIAN) {
1076
        DWORD value;
1077
        if (Tcl_GetIntFromObj(interp, dataObj, (int*) &value) != TCL_OK) {
1078
            RegCloseKey(key);
1079
            return TCL_ERROR;
1080
        }
1081
 
1082
        value = ConvertDWORD(type, value);
1083
        result = RegSetValueEx(key, valueName, 0, type, (BYTE*) &value,
1084
                sizeof(DWORD));
1085
    } else if (type == REG_MULTI_SZ) {
1086
        Tcl_DString data;
1087
        int objc, i;
1088
        Tcl_Obj **objv;
1089
        char *element;
1090
 
1091
        if (Tcl_ListObjGetElements(interp, dataObj, &objc, &objv) != TCL_OK) {
1092
            RegCloseKey(key);
1093
            return TCL_ERROR;
1094
        }
1095
 
1096
        /*
1097
         * Append the elements as null terminated strings.  Note that
1098
         * we must not assume the length of the string in case there are
1099
         * embedded nulls, which aren't allowed in REG_MULTI_SZ values.
1100
         */
1101
 
1102
        Tcl_DStringInit(&data);
1103
        for (i = 0; i < objc; i++) {
1104
            element = Tcl_GetStringFromObj(objv[i], NULL);
1105
            Tcl_DStringAppend(&data, element, -1);
1106
            Tcl_DStringSetLength(&data, Tcl_DStringLength(&data)+1);
1107
        }
1108
        result = RegSetValueEx(key, valueName, 0, type,
1109
                (LPBYTE) Tcl_DStringValue(&data),
1110
                (DWORD) (Tcl_DStringLength(&data)+1));
1111
        Tcl_DStringFree(&data);
1112
    } else {
1113
        char *data = Tcl_GetStringFromObj(dataObj, &length);
1114
 
1115
        /*
1116
         * Include the null in the length if we are storing a null terminated
1117
         * string.  Note that we also need to call strlen to find the first
1118
         * null so we don't pass bad data to the registry.
1119
         */
1120
 
1121
        if (type == REG_SZ || type == REG_EXPAND_SZ) {
1122
            length = strlen(data) + 1;
1123
        }
1124
 
1125
        result = RegSetValueEx(key, valueName, 0, type, (LPBYTE)data, length);
1126
    }
1127
    RegCloseKey(key);
1128
    if (result != ERROR_SUCCESS) {
1129
        Tcl_AppendToObj(resultPtr, "unable to set value: ", -1);
1130
        AppendSystemError(interp, result);
1131
        return TCL_ERROR;
1132
    }
1133
    return TCL_OK;
1134
}
1135
 
1136
/*
1137
 *----------------------------------------------------------------------
1138
 *
1139
 * AppendSystemError --
1140
 *
1141
 *      This routine formats a Windows system error message and places
1142
 *      it into the interpreter result.
1143
 *
1144
 * Results:
1145
 *      None.
1146
 *
1147
 * Side effects:
1148
 *      None.
1149
 *
1150
 *----------------------------------------------------------------------
1151
 */
1152
 
1153
static void
1154
AppendSystemError(
1155
    Tcl_Interp *interp,         /* Current interpreter. */
1156
    DWORD error)                /* Result code from error. */
1157
{
1158
    int length;
1159
    char *msgbuf, id[10];
1160
    Tcl_Obj *resultPtr = Tcl_GetObjResult(interp);
1161
 
1162
    sprintf(id, "%d", error);
1163
    length = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
1164
            | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, error,
1165
            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&msgbuf,
1166
            0, NULL);
1167
    if (length == 0) {
1168
        if (error == ERROR_CALL_NOT_IMPLEMENTED) {
1169
            msgbuf = "function not supported under Win32s";
1170
        } else {
1171
            msgbuf = id;
1172
        }
1173
    } else {
1174
        /*
1175
         * Trim the trailing CR/LF from the system message.
1176
         */
1177
        if (msgbuf[length-1] == '\n') {
1178
            msgbuf[--length] = 0;
1179
        }
1180
        if (msgbuf[length-1] == '\r') {
1181
            msgbuf[--length] = 0;
1182
        }
1183
    }
1184
    Tcl_SetErrorCode(interp, "WINDOWS", id, msgbuf, (char *) NULL);
1185
    Tcl_AppendToObj(resultPtr, msgbuf, -1);
1186
 
1187
    if (length != 0) {
1188
        LocalFree(msgbuf);
1189
    }
1190
}
1191
 
1192
/*
1193
 *----------------------------------------------------------------------
1194
 *
1195
 * ConvertDWORD --
1196
 *
1197
 *      This function determines whether a DWORD needs to be byte
1198
 *      swapped, and returns the appropriately swapped value.
1199
 *
1200
 * Results:
1201
 *      Returns a converted DWORD.
1202
 *
1203
 * Side effects:
1204
 *      None.
1205
 *
1206
 *----------------------------------------------------------------------
1207
 */
1208
 
1209
static DWORD
1210
ConvertDWORD(
1211
    DWORD type,                 /* Either REG_DWORD or REG_DWORD_BIG_ENDIAN */
1212
    DWORD value)                /* The value to be converted. */
1213
{
1214
    DWORD order = 1;
1215
    DWORD localType;
1216
 
1217
    /*
1218
     * Check to see if the low bit is in the first byte.
1219
     */
1220
 
1221
    localType = (*((char*)(&order)) == 1) ? REG_DWORD : REG_DWORD_BIG_ENDIAN;
1222
    return (type != localType) ? SWAPLONG(value) : value;
1223
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.