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

Last change on this file since 133 was 133, checked in by umoeller, 24 years ago

program plus other fixes

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