source: trunk/src/helpers/xprf.c@ 59

Last change on this file since 59 was 21, checked in by umoeller, 25 years ago

Final changes for 0.9.7, i hope...

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 31.3 KB
Line 
1
2/*
3 *@@sourcefile xprf.c:
4 * contains replacement profile (INI) functions.
5 * This file is new with V0.9.5 (2000-08-10) [umoeller].
6 *
7 * These functions are quite similar to the regular Prf*
8 * APIs, with the following advantages:
9 *
10 * -- They do not use shared memory, but the default
11 * memory allocation functions (malloc() etc.).
12 * This greatly reduces the pressure on the process's
13 * address space which apparently the default Prf*
14 * functions are causing with large INI files.
15 *
16 * -- Profiles are written out to disk in one flush, not
17 * in the 32 KB chunks that the regular Prf* functions
18 * use.
19 *
20 * Other differences:
21 *
22 * -- They cannot be used interchangably. Once you open
23 * a profile using xprfOpenProfile, you must use the
24 * extended functions.
25 *
26 * -- The INI file is kept open after xprfOpenProfile
27 * until xprfCloseProfile is called. Besides, we use
28 * DosProtectOpen so that a second open of the same INI
29 * file will always fail until xprfCloseProfile is called
30 * (sorta like a mutex for profiles).
31 * This is independent of the process or thread which
32 * is doing the second open.
33 *
34 * This is because since we are not using shared memory,
35 * some other sort of protection had to be introduced
36 * to make sure no two processes operate on the same INI.
37 *
38 * Still, these functions are NOT thread-safe for the same profile.
39 * If you open the profile on one thread and write and read
40 * concurrently on two threads, there's no protection, and everything
41 * will blow up. The functions are reeantrant though, so for different
42 * profiles there will be no problems.
43 *
44 * -- All changes to the INI files using xprfWriteProfileData
45 * are only made to the file in memory. Only xprfCloseProfile
46 * will flush the changes to disk. (I am not sure how the
47 * default PrfCloseProfile handles this on files other than
48 * HINI_USER and HINI_SYSTEM.)
49 *
50 * -- HINI_USER and HINI_SYSTEM don't work. To retrieve data
51 * from them, use the standard Prf* functions. You can however
52 * use the new functions to create a duplicate of these files.
53 *
54 * -- One similarity: All data items are limited to 64K,
55 * as with the standard profiles. This is not a limitation
56 * of the code, but of the INI file format, which uses
57 * USHORT's for all item length specifications.
58 *
59 * Thanks go out to Carsten Arnold for sending the INI file
60 * format information (xprf.h) to me, which enabled me to
61 * create this in the first place.
62 *
63 * Usage: All OS/2 programs.
64 *
65 * Function prefixes:
66 * -- xprf* replacement profile (INI) functions
67 *
68 * Note: Version numbering in this file relates to XWorkplace version
69 * numbering.
70 *
71 *@@header "helpers\xprf.h"
72 *@@added V0.9.5 (2000-08-10) [umoeller]
73 */
74
75/*
76 * Copyright (C) 2000 Ulrich M”ller.
77 * This file is part of the "XWorkplace helpers" source package.
78 * This is free software; you can redistribute it and/or modify
79 * it under the terms of the GNU General Public License as published
80 * by the Free Software Foundation, in version 2 as it comes in the
81 * "COPYING" file of the XWorkplace main distribution.
82 * This program is distributed in the hope that it will be useful,
83 * but WITHOUT ANY WARRANTY; without even the implied warranty of
84 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
85 * GNU General Public License for more details.
86 */
87
88#define OS2EMX_PLAIN_CHAR
89 // this is needed for "os2emx.h"; if this is defined,
90 // emx will define PSZ as _signed_ char, otherwise
91 // as unsigned char
92
93#define INCL_DOSERRORS
94#define INCL_WINSHELLDATA
95#include <os2.h>
96
97#include <stdlib.h>
98#include <stdio.h>
99#include <string.h>
100
101#include "setup.h" // code generation and debugging options
102
103#include "helpers\linklist.h"
104#include "helpers\prfh.h"
105#include "helpers\xprf.h"
106
107#pragma hdrstop
108
109/*
110 *@@category: Helpers\Profile (INI) replacement functions
111 * See xprf.c.
112 */
113
114/* ******************************************************************
115 *
116 * Declarations
117 *
118 ********************************************************************/
119
120/*
121 *@@ XINIAPPDATA:
122 * application structure in XINI.
123 */
124
125typedef struct _XINIAPPDATA
126{
127 PSZ pszAppName;
128 LINKLIST llKeys; // contains PXINIKEYDATA pointers
129 ULONG cKeys; // count of items on list
130} XINIAPPDATA, *PXINIAPPDATA;
131
132/*
133 *@@ XINIKEYDATA:
134 * key/data structure in XINIAPPDATA.
135 */
136
137typedef struct _XINIKEYDATA
138{
139 PSZ pszKeyName;
140 PBYTE pbData;
141 ULONG cbData;
142} XINIKEYDATA, *PXINIKEYDATA;
143
144/* ******************************************************************
145 *
146 * Helpers
147 *
148 ********************************************************************/
149
150/*
151 * FindApp:
152 * attempts to find the specified application
153 * in the given profile data.
154 * Returns NULL if not found.
155 *
156 * Private helper.
157 */
158
159PXINIAPPDATA FindApp(PXINI pXIni, // in: profile opened with xprfOpenProfile
160 const char *pcszApp)
161{
162 PXINIAPPDATA pReturn = NULL;
163 PLISTNODE pAppNode = lstQueryFirstNode(&pXIni->llApps);
164 while (pAppNode)
165 {
166 PXINIAPPDATA pAppDataThis = (PXINIAPPDATA)pAppNode->pItemData;
167 if (strcmp(pAppDataThis->pszAppName, pcszApp) == 0)
168 {
169 pReturn = pAppDataThis;
170 break;
171 }
172
173 pAppNode = pAppNode->pNext;
174 }
175
176 return (pReturn);
177}
178
179/*
180 * CreateApp:
181 * creates a new application in the specified
182 * profile structure and appends it to the list.
183 * This does NOT check for whether the app is
184 * already in the profile.
185 *
186 * Private helper.
187 */
188
189PXINIAPPDATA CreateApp(PXINI pXIni, // in: profile opened with xprfOpenProfile
190 const char *pcszApp)
191{
192 PXINIAPPDATA pAppData = (PXINIAPPDATA)malloc(sizeof(XINIAPPDATA));
193 if (pAppData)
194 {
195 pAppData->pszAppName = strdup(pcszApp);
196 lstInit(&pAppData->llKeys, FALSE);
197 pAppData->cKeys = 0;
198
199 // store in INI's apps list
200 lstAppendItem(&pXIni->llApps, pAppData);
201 pXIni->cApps++;
202 }
203
204 return (pAppData);
205}
206
207/*
208 * FindKey:
209 * attempts to find the specified key
210 * in the given application.
211 * Returns NULL if not found.
212 *
213 * Private helper.
214 */
215
216PXINIKEYDATA FindKey(PXINIAPPDATA pAppData,
217 const char *pcszKey)
218{
219 PXINIKEYDATA pReturn = NULL;
220 PLISTNODE pKeyNode = lstQueryFirstNode(&pAppData->llKeys);
221 while (pKeyNode)
222 {
223 PXINIKEYDATA pKeyDataThis = (PXINIKEYDATA)pKeyNode->pItemData;
224 if (strcmp(pKeyDataThis->pszKeyName, pcszKey) == 0)
225 {
226 pReturn = pKeyDataThis;
227 break;
228 }
229
230 pKeyNode = pKeyNode->pNext;
231 }
232
233 return (pReturn);
234}
235
236/*
237 * CreateKey:
238 * creates a new key in the specified application
239 * structure and appends it to the list.
240 * This does NOT check for whether the key is
241 * already in the application.
242 *
243 * Private helper.
244 */
245
246PXINIKEYDATA CreateKey(PXINIAPPDATA pAppData,
247 const char *pcszKey, // in: key name
248 PBYTE pbData, // in: data for key
249 ULONG cbData) // in: sizeof (*pbData)
250{
251 PXINIKEYDATA pKeyData = (PXINIKEYDATA)malloc(sizeof(XINIKEYDATA));
252 if (pKeyData)
253 {
254 pKeyData->pszKeyName = strdup(pcszKey);
255
256 pKeyData->pbData = (PBYTE)malloc(cbData);
257 if (pKeyData->pbData)
258 {
259 memcpy(pKeyData->pbData, pbData, cbData);
260 pKeyData->cbData = cbData;
261 // store in app's keys list
262 lstAppendItem(&pAppData->llKeys, pKeyData);
263 pAppData->cKeys++;
264 }
265 else
266 {
267 // malloc failed:
268 free(pKeyData);
269 pKeyData = 0;
270 }
271 }
272
273 return (pKeyData);
274}
275
276/*
277 * FreeKey:
278 * frees the specified key. Does not remove
279 * the key from the keys list in XINIAPPDATA
280 * however.
281 *
282 * Private helper.
283 */
284
285VOID FreeKey(PXINIKEYDATA pKeyDataThis)
286{
287 if (pKeyDataThis->pszKeyName)
288 free(pKeyDataThis->pszKeyName);
289 if (pKeyDataThis->pbData)
290 free(pKeyDataThis->pbData);
291 free(pKeyDataThis);
292}
293
294/*
295 * FreeApp:
296 * frees the specified application. Does not remove
297 * the application from the application list in XINI
298 * however.
299 *
300 * Private helper.
301 */
302
303VOID FreeApp(PXINIAPPDATA pAppDataThis)
304{
305 PLISTNODE pKeyNode = lstQueryFirstNode(&pAppDataThis->llKeys);
306 while (pKeyNode)
307 {
308 PXINIKEYDATA pKeyDataThis = (PXINIKEYDATA)pKeyNode->pItemData;
309
310 FreeKey(pKeyDataThis);
311
312 pKeyNode = pKeyNode->pNext;
313 }
314
315 if (pAppDataThis->pszAppName)
316 free(pAppDataThis->pszAppName);
317
318 lstClear(&pAppDataThis->llKeys);
319
320 free(pAppDataThis);
321}
322
323/*
324 * FreeINI:
325 * cleans up the specified ini structure entirely.
326 *
327 * Private helper.
328 */
329
330BOOL FreeINI(PXINI pXIni) // in: profile opened with xprfOpenProfile
331{
332 BOOL brc = FALSE;
333
334 if (pXIni)
335 {
336 PLISTNODE pAppNode = lstQueryFirstNode(&pXIni->llApps);
337 while (pAppNode)
338 {
339 PXINIAPPDATA pAppDataThis = (PXINIAPPDATA)pAppNode->pItemData;
340
341 FreeApp(pAppDataThis);
342
343 pAppNode = pAppNode->pNext;
344 }
345
346 lstClear(&pXIni->llApps);
347 free(pXIni);
348 }
349
350 return (brc);
351}
352
353/* ******************************************************************
354 *
355 * Read/write data
356 *
357 ********************************************************************/
358
359/*
360 * ReadINI:
361 * reads in the entire INI file from disk and
362 * initializes all internal data structures.
363 *
364 * Private helper.
365 */
366
367BOOL ReadINI(PXINI pXIni) // in: profile opened with xprfOpenProfile
368{
369 BOOL brc = FALSE;
370 FILESTATUS3 fs3;
371
372 if (DosProtectQueryFileInfo(pXIni->hFile,
373 FIL_STANDARD,
374 &fs3,
375 sizeof(fs3),
376 pXIni->hLock)
377 == NO_ERROR)
378 {
379 PBYTE pbFileData = (PBYTE)malloc(fs3.cbFile);
380 if (pbFileData)
381 {
382 ULONG ulSet = 0;
383 APIRET arc = DosProtectSetFilePtr(pXIni->hFile,
384 0,
385 FILE_BEGIN,
386 &ulSet,
387 pXIni->hLock);
388 if ( (arc == NO_ERROR)
389 && (ulSet == 0)
390 )
391 {
392 ULONG cbRead = 0;
393 arc = DosProtectRead(pXIni->hFile,
394 pbFileData,
395 fs3.cbFile,
396 &cbRead,
397 pXIni->hLock);
398 if ( (arc == NO_ERROR)
399 && (cbRead == fs3.cbFile)
400 )
401 {
402 PINIFILE_HEADER pHeader = (PINIFILE_HEADER)pbFileData;
403 if (pHeader->magic == 0xFFFFFFFF)
404 {
405 ULONG ulAppOfs = pHeader->offFirstApp;
406
407 // it was a valid profile, so return TRUE
408 brc = TRUE;
409
410 // create-applications loop
411 while ((ulAppOfs) && (brc))
412 {
413 // application struct
414 PINIFILE_APP pApp = (PINIFILE_APP)(pbFileData + ulAppOfs);
415 ULONG ulKeysOfs = pApp->offFirstKeyInApp;
416 PXINIAPPDATA pIniApp
417 = CreateApp(pXIni,
418 (PBYTE)(pbFileData + pApp->offAppName));
419 if (!pIniApp)
420 {
421 brc = FALSE;
422 break;
423 }
424
425 // create-keys loop
426 while ((ulKeysOfs) && (brc))
427 {
428 PINIFILE_KEY pKey = (PINIFILE_KEY)(pbFileData + ulKeysOfs);
429
430 PXINIKEYDATA pIniKey
431 = CreateKey(pIniApp,
432 (PSZ)(pbFileData + pKey->offKeyName),
433 (PBYTE)(pbFileData + pKey->offKeyData),
434 pKey->lenKeyData);
435
436 if (!pKey)
437 {
438 brc = FALSE;
439 break;
440 }
441
442 // next key; can be null
443 ulKeysOfs = pKey->offNextKeyInApp;
444 }
445
446 // next application; can be null
447 ulAppOfs = pApp->offNextApp;
448 }
449 }
450 }
451 }
452
453 free(pbFileData);
454 }
455 }
456
457 return (brc);
458}
459
460/*
461 * WriteINI:
462 * writes the entire data structure back to disk.
463 * Does not close the file.
464 *
465 * Private helper.
466 */
467
468BOOL WriteINI(PXINI pXIni) // in: profile opened with xprfOpenProfile
469{
470 BOOL brc = FALSE;
471 ULONG ulTotalFileSize = sizeof(INIFILE_HEADER);
472 ULONG ulSet = 0;
473 PBYTE pbData2Write = NULL;
474
475 // check how much memory we'll need:
476 // one INIFILE_HEADER
477 // + for each app: one INIFILE_APP plus app name length
478 // + for each key: one INIFILE_KEY plus key name length plus data length
479
480 // go thru all apps
481 PLISTNODE pAppNode = lstQueryFirstNode(&pXIni->llApps);
482 while (pAppNode)
483 {
484 PLISTNODE pKeyNode;
485
486 PXINIAPPDATA pAppDataThis = (PXINIAPPDATA)pAppNode->pItemData;
487
488 // one INIFILE_APP plus app name length for each app
489 ulTotalFileSize += sizeof(INIFILE_APP)
490 + strlen(pAppDataThis->pszAppName)
491 + 1; // null terminator
492
493 // for each app, go thru all keys
494 pKeyNode = lstQueryFirstNode(&pAppDataThis->llKeys);
495 while (pKeyNode)
496 {
497 PXINIKEYDATA pKeyDataThis = (PXINIKEYDATA)pKeyNode->pItemData;
498 ulTotalFileSize += sizeof(INIFILE_KEY)
499 + strlen(pKeyDataThis->pszKeyName)
500 + pKeyDataThis->cbData
501 + 1; // null terminator
502
503 pKeyNode = pKeyNode->pNext;
504 }
505
506 pAppNode = pAppNode->pNext;
507 }
508
509 // allocate buffer for total size
510 pbData2Write = (PBYTE)malloc(ulTotalFileSize);
511 if (pbData2Write)
512 {
513 APIRET arc = NO_ERROR;
514
515 // set header in buffer
516 PINIFILE_HEADER pHeader = (PINIFILE_HEADER)pbData2Write;
517 // pointer into buffer for current write
518 // (used below)
519 ULONG ulCurOfs = sizeof(INIFILE_HEADER);
520
521 // 1) set up header
522
523 pHeader->magic = 0xFFFFFFFF;
524 if (pXIni->cApps)
525 // we have any applications:
526 pHeader->offFirstApp = sizeof(INIFILE_HEADER);
527 // offset of first application in file
528 else
529 // empty INI file:
530 pHeader->offFirstApp = 0;
531 pHeader->lenFile = ulTotalFileSize;
532 pHeader->filler1 = 0;
533 pHeader->filler2 = 0;
534
535 // 2) for-all-applications loop
536
537 pAppNode = lstQueryFirstNode(&pXIni->llApps);
538 while (pAppNode)
539 {
540 PXINIAPPDATA pAppDataThis = (PXINIAPPDATA)pAppNode->pItemData;
541 ULONG cbAppName = strlen(pAppDataThis->pszAppName) + 1;
542
543 // layout of application entry in file:
544 // -- struct PINIFILE_APP (ulCurOfs right now)
545 // -- application name (null-terminated)
546 // -- INIFILE_KEY 1
547 // -- INIFILE_KEY 2 ...
548 // -- next struct PINIFILE_APP
549
550 // make pointer to application entry
551 PINIFILE_APP pIniAppCurrent = (PINIFILE_APP)(pbData2Write + ulCurOfs);
552
553 // write out application entry
554 // pIniAppCurrent->offNextApp = 0;
555 // pIniAppCurrent->offFirstKeyInApp = ulCurOfs + cbAppName;
556 pIniAppCurrent->filler1 = 0;
557 pIniAppCurrent->lenAppName
558 = pIniAppCurrent->_lenAppName
559 = cbAppName;
560 // set offset to application name: put this right after the application
561 ulCurOfs += sizeof(INIFILE_APP);
562 pIniAppCurrent->offAppName = ulCurOfs;
563
564 // write app name (null-terminated)
565 memcpy(pbData2Write + ulCurOfs,
566 pAppDataThis->pszAppName,
567 cbAppName);
568 ulCurOfs += cbAppName;
569
570 // ulCurOfs points to INIFILE_KEY entry now
571 if (pAppDataThis->cKeys)
572 {
573 // we have keys:
574 PLISTNODE pKeyNode = lstQueryFirstNode(&pAppDataThis->llKeys);
575 pIniAppCurrent->offFirstKeyInApp = ulCurOfs;
576
577 // 3) for-all-keys loop per application
578
579 while (pKeyNode)
580 {
581 PXINIKEYDATA pKeyDataThis = (PXINIKEYDATA)pKeyNode->pItemData;
582 ULONG cbKeyName = strlen(pKeyDataThis->pszKeyName) + 1;
583
584 PINIFILE_KEY pIniKeyCurrent = (PINIFILE_KEY)(pbData2Write + ulCurOfs);
585 pIniKeyCurrent->filler1 = 0;
586 ulCurOfs += sizeof(INIFILE_KEY);
587 // has offset to key name now
588
589 // a) key name
590 pIniKeyCurrent->lenKeyName
591 = pIniKeyCurrent->_lenKeyName
592 = cbKeyName;
593 pIniKeyCurrent->offKeyName = ulCurOfs;
594 memcpy(pbData2Write + ulCurOfs,
595 pKeyDataThis->pszKeyName,
596 cbKeyName);
597 ulCurOfs += cbKeyName;
598 // has offset to data now
599
600 // b) data
601 pIniKeyCurrent->lenKeyData
602 = pIniKeyCurrent->_lenKeyData
603 = pKeyDataThis->cbData;
604 pIniKeyCurrent->offKeyData = ulCurOfs;
605 memcpy(pbData2Write + ulCurOfs,
606 pKeyDataThis->pbData,
607 pKeyDataThis->cbData);
608 ulCurOfs += pKeyDataThis->cbData;
609 // points to after all key data now;
610 // this receives either the next key/data block
611 // or the next application or nothing
612
613 // ofs of next key:
614 if (pKeyNode->pNext)
615 pIniKeyCurrent->offNextKeyInApp = ulCurOfs;
616 else
617 // last key:
618 pIniKeyCurrent->offNextKeyInApp = 0;
619
620 pKeyNode = pKeyNode->pNext;
621 }
622
623 // ulCurOfs points to after the last keys entry now
624 }
625 else
626 // no keys:
627 pIniAppCurrent->offFirstKeyInApp = 0;
628
629 // done with keys (there may be none!);
630 // now set offset to next app in current application
631 if (pAppNode->pNext)
632 pIniAppCurrent->offNextApp = ulCurOfs;
633 else
634 // this was the last one:
635 pIniAppCurrent->offNextApp = 0;
636
637 // next app
638 pAppNode = pAppNode->pNext;
639 }
640
641 // write out everything
642 arc = DosProtectSetFilePtr(pXIni->hFile,
643 0,
644 FILE_BEGIN,
645 &ulSet,
646 pXIni->hLock);
647 if (arc == NO_ERROR)
648 {
649 ULONG cbWritten = 0;
650 arc = DosProtectWrite(pXIni->hFile,
651 pbData2Write,
652 ulTotalFileSize,
653 &cbWritten,
654 pXIni->hLock);
655 if (arc == NO_ERROR)
656 {
657 arc = DosProtectSetFileSize(pXIni->hFile,
658 ulTotalFileSize,
659 pXIni->hLock);
660 if (arc == NO_ERROR)
661 brc = TRUE;
662 }
663 }
664
665 free(pbData2Write);
666 }
667
668 return (brc);
669}
670
671/* ******************************************************************
672 *
673 * API Functions
674 *
675 ********************************************************************/
676
677/*
678 *@@ xprfOpenProfile:
679 * opens an extended profile (XINI). This is similar to
680 * PrfOpenProfile, but cannot be used interchangably.
681 * See the top of this file (xprf.c) for general remarks.
682 *
683 * If the full path is not specified, the current
684 * directory is used. This uses DosProtectOpen to
685 * open the profile, so see CPREF for additional remarks.
686 *
687 * If the specified profile does not exist yet, it is
688 * created by this function.
689 *
690 * Note that you must not open the system profiles
691 * (OS2.INI and OS2SYS.INI) using this function because
692 * this would keep OS/2 from updating them.
693 *
694 * This returns 0 (NO_ERROR) on success. Otherwise either
695 * an OS/2 error code (ERROR_*) or one of the profile error
696 * codes defined in prfh.h is returned.
697 */
698
699APIRET xprfOpenProfile(const char *pcszFilename, // in: profile name
700 PXINI *ppxini) // out: profile handle
701{
702 APIRET arc = NO_ERROR;
703 PXINI pXIni = NULL;
704
705 if (pcszFilename)
706 if (strlen(pcszFilename) < CCHMAXPATH - 1)
707 {
708 HFILE hFile = NULLHANDLE;
709 ULONG ulAction = 0;
710 FHLOCK hLock = 0;
711 arc = DosProtectOpen((PSZ)pcszFilename,
712 &hFile,
713 &ulAction,
714 1024, // initial size
715 FILE_NORMAL,
716 OPEN_ACTION_CREATE_IF_NEW
717 | OPEN_ACTION_OPEN_IF_EXISTS,
718 OPEN_FLAGS_FAIL_ON_ERROR
719 | OPEN_FLAGS_NO_CACHE
720 | OPEN_FLAGS_SEQUENTIAL
721 | OPEN_SHARE_DENYREADWRITE
722 | OPEN_ACCESS_READWRITE,
723 NULL, // no EAs
724 &hLock);
725 if (arc == NO_ERROR)
726 {
727 pXIni = (PXINI)malloc(sizeof(XINI));
728 if (!pXIni)
729 arc = ERROR_NOT_ENOUGH_MEMORY;
730 else
731 {
732 // OK: initialize XINI
733 memset(pXIni, 0, sizeof(XINI));
734 memcpy(pXIni->acMagic, XINI_MAGIC_BYTES, sizeof(XINI_MAGIC_BYTES));
735 strcpy(pXIni->szFilename, pcszFilename);
736 pXIni->hFile = hFile;
737 pXIni->hLock = hLock;
738
739 lstInit(&pXIni->llApps, FALSE);
740
741 if (ulAction == FILE_CREATED)
742 // file newly created: rewrite on close
743 pXIni->fDirty = TRUE;
744 else
745 // file existed: read data
746 if (!ReadINI(pXIni))
747 {
748 // error:
749 FreeINI(pXIni);
750 pXIni = NULL;
751 arc = PRFERR_READ;
752 }
753
754 if ((pXIni) && (ppxini))
755 *ppxini = pXIni;
756 }
757 }
758 }
759
760 return (arc);
761}
762
763/*
764 *@@ xprfQueryProfileData:
765 * similar to PrfQueryProfileData.
766 *
767 * @@todo: Still to be written.
768 */
769
770/* BOOL xprfQueryProfileData(PXINI hIni, // in: profile opened with xprfOpenProfile
771 const char *pcszApp,
772 const char *pcszKey,
773 PVOID pBuffer,
774 PULONG pulBufferMax)
775{
776 BOOL brc = FALSE;
777
778 return (brc);
779} */
780
781/*
782 *@@ xprfWriteProfileData:
783 * writes data into an extended profile (XINI).
784 * This operates similar to PrfWriteProfileData,
785 * that is:
786 *
787 * -- If all of pcszApp, pcszKey, pData, and
788 * ulDataLen are specified, the given data is
789 * written into the specified application/key
790 * pair.
791 *
792 * -- If pcszApp and pcszKey are specified, but
793 * pData and ulDataLen are null, the specified
794 * key is deleted.
795 *
796 * -- If pcszApp is specified, but all of pcszKey,
797 * pData, and ulDataLen are null, the entire
798 * specified application is deleted.
799 *
800 * You cannot specify HINI_SYSTEM or HINI_USER for
801 * hINi.
802 *
803 * Note that if data has been added or removed,
804 * the INI file on disk is not updated automatically.
805 * Instead, our memory copy of it is only marked
806 * as "dirty" so that the file will be rewritten
807 * on xprfCloseProfile.
808 */
809
810BOOL xprfWriteProfileData(PXINI hIni, // in: profile opened with xprfOpenProfile
811 const char *pcszApp, // in: application name
812 const char *pcszKey, // in: key name or NULL
813 PVOID pData, // in: data to write or NULL
814 ULONG ulDataLen) // in: sizeof(*pData) or null
815{
816 BOOL brc = FALSE;
817
818 if (hIni)
819 {
820 PXINI pXIni = (PXINI)hIni;
821 if (memcmp(pXIni->acMagic, XINI_MAGIC_BYTES, sizeof(XINI_MAGIC_BYTES))
822 == 0)
823 {
824 // check if application exists
825 PXINIAPPDATA pAppData = FindApp(pXIni,
826 pcszApp);
827
828 // now check: does caller want entire application deleted?
829 if (!pcszKey)
830 {
831 // yes, delete application: did we find it?
832 if (pAppData)
833 {
834 // yes: kill that
835 FreeApp(pAppData);
836 // and remove from list
837 brc = lstRemoveItem(&pXIni->llApps, pAppData);
838 pXIni->cApps--;
839 // rewrite profile on close
840 pXIni->fDirty = TRUE;
841 }
842 else
843 // application doesn't exist:
844 brc = TRUE;
845 }
846 else
847 {
848 // caller has specified key:
849 // does caller want a key to be deleted?
850 if (!ulDataLen)
851 {
852 // yes: delete key:
853 if (pAppData)
854 {
855 // app exists:
856 // find key
857 PXINIKEYDATA pKeyData = FindKey(pAppData,
858 pcszKey);
859 if (pKeyData)
860 {
861 // key exists: kill that
862 FreeKey(pKeyData);
863 // and remove from app's keys list
864 brc = lstRemoveItem(&pAppData->llKeys, pKeyData);
865 pAppData->cKeys--;
866 // rewrite profile on close
867 pXIni->fDirty = TRUE;
868 }
869 else
870 // key doesn't even exist:
871 brc = TRUE;
872 }
873 else
874 // app doesn't even exist:
875 brc = TRUE;
876 }
877 else
878 {
879 // key and data specified: let's add something...
880
881 if (!pAppData)
882 // app doesn't exist yet:
883 // create
884 pAppData = CreateApp(pXIni,
885 pcszApp);
886
887 if (pAppData)
888 {
889 // found or created app:
890 // check if key exists
891 PXINIKEYDATA pKeyData = FindKey(pAppData,
892 pcszKey);
893 if (!pKeyData)
894 // doesn't exist yet:
895 // create
896 pKeyData = CreateKey(pAppData,
897 pcszKey,
898 (PBYTE)pData,
899 ulDataLen);
900
901 if (pKeyData)
902 {
903 // mark as dirty
904 pXIni->fDirty = TRUE;
905 brc = TRUE;
906 }
907 }
908 }
909 }
910 }
911 }
912
913 return (brc);
914}
915
916/*
917 *@@ xprfCloseProfile:
918 * closes a profile opened with xprfOpenProfile.
919 * If the profile is "dirty", that is, if any data
920 * has been changed using xprfWriteProfileData, the
921 * file is written back to disk before closing.
922 *
923 * You cannot specify HINI_SYSTEM or HINI_USER for
924 * hINi.
925 */
926
927BOOL xprfCloseProfile(PXINI hIni) // in: profile opened with xprfOpenProfile
928{
929 BOOL brc = FALSE;
930
931 if (hIni)
932 {
933 PXINI pXIni = (PXINI)hIni;
934 if (memcmp(pXIni->acMagic, XINI_MAGIC_BYTES, sizeof(XINI_MAGIC_BYTES))
935 == 0)
936 {
937 brc = TRUE;
938
939 if (pXIni->fDirty)
940 brc = WriteINI(pXIni);
941
942 if (brc)
943 {
944 APIRET arc = DosProtectClose(pXIni->hFile,
945 pXIni->hLock);
946 if (arc == NO_ERROR)
947 {
948 pXIni->hFile = 0;
949 pXIni->hLock = 0;
950
951 FreeINI(pXIni);
952 }
953 else
954 brc = FALSE;
955 }
956 }
957 }
958
959 return (brc);
960}
961
962
Note: See TracBrowser for help on using the repository browser.