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

Last change on this file since 420 was 391, checked in by pr, 14 years ago

Add NOINHERIT flag to xprfOpen

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 41.2 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-2011 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(PCSZ 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 // WarpIN V1.0.20 (2011-07-08) [pr]: add NOINHERIT
744 if (!(arc = DosOpen((PSZ)pcszFilename,
745 &hFile,
746 &ulAction,
747 1024, // initial size
748 FILE_NORMAL,
749 OPEN_ACTION_CREATE_IF_NEW
750 | OPEN_ACTION_OPEN_IF_EXISTS,
751 OPEN_FLAGS_FAIL_ON_ERROR
752 | OPEN_FLAGS_SEQUENTIAL
753 | OPEN_FLAGS_NOINHERIT
754 | OPEN_SHARE_DENYREADWRITE
755 | OPEN_ACCESS_READWRITE,
756 NULL)))
757 {
758 if (!(pXIni = (PXINI)malloc(sizeof(XINI))))
759 arc = ERROR_NOT_ENOUGH_MEMORY;
760 else
761 {
762 // OK: initialize XINI
763 memset(pXIni, 0, sizeof(XINI));
764 memcpy(pXIni->acMagic, XINI_MAGIC_BYTES, sizeof(XINI_MAGIC_BYTES));
765 memcpy(pXIni->szFilename,
766 pcszFilename,
767 ulFilenameLen + 1);
768 pXIni->hFile = hFile;
769 // pXIni->hLock = hLock;
770
771 lstInit(&pXIni->llApps, FALSE);
772
773 if (ulAction == FILE_CREATED)
774 // file newly created: rewrite on close
775 pXIni->fDirty = TRUE;
776 else
777 // file existed: read data
778 if (arc = ReadINI(pXIni))
779 // error:
780 FreeINI(pXIni);
781 }
782
783 if (!arc)
784 *ppxini = pXIni;
785 else
786 DosClose(hFile);
787 }
788 }
789
790 return arc;
791}
792
793/*
794 *@@ xprfQueryProfileSize:
795 * returns the size of INI data, similarly to
796 * what PrfQueryProfileSize does.
797 *
798 * If (pszAppName == NULL), this returns the size of
799 * the buffer required to hold the enumerated list
800 * of application names. pszKey is then ignored.
801 *
802 * Otherwise, if (pszKeyName == NULL), this returns
803 * the size of the buffer required to hold the
804 * enumerated list of _key_ names for the given
805 * application.
806 *
807 * If both pszAppName and pszKeyName are not NULL, this
808 * returns the data size of the given key.
809 *
810 * Returns:
811 *
812 * -- NO_ERROR
813 *
814 *@@added V1.0.0 (2002-09-17) [umoeller]
815 */
816
817APIRET xprfQueryProfileSize(PXINI pXIni, // in: profile opened with xprfOpenProfile
818 PCSZ pcszAppName, // in: application name or NULL
819 PCSZ pcszKeyName, // in: key name or NULL
820 PULONG pulDataLen) // out: size of requested data
821{
822 APIRET arc = NO_ERROR;
823 ULONG ulDataLen = 0;
824
825 if (!pcszAppName)
826 {
827 PLISTNODE pAppNode = lstQueryFirstNode(&pXIni->llApps);
828 while (pAppNode)
829 {
830 PXINIAPPDATA pAppDataThis = (PXINIAPPDATA)pAppNode->pItemData;
831 ulDataLen += strlen(pAppDataThis->pszAppName) + 1;
832 pAppNode = pAppNode->pNext;
833 }
834
835 // extra byte for terminating extra null
836 ++ulDataLen;
837 }
838 else
839 {
840 // app specified:
841 PXINIAPPDATA pAppData;
842
843 if (!(arc = FindApp(pXIni,
844 pcszAppName,
845 &pAppData)))
846 {
847 // app exists:
848
849 if (!pcszKeyName)
850 {
851 // app != NULL, but key == NULL:
852 // return size of keys list
853 PLISTNODE pKeyNode = lstQueryFirstNode(&pAppData->llKeys);
854 while (pKeyNode)
855 {
856 PXINIKEYDATA pKeyDataThis = (PXINIKEYDATA)pKeyNode->pItemData;
857 ulDataLen += strlen(pKeyDataThis->pszKeyName) + 1;
858 pKeyNode = pKeyNode->pNext;
859 }
860
861 // extra byte for terminating extra null
862 ++ulDataLen;
863 }
864 else
865 {
866 // both app and key specified:
867 PXINIKEYDATA pKeyData;
868 if (!(arc = FindKey(pAppData,
869 pcszKeyName,
870 &pKeyData)))
871 ulDataLen = pKeyData->cbData;
872 }
873 }
874 }
875
876 if (pulDataLen)
877 *pulDataLen = ulDataLen;
878
879 return arc;
880}
881
882/*
883 *@@ xprfQueryProfileData:
884 * reads data from the given XINI, similarly to
885 * what PrfQueryProfileData does.
886 *
887 * If (pszAppName == NULL), this returns the
888 * enumerated list of application names.
889 * pszKey is then ignored. *pulBufferMax
890 * receives the total size of the list excluding
891 * the final NULL character.
892 *
893 * Otherwise, if (pszKeyName == NULL), this the
894 * enumerated list of _key_ names for the given
895 * application. *pulBufferMax receives the total
896 * size of the list excluding the final NULL character.
897 *
898 * If both pszAppName and pszKeyName are not NULL,
899 * this returns the data of the given key.
900 * pulBufferMax receives the bytes copied.
901 *
902 * Returns:
903 *
904 * -- NO_ERROR
905 */
906
907APIRET xprfQueryProfileData(PXINI pXIni, // in: profile opened with xprfOpenProfile
908 PCSZ pcszAppName, // in: application name
909 PCSZ pcszKeyName, // in: key name or NULL
910 PVOID pBuffer, // in: buffer to receive data
911 PULONG pulBufferMax) // in: buffer size, out: size of written data
912{
913 APIRET arc = NO_ERROR;
914 ULONG ulDataLen = 0;
915
916 if (!pcszAppName)
917 {
918 PLISTNODE pAppNode = lstQueryFirstNode(&pXIni->llApps);
919 PBYTE pbTarget = (PSZ)pBuffer;
920 ULONG cbCopied = 0;
921 while (pAppNode)
922 {
923 PXINIAPPDATA pAppDataThis = (PXINIAPPDATA)pAppNode->pItemData;
924 ULONG cbThis = strlen(pAppDataThis->pszAppName) + 1;
925 if (cbCopied + cbThis > *pulBufferMax)
926 break;
927 else
928 {
929 memcpy(pbTarget + cbCopied,
930 pAppDataThis->pszAppName,
931 cbThis);
932 cbCopied += cbThis;
933 }
934
935 pAppNode = pAppNode->pNext;
936 }
937
938 // extra byte for terminating extra null
939 pbTarget[cbCopied] = '\0';
940 ulDataLen = cbCopied; // PMREF says terminating null is not counted
941 }
942 else
943 {
944 // app specified:
945 PXINIAPPDATA pAppData;
946
947 if (!(arc = FindApp(pXIni,
948 pcszAppName,
949 &pAppData)))
950 {
951 // app exists:
952
953 if (!pcszKeyName)
954 {
955 // app != NULL, but key == NULL:
956 // return size of keys list
957 PLISTNODE pKeyNode = lstQueryFirstNode(&pAppData->llKeys);
958 PBYTE pbTarget = (PSZ)pBuffer;
959 ULONG cbCopied = 0;
960 while (pKeyNode)
961 {
962 PXINIKEYDATA pKeyDataThis = (PXINIKEYDATA)pKeyNode->pItemData;
963 ULONG cbThis = strlen(pKeyDataThis->pszKeyName) + 1;
964 if (cbCopied + cbThis > *pulBufferMax)
965 break;
966 else
967 {
968 memcpy(pbTarget + cbCopied,
969 pKeyDataThis->pszKeyName,
970 cbThis);
971 cbCopied += cbThis;
972 }
973
974 pKeyNode = pKeyNode->pNext;
975 }
976
977 // extra byte for terminating extra null
978 pbTarget[cbCopied] = '\0';
979 ulDataLen = cbCopied; // PMREF says terminating null is not counted
980 }
981 else
982 {
983 // both app and key specified:
984 PXINIKEYDATA pKeyData;
985 if (!(arc = FindKey(pAppData,
986 pcszKeyName,
987 &pKeyData)))
988 {
989 ulDataLen = min(pKeyData->cbData,
990 *pulBufferMax);
991 memcpy(pBuffer,
992 pKeyData->pbData,
993 ulDataLen);
994 }
995 }
996 }
997 }
998
999 if (pulBufferMax)
1000 *pulBufferMax = ulDataLen;
1001
1002 return arc;
1003}
1004
1005/*
1006 *@@ xprfQueryProfileInt:
1007 * reads data from the given XINI, similarly to
1008 * what PrfQueryProfileInt does.
1009 *
1010 * You cannot specify HINI_SYSTEM or HINI_USER for
1011 * hINi.
1012 *
1013 *@@added WarpIN V1.0.18 (2008-10-04) [pr]
1014 */
1015
1016LONG xprfQueryProfileInt(PXINI pXIni,
1017 PCSZ pcszApp,
1018 PCSZ pcszKey,
1019 LONG lDefault)
1020{
1021 char szBuffer[20];
1022 LONG lVal = lDefault;
1023 ULONG ulSize = sizeof(szBuffer) - 1;
1024
1025 if (pcszApp && pcszApp[0] && pcszKey && pcszKey[0] &&
1026 !xprfQueryProfileData(pXIni, pcszApp, pcszKey, szBuffer, &ulSize))
1027 {
1028 szBuffer[ulSize] = '\0';
1029 lVal = atol(szBuffer);
1030 }
1031
1032 return lVal;
1033}
1034
1035/*
1036 *@@ xprfWriteProfileData:
1037 * writes data into an extended profile (XINI).
1038 * This operates similar to PrfWriteProfileData,
1039 * that is:
1040 *
1041 * -- If all of pcszApp, pcszKey, pData, and
1042 * ulDataLen are specified, the given data is
1043 * written into the specified application/key
1044 * pair.
1045 *
1046 * -- If pcszApp and pcszKey are specified, but
1047 * pData and ulDataLen are null, the specified
1048 * key is deleted.
1049 *
1050 * -- If pcszApp is specified, but all of pcszKey,
1051 * pData, and ulDataLen are null, the entire
1052 * specified application is deleted.
1053 *
1054 * You cannot specify HINI_SYSTEM or HINI_USER for
1055 * hINi.
1056 *
1057 * Note that if data has been added or removed,
1058 * the INI file on disk is not updated automatically.
1059 * Instead, our memory copy of it is only marked
1060 * as "dirty" so that the file will be rewritten
1061 * on xprfCloseProfile.
1062 *
1063 * Returns:
1064 *
1065 * -- NO_ERROR
1066 */
1067
1068APIRET xprfWriteProfileData(PXINI pXIni, // in: profile opened with xprfOpenProfile
1069 PCSZ pcszApp, // in: application name
1070 PCSZ pcszKey, // in: key name or NULL
1071 PVOID pData, // in: data to write or NULL
1072 ULONG ulDataLen) // in: sizeof(*pData) or null
1073{
1074 APIRET arc = NO_ERROR;
1075
1076 if ( (!pXIni)
1077 || (memcmp(pXIni->acMagic, XINI_MAGIC_BYTES, sizeof(XINI_MAGIC_BYTES)))
1078 )
1079 arc = ERROR_INVALID_PARAMETER;
1080 else
1081 {
1082 // check if application exists
1083 PXINIAPPDATA pAppData;
1084
1085 if (FindApp(pXIni,
1086 pcszApp,
1087 &pAppData))
1088 // not found:
1089 pAppData = NULL;
1090
1091 // now check: does caller want entire application deleted?
1092 if (!pcszKey)
1093 {
1094 // yes, delete application: did we find it?
1095 if (pAppData)
1096 {
1097 // yes: kill that
1098 FreeApp(pAppData);
1099 // and remove from list
1100 lstRemoveItem(&pXIni->llApps, pAppData);
1101
1102 // rewrite profile on close
1103 pXIni->fDirty = TRUE;
1104 }
1105 // else application doesn't exist:
1106 // nothing to do return NO_ERROR
1107 }
1108 else
1109 {
1110 // caller has specified key:
1111 // does caller want a key to be deleted?
1112 if (!ulDataLen)
1113 {
1114 // yes: delete key:
1115 if (pAppData)
1116 {
1117 // app exists:
1118 FreeKeyIfExists(pXIni,
1119 pAppData,
1120 pcszKey);
1121 }
1122 // else app doesn't even exist:
1123 // nothing to do, return NO_ERROR
1124 }
1125 else
1126 {
1127 // key and data specified: let's add something...
1128
1129 if (!pAppData)
1130 // app doesn't exist yet:
1131 // create
1132 arc = CreateApp(pXIni,
1133 pcszApp,
1134 &pAppData);
1135
1136 if (!arc)
1137 {
1138 // found or created app:
1139
1140 // delete existing key if it exists
1141 PXINIKEYDATA pKeyData;
1142
1143 FreeKeyIfExists(pXIni,
1144 pAppData,
1145 pcszKey);
1146
1147 // now create new key
1148 if (!(arc = CreateKey(pAppData,
1149 pcszKey,
1150 (PBYTE)pData,
1151 ulDataLen,
1152 &pKeyData)))
1153 // mark as dirty
1154 pXIni->fDirty = TRUE;
1155 }
1156 }
1157 }
1158 }
1159
1160 return arc;
1161}
1162
1163/*
1164 *@@ xprfWriteProfileString:
1165 * writes string into an extended profile (XINI).
1166 * This operates similar to PrfWriteProfileString.
1167 *
1168 * You cannot specify HINI_SYSTEM or HINI_USER for
1169 * hINi.
1170 *
1171 *@@added WarpIN V1.0.18 (2008-10-04) [pr]
1172 */
1173
1174APIRET xprfWriteProfileString(PXINI pXIni, // in: profile opened with xprfOpenProfile
1175 PCSZ pcszApp, // in: application name
1176 PCSZ pcszKey, // in: key name or NULL
1177 PCSZ pcszString) // in: string to write or NULL
1178{
1179 ULONG ulDataLen = 0;
1180
1181 if (pcszString)
1182 ulDataLen = strlen(pcszString) + 1;
1183
1184 return xprfWriteProfileData(pXIni, pcszApp, pcszKey, (PVOID) pcszString, ulDataLen);
1185}
1186
1187/*
1188 *@@ xprfCloseProfile:
1189 * closes a profile opened with xprfOpenProfile.
1190 * If the profile is "dirty", that is, if any data
1191 * has been changed using xprfWriteProfileData, the
1192 * file is written back to disk before closing.
1193 *
1194 * You cannot specify HINI_SYSTEM or HINI_USER for
1195 * hINi.
1196 *
1197 * Returns:
1198 *
1199 * -- NO_ERROR
1200 */
1201
1202APIRET xprfCloseProfile(PXINI pXIni) // in: profile opened with xprfOpenProfile
1203{
1204 APIRET arc = NO_ERROR;
1205
1206 if ( (!pXIni)
1207 || (memcmp(pXIni->acMagic, XINI_MAGIC_BYTES, sizeof(XINI_MAGIC_BYTES)))
1208 )
1209 arc = ERROR_INVALID_PARAMETER;
1210 else
1211 {
1212 if (pXIni->fDirty)
1213 arc = WriteINI(pXIni);
1214
1215 if (!arc)
1216 {
1217 if (!(arc = DosClose(pXIni->hFile)))
1218 {
1219 pXIni->hFile = 0;
1220
1221 FreeINI(pXIni);
1222 }
1223 }
1224 }
1225
1226 return arc;
1227}
1228
1229/*
1230 *@@ xprfQueryKeysForApp:
1231 * the equivalent of prfhQueryKeysForApp for
1232 * XINI files.
1233 *
1234 *@@added V1.0.0 (2002-09-17) [umoeller]
1235 *@@changed WarpIN V1.0.18 (2008-10-04) [pr]: fixed inverted logic bugs
1236 */
1237
1238APIRET xprfQueryKeysForApp(PXINI hIni, // in: INI handle
1239 PCSZ pcszApp, // in: application to query list for (or NULL for applications list)
1240 PSZ *ppszKeys) // out: keys list (newly allocated)
1241{
1242 APIRET arc = NO_ERROR;
1243 PSZ pKeys = NULL;
1244 ULONG ulSizeOfKeysList = 0;
1245
1246 // get size of keys list for pszApp
1247 if (xprfQueryProfileSize(hIni, pcszApp, NULL, &ulSizeOfKeysList))
1248 arc = PRFERR_KEYSLIST;
1249 else
1250 {
1251 if (ulSizeOfKeysList == 0)
1252 ulSizeOfKeysList = 1; // V0.9.19 (2002-04-11) [pr]
1253
1254 if (!(pKeys = (PSZ)malloc(ulSizeOfKeysList)))
1255 arc = ERROR_NOT_ENOUGH_MEMORY;
1256 else
1257 {
1258 *pKeys = 0;
1259 if (xprfQueryProfileData(hIni, pcszApp, NULL, pKeys, &ulSizeOfKeysList))
1260 arc = PRFERR_KEYSLIST;
1261 }
1262 }
1263
1264 if (!arc) // V0.9.12 (2001-05-12) [umoeller]
1265 *ppszKeys = pKeys;
1266 else
1267 if (pKeys)
1268 free(pKeys);
1269
1270 return arc;
1271}
1272
1273/*
1274 *@@ xprfhQueryProfileData:
1275 * the equivalent of prfhQueryProfileData for
1276 * XINI files.
1277 *
1278 *@@added WarpIN V1.0.18 (2008-10-04) [pr]
1279 */
1280
1281PSZ xprfhQueryProfileData(PXINI pXIni, // in: INI handle
1282 PCSZ pcszApp, // in: application to query
1283 PCSZ pcszKey, // in: key to query
1284 PULONG pcbBuf) // out: size of the returned buffer; ptr can be NULL
1285{
1286 PSZ pData = NULL;
1287 ULONG ulSizeOfData;
1288
1289 // get size of data for pcszApp/pcszKey
1290 if ( (!xprfQueryProfileSize(pXIni, (PSZ)pcszApp, (PSZ)pcszKey, &ulSizeOfData))
1291 && (ulSizeOfData)
1292 && (pData = (PSZ)malloc(ulSizeOfData))
1293 )
1294 {
1295 if (xprfQueryProfileData(pXIni, (PSZ)pcszApp, (PSZ)pcszKey, pData, &ulSizeOfData))
1296 {
1297 free(pData);
1298 pData = NULL;
1299 }
1300 }
1301
1302 if (pcbBuf)
1303 *pcbBuf = ulSizeOfData;
1304
1305 return pData;
1306}
1307
Note: See TracBrowser for help on using the repository browser.