source: branches/branch-1-0/src/helpers/xprf.c@ 365

Last change on this file since 365 was 229, checked in by umoeller, 23 years ago

Sources as of 1.0.0.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 38.5 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 *@@changed V1.0.0 (2002-09-17) [umoeller]: now returning APIRET
159 */
160
161STATIC APIRET FindApp(PXINI pXIni, // in: profile opened with xprfOpenProfile
162 const char *pcszApp,
163 PXINIAPPDATA *ppAppData)
164{
165 PLISTNODE pAppNode = lstQueryFirstNode(&pXIni->llApps);
166 while (pAppNode)
167 {
168 PXINIAPPDATA pAppDataThis = (PXINIAPPDATA)pAppNode->pItemData;
169 if (!strcmp(pAppDataThis->pszAppName, pcszApp))
170 {
171 *ppAppData = pAppDataThis;
172 return NO_ERROR;
173 }
174
175 pAppNode = pAppNode->pNext;
176 }
177
178 return PRFERR_INVALID_APP_NAME;
179}
180
181/*
182 * CreateApp:
183 * creates a new application in the specified
184 * profile structure and appends it to the list.
185 * This does NOT check for whether the app is
186 * already in the profile.
187 *
188 * Private helper.
189 *
190 *@@changed V1.0.0 (2002-09-17) [umoeller]: now returning APIRET
191 */
192
193STATIC APIRET CreateApp(PXINI pXIni, // in: profile opened with xprfOpenProfile
194 const char *pcszApp,
195 PXINIAPPDATA *ppAppData)
196{
197 PXINIAPPDATA pAppData;
198 if (pAppData = (PXINIAPPDATA)malloc(sizeof(XINIAPPDATA)))
199 {
200 pAppData->pszAppName = strdup(pcszApp);
201 lstInit(&pAppData->llKeys, FALSE);
202 pAppData->cKeys = 0;
203
204 // store in INI's apps list
205 lstAppendItem(&pXIni->llApps, pAppData);
206
207 *ppAppData = pAppData;
208 return NO_ERROR;
209 }
210
211 return ERROR_NOT_ENOUGH_MEMORY;
212}
213
214/*
215 * FindKey:
216 * attempts to find the specified key
217 * in the given application.
218 * Returns NULL if not found.
219 *
220 * Private helper.
221 *
222 *@@changed V1.0.0 (2002-09-17) [umoeller]: now returning APIRET
223 */
224
225STATIC APIRET FindKey(PXINIAPPDATA pAppData,
226 const char *pcszKey,
227 PXINIKEYDATA *ppKeyData)
228{
229 PLISTNODE pKeyNode = lstQueryFirstNode(&pAppData->llKeys);
230 while (pKeyNode)
231 {
232 PXINIKEYDATA pKeyDataThis = (PXINIKEYDATA)pKeyNode->pItemData;
233 if (!strcmp(pKeyDataThis->pszKeyName, pcszKey))
234 {
235 *ppKeyData = pKeyDataThis;
236 return NO_ERROR;
237 }
238
239 pKeyNode = pKeyNode->pNext;
240 }
241
242 return PRFERR_INVALID_KEY_NAME;
243}
244
245/*
246 * CreateKey:
247 * creates a new key in the specified application
248 * structure and appends it to the list.
249 * This does NOT check for whether the key is
250 * already in the application.
251 *
252 * Private helper.
253 *
254 *@@changed V1.0.0 (2002-09-17) [umoeller]: now returning APIRET
255 */
256
257STATIC APIRET CreateKey(PXINIAPPDATA pAppData,
258 const char *pcszKey, // in: key name
259 PBYTE pbData, // in: data for key
260 ULONG cbData, // in: sizeof (*pbData)
261 PXINIKEYDATA *ppKeyData) // out: new key data
262{
263 PXINIKEYDATA pKeyData;
264 if (pKeyData = (PXINIKEYDATA)malloc(sizeof(XINIKEYDATA)))
265 {
266 pKeyData->pszKeyName = strdup(pcszKey);
267
268 if (pKeyData->pbData = (PBYTE)malloc(cbData))
269 {
270 memcpy(pKeyData->pbData, pbData, cbData);
271 pKeyData->cbData = cbData;
272 // store in app's keys list
273 lstAppendItem(&pAppData->llKeys, pKeyData);
274 pAppData->cKeys++;
275
276 *ppKeyData = pKeyData;
277 return NO_ERROR;
278 }
279 else
280 // malloc failed:
281 free(pKeyData);
282 }
283
284 return ERROR_NOT_ENOUGH_MEMORY;
285}
286
287/*
288 * FreeKey:
289 * frees the specified key. Does not remove
290 * the key from the keys list in XINIAPPDATA
291 * however.
292 *
293 * Private helper.
294 */
295
296STATIC VOID FreeKey(PXINIKEYDATA pKeyDataThis)
297{
298 if (pKeyDataThis->pszKeyName)
299 free(pKeyDataThis->pszKeyName);
300 if (pKeyDataThis->pbData)
301 free(pKeyDataThis->pbData);
302 free(pKeyDataThis);
303}
304
305/*
306 *@@ FreeKeyIfExists:
307 *
308 *@@added V1.0.0 (2002-09-17) [umoeller]
309 */
310
311STATIC VOID FreeKeyIfExists(PXINI pXIni, // in: profile opened with xprfOpenProfile
312 PXINIAPPDATA pAppData,
313 PCSZ pcszKey)
314{
315 // find key
316 PXINIKEYDATA pKeyData;
317
318 if (!FindKey(pAppData,
319 pcszKey,
320 &pKeyData))
321 {
322 // key exists: kill that
323 FreeKey(pKeyData);
324 // and remove from app's keys list
325 lstRemoveItem(&pAppData->llKeys, pKeyData);
326 pAppData->cKeys--;
327
328 // rewrite profile on close
329 pXIni->fDirty = TRUE;
330 }
331 // else key doesn't exist:
332 // nothing to do
333}
334
335/*
336 * FreeApp:
337 * frees the specified application. Does not remove
338 * the application from the application list in XINI
339 * however.
340 *
341 * Private helper.
342 */
343
344STATIC VOID FreeApp(PXINIAPPDATA pAppDataThis)
345{
346 PLISTNODE pKeyNode = lstQueryFirstNode(&pAppDataThis->llKeys);
347 while (pKeyNode)
348 {
349 PXINIKEYDATA pKeyDataThis = (PXINIKEYDATA)pKeyNode->pItemData;
350
351 FreeKey(pKeyDataThis);
352
353 pKeyNode = pKeyNode->pNext;
354 }
355
356 if (pAppDataThis->pszAppName)
357 free(pAppDataThis->pszAppName);
358
359 lstClear(&pAppDataThis->llKeys);
360
361 free(pAppDataThis);
362}
363
364/*
365 * FreeINI:
366 * cleans up the specified ini structure entirely.
367 *
368 * Private helper.
369 */
370
371STATIC VOID FreeINI(PXINI pXIni) // in: profile opened with xprfOpenProfile
372{
373 if (pXIni)
374 {
375 PLISTNODE pAppNode = lstQueryFirstNode(&pXIni->llApps);
376 while (pAppNode)
377 {
378 PXINIAPPDATA pAppDataThis = (PXINIAPPDATA)pAppNode->pItemData;
379
380 FreeApp(pAppDataThis);
381
382 pAppNode = pAppNode->pNext;
383 }
384
385 lstClear(&pXIni->llApps);
386 free(pXIni);
387 }
388}
389
390/* ******************************************************************
391 *
392 * Read/write data
393 *
394 ********************************************************************/
395
396/*
397 * ReadINI:
398 * reads in the entire INI file from disk and
399 * initializes all internal data structures.
400 *
401 * Private helper.
402 *
403 *@@changed V1.0.0 (2002-09-17) [umoeller]: now returning APIRET
404 */
405
406STATIC APIRET ReadINI(PXINI pXIni) // in: profile opened with xprfOpenProfile
407{
408 APIRET arc;
409 FILESTATUS3 fs3;
410
411 if (!(arc = DosQueryFileInfo(pXIni->hFile,
412 FIL_STANDARD,
413 &fs3,
414 sizeof(fs3))))
415 {
416 PBYTE pbFileData;
417 if (!(pbFileData = (PBYTE)malloc(fs3.cbFile)))
418 arc = ERROR_NOT_ENOUGH_MEMORY;
419 else
420 {
421 ULONG ulSet = 0;
422
423 if (!(arc = DosSetFilePtr(pXIni->hFile,
424 0,
425 FILE_BEGIN,
426 &ulSet)))
427 {
428 ULONG cbRead = 0;
429 if (!(arc = DosRead(pXIni->hFile,
430 pbFileData,
431 fs3.cbFile,
432 &cbRead)))
433 {
434 if (cbRead != fs3.cbFile)
435 arc = ERROR_NO_DATA;
436 else
437 {
438 PINIFILE_HEADER pHeader = (PINIFILE_HEADER)pbFileData;
439 if (pHeader->magic == 0xFFFFFFFF)
440 {
441 ULONG ulAppOfs = pHeader->offFirstApp;
442
443 // create-applications loop
444 while ((ulAppOfs) && (!arc))
445 {
446 // application struct
447 PINIFILE_APP pApp = (PINIFILE_APP)(pbFileData + ulAppOfs);
448 ULONG ulKeysOfs = pApp->offFirstKeyInApp;
449 PXINIAPPDATA pIniApp;
450
451 if (arc = CreateApp(pXIni,
452 (PBYTE)(pbFileData + pApp->offAppName),
453 &pIniApp))
454 break;
455
456 // create-keys loop
457 while ((ulKeysOfs) && (!arc))
458 {
459 PINIFILE_KEY pKey = (PINIFILE_KEY)(pbFileData + ulKeysOfs);
460
461 PXINIKEYDATA pIniKey;
462
463 if (arc = CreateKey(pIniApp,
464 (PSZ)(pbFileData + pKey->offKeyName),
465 (PBYTE)(pbFileData + pKey->offKeyData),
466 pKey->lenKeyData,
467 &pIniKey))
468 break;
469
470 // next key; can be null
471 ulKeysOfs = pKey->offNextKeyInApp;
472 }
473
474 // next application; can be null
475 ulAppOfs = pApp->offNextApp;
476 }
477 }
478 }
479 }
480 }
481
482 free(pbFileData);
483 }
484 }
485
486 return arc;
487}
488
489/*
490 * WriteINI:
491 * writes the entire data structure back to disk.
492 * Does not close the file.
493 *
494 * Private helper.
495 *
496 *@@changed V1.0.0 (2002-09-17) [umoeller]: now returning APIRET
497 */
498
499STATIC APIRET WriteINI(PXINI pXIni) // in: profile opened with xprfOpenProfile
500{
501 APIRET arc = NO_ERROR;
502 ULONG ulTotalFileSize = sizeof(INIFILE_HEADER);
503 ULONG ulSet = 0;
504 PBYTE pbData2Write = NULL;
505
506 // check how much memory we'll need:
507 // one INIFILE_HEADER
508 // + for each app: one INIFILE_APP plus app name length
509 // + for each key: one INIFILE_KEY plus key name length plus data length
510
511 // go thru all apps
512 PLISTNODE pAppNode = lstQueryFirstNode(&pXIni->llApps);
513
514 while (pAppNode)
515 {
516 PLISTNODE pKeyNode;
517
518 PXINIAPPDATA pAppDataThis = (PXINIAPPDATA)pAppNode->pItemData;
519
520 // one INIFILE_APP plus app name length for each app
521 ulTotalFileSize += sizeof(INIFILE_APP)
522 + strlen(pAppDataThis->pszAppName)
523 + 1; // null terminator
524
525 // for each app, go thru all keys
526 pKeyNode = lstQueryFirstNode(&pAppDataThis->llKeys);
527 while (pKeyNode)
528 {
529 PXINIKEYDATA pKeyDataThis = (PXINIKEYDATA)pKeyNode->pItemData;
530 ulTotalFileSize += sizeof(INIFILE_KEY)
531 + strlen(pKeyDataThis->pszKeyName)
532 + pKeyDataThis->cbData
533 + 1; // null terminator
534
535 pKeyNode = pKeyNode->pNext;
536 }
537
538 pAppNode = pAppNode->pNext;
539 }
540
541 // allocate buffer for total size
542 if (pbData2Write = (PBYTE)malloc(ulTotalFileSize))
543 {
544 // set header in buffer
545 PINIFILE_HEADER pHeader = (PINIFILE_HEADER)pbData2Write;
546 // pointer into buffer for current write
547 // (used below)
548 ULONG ulCurOfs = sizeof(INIFILE_HEADER);
549
550 // 1) set up header
551
552 pHeader->magic = 0xFFFFFFFF;
553 if (lstCountItems(&pXIni->llApps))
554 // we have any applications:
555 pHeader->offFirstApp = sizeof(INIFILE_HEADER);
556 // offset of first application in file
557 else
558 // empty INI file:
559 pHeader->offFirstApp = 0;
560 pHeader->lenFile = ulTotalFileSize;
561 pHeader->filler1 = 0;
562 pHeader->filler2 = 0;
563
564 // 2) for-all-applications loop
565
566 pAppNode = lstQueryFirstNode(&pXIni->llApps);
567 while (pAppNode)
568 {
569 PXINIAPPDATA pAppDataThis = (PXINIAPPDATA)pAppNode->pItemData;
570 ULONG cbAppName = strlen(pAppDataThis->pszAppName) + 1;
571
572 // layout of application entry in file:
573 // -- struct PINIFILE_APP (ulCurOfs right now)
574 // -- application name (null-terminated)
575 // -- INIFILE_KEY 1
576 // -- INIFILE_KEY 2 ...
577 // -- next struct PINIFILE_APP
578
579 // make pointer to application entry
580 PINIFILE_APP pIniAppCurrent = (PINIFILE_APP)(pbData2Write + ulCurOfs);
581
582 // write out application entry
583 // pIniAppCurrent->offNextApp = 0;
584 // pIniAppCurrent->offFirstKeyInApp = ulCurOfs + cbAppName;
585 pIniAppCurrent->filler1 = 0;
586 pIniAppCurrent->lenAppName
587 = pIniAppCurrent->_lenAppName
588 = cbAppName;
589 // set offset to application name: put this right after the application
590 ulCurOfs += sizeof(INIFILE_APP);
591 pIniAppCurrent->offAppName = ulCurOfs;
592
593 // write app name (null-terminated)
594 memcpy(pbData2Write + ulCurOfs,
595 pAppDataThis->pszAppName,
596 cbAppName);
597 ulCurOfs += cbAppName;
598
599 // ulCurOfs points to INIFILE_KEY entry now
600 if (pAppDataThis->cKeys)
601 {
602 // we have keys:
603 PLISTNODE pKeyNode = lstQueryFirstNode(&pAppDataThis->llKeys);
604 pIniAppCurrent->offFirstKeyInApp = ulCurOfs;
605
606 // 3) for-all-keys loop per application
607
608 while (pKeyNode)
609 {
610 PXINIKEYDATA pKeyDataThis = (PXINIKEYDATA)pKeyNode->pItemData;
611 ULONG cbKeyName = strlen(pKeyDataThis->pszKeyName) + 1;
612
613 PINIFILE_KEY pIniKeyCurrent = (PINIFILE_KEY)(pbData2Write + ulCurOfs);
614 pIniKeyCurrent->filler1 = 0;
615 ulCurOfs += sizeof(INIFILE_KEY);
616 // has offset to key name now
617
618 // a) key name
619 pIniKeyCurrent->lenKeyName
620 = pIniKeyCurrent->_lenKeyName
621 = cbKeyName;
622 pIniKeyCurrent->offKeyName = ulCurOfs;
623 memcpy(pbData2Write + ulCurOfs,
624 pKeyDataThis->pszKeyName,
625 cbKeyName);
626 ulCurOfs += cbKeyName;
627 // has offset to data now
628
629 // b) data
630 pIniKeyCurrent->lenKeyData
631 = pIniKeyCurrent->_lenKeyData
632 = pKeyDataThis->cbData;
633 pIniKeyCurrent->offKeyData = ulCurOfs;
634 memcpy(pbData2Write + ulCurOfs,
635 pKeyDataThis->pbData,
636 pKeyDataThis->cbData);
637 ulCurOfs += pKeyDataThis->cbData;
638 // points to after all key data now;
639 // this receives either the next key/data block
640 // or the next application or nothing
641
642 // ofs of next key:
643 if (pKeyNode->pNext)
644 pIniKeyCurrent->offNextKeyInApp = ulCurOfs;
645 else
646 // last key:
647 pIniKeyCurrent->offNextKeyInApp = 0;
648
649 pKeyNode = pKeyNode->pNext;
650 }
651
652 // ulCurOfs points to after the last keys entry now
653 }
654 else
655 // no keys:
656 pIniAppCurrent->offFirstKeyInApp = 0;
657
658 // done with keys (there may be none!);
659 // now set offset to next app in current application
660 if (pAppNode->pNext)
661 pIniAppCurrent->offNextApp = ulCurOfs;
662 else
663 // this was the last one:
664 pIniAppCurrent->offNextApp = 0;
665
666 // next app
667 pAppNode = pAppNode->pNext;
668 }
669
670 // write out everything
671 if (!(arc = DosSetFilePtr(pXIni->hFile,
672 0,
673 FILE_BEGIN,
674 &ulSet)))
675 {
676 ULONG cbWritten = 0;
677 if (!(arc = DosWrite(pXIni->hFile,
678 pbData2Write,
679 ulTotalFileSize,
680 &cbWritten)))
681 {
682 if (!(arc = DosSetFileSize(pXIni->hFile,
683 ulTotalFileSize)))
684 ;
685 }
686 }
687
688 free(pbData2Write);
689 }
690
691 return arc;
692}
693
694/* ******************************************************************
695 *
696 * API Functions
697 *
698 ********************************************************************/
699
700/*
701 *@@ xprfOpenProfile:
702 * opens an extended profile (XINI). This is similar to
703 * PrfOpenProfile, but cannot be used interchangably.
704 * See the top of this file (xprf.c) for general remarks.
705 *
706 * If the full path is not specified, the current
707 * directory is used. This uses DosProtectOpen to
708 * open the profile, so see CPREF for additional remarks.
709 *
710 * If the specified profile does not exist yet, it is
711 * created by this function.
712 *
713 * Note that you must not open the system profiles
714 * (OS2.INI and OS2SYS.INI) using this function because
715 * this would keep OS/2 from updating them.
716 *
717 * This returns 0 (NO_ERROR) on success. Otherwise either
718 * an OS/2 error code (ERROR_*) or one of the profile error
719 * codes defined in prfh.h is returned.
720 */
721
722APIRET xprfOpenProfile(const char *pcszFilename, // in: profile name
723 PXINI *ppxini) // out: profile handle
724{
725 APIRET arc = NO_ERROR;
726 PXINI pXIni = NULL;
727 ULONG ulFilenameLen;
728
729 if ( (!pcszFilename)
730 || (!ppxini)
731 )
732 arc = ERROR_INVALID_PARAMETER; // V1.0.0 (2002-09-17) [umoeller]
733 else if (!(ulFilenameLen = strlen(pcszFilename)))
734 arc = ERROR_INVALID_PARAMETER; // V1.0.0 (2002-09-17) [umoeller]
735 else if (ulFilenameLen >= CCHMAXPATH - 1)
736 arc = ERROR_FILENAME_EXCED_RANGE;
737 else
738 {
739 HFILE hFile = NULLHANDLE;
740 ULONG ulAction = 0;
741 // FHLOCK hLock = 0;
742
743 if (!(arc = DosOpen((PSZ)pcszFilename,
744 &hFile,
745 &ulAction,
746 1024, // initial size
747 FILE_NORMAL,
748 OPEN_ACTION_CREATE_IF_NEW
749 | OPEN_ACTION_OPEN_IF_EXISTS,
750 OPEN_FLAGS_FAIL_ON_ERROR
751 | OPEN_FLAGS_SEQUENTIAL
752 | OPEN_SHARE_DENYREADWRITE
753 | OPEN_ACCESS_READWRITE,
754 NULL)))
755 {
756 if (!(pXIni = (PXINI)malloc(sizeof(XINI))))
757 arc = ERROR_NOT_ENOUGH_MEMORY;
758 else
759 {
760 // OK: initialize XINI
761 memset(pXIni, 0, sizeof(XINI));
762 memcpy(pXIni->acMagic, XINI_MAGIC_BYTES, sizeof(XINI_MAGIC_BYTES));
763 memcpy(pXIni->szFilename,
764 pcszFilename,
765 ulFilenameLen + 1);
766 pXIni->hFile = hFile;
767 // pXIni->hLock = hLock;
768
769 lstInit(&pXIni->llApps, FALSE);
770
771 if (ulAction == FILE_CREATED)
772 // file newly created: rewrite on close
773 pXIni->fDirty = TRUE;
774 else
775 // file existed: read data
776 if (arc = ReadINI(pXIni))
777 // error:
778 FreeINI(pXIni);
779 }
780
781 if (!arc)
782 *ppxini = pXIni;
783 else
784 DosClose(hFile);
785 }
786 }
787
788 return arc;
789}
790
791/*
792 *@@ xprfQueryProfileSize:
793 * returns the size of INI data, similarly to
794 * what PrfQueryProfileSize does.
795 *
796 * If (pszAppName == NULL), this returns the size of
797 * the buffer required to hold the enumerated list
798 * of application names. pszKey is then ignored.
799 *
800 * Otherwise, if (pszKeyName == NULL), this returns
801 * the size of the buffer required to hold the
802 * enumerated list of _key_ names for the given
803 * application.
804 *
805 * If both pszAppName and pszKeyName are not NULL, this
806 * returns the data size of the given key.
807 *
808 * Returns:
809 *
810 * -- NO_ERROR
811 *
812 *@@added V1.0.0 (2002-09-17) [umoeller]
813 */
814
815APIRET xprfQueryProfileSize(PXINI pXIni, // in: profile opened with xprfOpenProfile
816 PCSZ pszAppName, // in: application name or NULL
817 PCSZ pszKeyName, // in: key name or NULL
818 PULONG pulDataLen) // out: size of requested data
819{
820 APIRET arc = NO_ERROR;
821 ULONG ulDataLen = 0;
822
823 if (!pszAppName)
824 {
825 PLISTNODE pAppNode = lstQueryFirstNode(&pXIni->llApps);
826 while (pAppNode)
827 {
828 PXINIAPPDATA pAppDataThis = (PXINIAPPDATA)pAppNode->pItemData;
829 ulDataLen += strlen(pAppDataThis->pszAppName) + 1;
830 pAppNode = pAppNode->pNext;
831 }
832
833 // extra byte for terminating extra null
834 ++ulDataLen;
835 }
836 else
837 {
838 // app specified:
839 PXINIAPPDATA pAppData;
840
841 if (!(arc = FindApp(pXIni,
842 pszAppName,
843 &pAppData)))
844 {
845 // app exists:
846
847 if (!pszKeyName)
848 {
849 // app != NULL, but key == NULL:
850 // return size of keys list
851 PLISTNODE pKeyNode = lstQueryFirstNode(&pAppData->llKeys);
852 while (pKeyNode)
853 {
854 PXINIKEYDATA pKeyDataThis = (PXINIKEYDATA)pKeyNode->pItemData;
855 ulDataLen += strlen(pKeyDataThis->pszKeyName) + 1;
856 pKeyNode = pKeyNode->pNext;
857 }
858
859 // extra byte for terminating extra null
860 ++ulDataLen;
861 }
862 else
863 {
864 // both app and key specified:
865 PXINIKEYDATA pKeyData;
866 if (!(arc = FindKey(pAppData,
867 pszKeyName,
868 &pKeyData)))
869 ulDataLen = pKeyData->cbData;
870 }
871 }
872 }
873
874 if (pulDataLen)
875 *pulDataLen = ulDataLen;
876
877 return arc;
878}
879
880/*
881 *@@ xprfQueryProfileData:
882 * reads data from the given XINI, similarly to
883 * what PrfQueryProfileData does.
884 *
885 * If (pszAppName == NULL), this returns the
886 * enumerated list of application names.
887 * pszKey is then ignored. *pulBufferMax
888 * receives the total size of the list excluding
889 * the final NULL character.
890 *
891 * Otherwise, if (pszKeyName == NULL), this the
892 * enumerated list of _key_ names for the given
893 * application. *pulBufferMax receives the total
894 * size of the list excluding the final NULL character.
895 *
896 * If both pszAppName and pszKeyName are not NULL,
897 * this returns the data of the given key.
898 * pulBufferMax receives the bytes copied.
899 *
900 * Returns:
901 *
902 * -- NO_ERROR
903 */
904
905APIRET xprfQueryProfileData(PXINI pXIni, // in: profile opened with xprfOpenProfile
906 PCSZ pszAppName, // in: application name
907 PCSZ pszKeyName, // in: key name or NULL
908 PVOID pBuffer, // in: buffer to receive data
909 PULONG pulBufferMax) // in: buffer size, out: size of written data
910{
911 APIRET arc = NO_ERROR;
912 ULONG ulDataLen = 0;
913
914 if (!pszAppName)
915 {
916 PLISTNODE pAppNode = lstQueryFirstNode(&pXIni->llApps);
917 PBYTE pbTarget = (PSZ)pBuffer;
918 ULONG cbCopied = 0;
919 while (pAppNode)
920 {
921 PXINIAPPDATA pAppDataThis = (PXINIAPPDATA)pAppNode->pItemData;
922 ULONG cbThis = strlen(pAppDataThis->pszAppName) + 1;
923 if (cbCopied + cbThis > *pulBufferMax)
924 break;
925 else
926 {
927 memcpy(pbTarget + cbCopied,
928 pAppDataThis->pszAppName,
929 cbThis);
930 cbCopied += cbThis;
931 }
932
933 pAppNode = pAppNode->pNext;
934 }
935
936 // extra byte for terminating extra null
937 pbTarget[cbCopied] = '\0';
938 ulDataLen = cbCopied; // PMREF says terminating null is not counted
939 }
940 else
941 {
942 // app specified:
943 PXINIAPPDATA pAppData;
944
945 if (!(arc = FindApp(pXIni,
946 pszAppName,
947 &pAppData)))
948 {
949 // app exists:
950
951 if (!pszKeyName)
952 {
953 // app != NULL, but key == NULL:
954 // return size of keys list
955 PLISTNODE pKeyNode = lstQueryFirstNode(&pAppData->llKeys);
956 PBYTE pbTarget = (PSZ)pBuffer;
957 ULONG cbCopied = 0;
958 while (pKeyNode)
959 {
960 PXINIKEYDATA pKeyDataThis = (PXINIKEYDATA)pKeyNode->pItemData;
961 ULONG cbThis = strlen(pKeyDataThis->pszKeyName) + 1;
962 if (cbCopied + cbThis > *pulBufferMax)
963 break;
964 else
965 {
966 memcpy(pbTarget + cbCopied,
967 pKeyDataThis->pszKeyName,
968 cbThis);
969 cbCopied += cbThis;
970 }
971
972 pKeyNode = pKeyNode->pNext;
973 }
974
975 // extra byte for terminating extra null
976 pbTarget[cbCopied] = '\0';
977 ulDataLen = cbCopied; // PMREF says terminating null is not counted
978 }
979 else
980 {
981 // both app and key specified:
982 PXINIKEYDATA pKeyData;
983 if (!(arc = FindKey(pAppData,
984 pszKeyName,
985 &pKeyData)))
986 {
987 ulDataLen = min(pKeyData->cbData,
988 *pulBufferMax);
989 memcpy(pBuffer,
990 pKeyData->pbData,
991 ulDataLen);
992 }
993 }
994 }
995 }
996
997 if (pulBufferMax)
998 *pulBufferMax = ulDataLen;
999
1000 return arc;
1001}
1002
1003/*
1004 *@@ xprfWriteProfileData:
1005 * writes data into an extended profile (XINI).
1006 * This operates similar to PrfWriteProfileData,
1007 * that is:
1008 *
1009 * -- If all of pcszApp, pcszKey, pData, and
1010 * ulDataLen are specified, the given data is
1011 * written into the specified application/key
1012 * pair.
1013 *
1014 * -- If pcszApp and pcszKey are specified, but
1015 * pData and ulDataLen are null, the specified
1016 * key is deleted.
1017 *
1018 * -- If pcszApp is specified, but all of pcszKey,
1019 * pData, and ulDataLen are null, the entire
1020 * specified application is deleted.
1021 *
1022 * You cannot specify HINI_SYSTEM or HINI_USER for
1023 * hINi.
1024 *
1025 * Note that if data has been added or removed,
1026 * the INI file on disk is not updated automatically.
1027 * Instead, our memory copy of it is only marked
1028 * as "dirty" so that the file will be rewritten
1029 * on xprfCloseProfile.
1030 *
1031 * Returns:
1032 *
1033 * -- NO_ERROR
1034 */
1035
1036APIRET xprfWriteProfileData(PXINI pXIni, // in: profile opened with xprfOpenProfile
1037 const char *pcszApp, // in: application name
1038 const char *pcszKey, // in: key name or NULL
1039 PVOID pData, // in: data to write or NULL
1040 ULONG ulDataLen) // in: sizeof(*pData) or null
1041{
1042 APIRET arc = NO_ERROR;
1043
1044 if ( (!pXIni)
1045 || (memcmp(pXIni->acMagic, XINI_MAGIC_BYTES, sizeof(XINI_MAGIC_BYTES)))
1046 )
1047 arc = ERROR_INVALID_PARAMETER;
1048 else
1049 {
1050 // check if application exists
1051 PXINIAPPDATA pAppData;
1052
1053 if (FindApp(pXIni,
1054 pcszApp,
1055 &pAppData))
1056 // not found:
1057 pAppData = NULL;
1058
1059 // now check: does caller want entire application deleted?
1060 if (!pcszKey)
1061 {
1062 // yes, delete application: did we find it?
1063 if (pAppData)
1064 {
1065 // yes: kill that
1066 FreeApp(pAppData);
1067 // and remove from list
1068 lstRemoveItem(&pXIni->llApps, pAppData);
1069
1070 // rewrite profile on close
1071 pXIni->fDirty = TRUE;
1072 }
1073 // else application doesn't exist:
1074 // nothing to do return NO_ERROR
1075 }
1076 else
1077 {
1078 // caller has specified key:
1079 // does caller want a key to be deleted?
1080 if (!ulDataLen)
1081 {
1082 // yes: delete key:
1083 if (pAppData)
1084 {
1085 // app exists:
1086 FreeKeyIfExists(pXIni,
1087 pAppData,
1088 pcszKey);
1089 }
1090 // else app doesn't even exist:
1091 // nothing to do, return NO_ERROR
1092 }
1093 else
1094 {
1095 // key and data specified: let's add something...
1096
1097 if (!pAppData)
1098 // app doesn't exist yet:
1099 // create
1100 arc = CreateApp(pXIni,
1101 pcszApp,
1102 &pAppData);
1103
1104 if (!arc)
1105 {
1106 // found or created app:
1107
1108 // delete existing key if it exists
1109 PXINIKEYDATA pKeyData;
1110
1111 FreeKeyIfExists(pXIni,
1112 pAppData,
1113 pcszKey);
1114
1115 // now create new key
1116 if (!(arc = CreateKey(pAppData,
1117 pcszKey,
1118 (PBYTE)pData,
1119 ulDataLen,
1120 &pKeyData)))
1121 // mark as dirty
1122 pXIni->fDirty = TRUE;
1123 }
1124 }
1125 }
1126 }
1127
1128 return arc;
1129}
1130
1131/*
1132 *@@ xprfCloseProfile:
1133 * closes a profile opened with xprfOpenProfile.
1134 * If the profile is "dirty", that is, if any data
1135 * has been changed using xprfWriteProfileData, the
1136 * file is written back to disk before closing.
1137 *
1138 * You cannot specify HINI_SYSTEM or HINI_USER for
1139 * hINi.
1140 *
1141 * Returns:
1142 *
1143 * -- NO_ERROR
1144 */
1145
1146APIRET xprfCloseProfile(PXINI pXIni) // in: profile opened with xprfOpenProfile
1147{
1148 APIRET arc = NO_ERROR;
1149
1150 if ( (!pXIni)
1151 || (memcmp(pXIni->acMagic, XINI_MAGIC_BYTES, sizeof(XINI_MAGIC_BYTES)))
1152 )
1153 arc = ERROR_INVALID_PARAMETER;
1154 else
1155 {
1156 if (pXIni->fDirty)
1157 arc = WriteINI(pXIni);
1158
1159 if (!arc)
1160 {
1161 if (!(arc = DosClose(pXIni->hFile)))
1162 {
1163 pXIni->hFile = 0;
1164
1165 FreeINI(pXIni);
1166 }
1167 }
1168 }
1169
1170 return arc;
1171}
1172
1173/*
1174 *@@ xprfQueryKeysForApp:
1175 * the equivalent of prfhQueryKeysForApp for
1176 * XINI files.
1177 *
1178 *@@added V1.0.0 (2002-09-17) [umoeller]
1179 */
1180
1181APIRET xprfQueryKeysForApp(PXINI hIni, // in: INI handle
1182 PCSZ pcszApp, // in: application to query list for (or NULL for applications list)
1183 PSZ *ppszKeys) // out: keys list (newly allocated)
1184{
1185 APIRET arc = NO_ERROR;
1186 PSZ pKeys = NULL;
1187 ULONG ulSizeOfKeysList = 0;
1188
1189 // get size of keys list for pszApp
1190 if (!xprfQueryProfileSize(hIni, pcszApp, NULL, &ulSizeOfKeysList))
1191 arc = PRFERR_KEYSLIST;
1192 else
1193 {
1194 if (ulSizeOfKeysList == 0)
1195 ulSizeOfKeysList = 1; // V0.9.19 (2002-04-11) [pr]
1196
1197 if (!(pKeys = (PSZ)malloc(ulSizeOfKeysList)))
1198 arc = ERROR_NOT_ENOUGH_MEMORY;
1199 else
1200 {
1201 *pKeys = 0;
1202 if (!xprfQueryProfileData(hIni, pcszApp, NULL, pKeys, &ulSizeOfKeysList))
1203 arc = PRFERR_KEYSLIST;
1204 }
1205 }
1206
1207 if (!arc) // V0.9.12 (2001-05-12) [umoeller]
1208 *ppszKeys = pKeys;
1209 else
1210 if (pKeys)
1211 free(pKeys);
1212
1213 return arc;
1214}
1215
Note: See TracBrowser for help on using the repository browser.