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

Last change on this file since 19 was 14, checked in by umoeller, 25 years ago

Major updates; timers, LVM, miscellaneous.

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