home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / xwphescr.zip / XWPH0208.ZIP / src / helpers / xprf.c < prev    next >
C/C++ Source or Header  |  2002-06-05  |  32KB  |  949 lines

  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.  
  125. typedef 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.  
  137. typedef 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.  
  159. static PXINIAPPDATA 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.  
  185. static PXINIAPPDATA 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.  
  212. static PXINIKEYDATA 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.  
  238. static PXINIKEYDATA 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.  
  276. static VOID 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.  
  294. static VOID 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.  
  321. static BOOL 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.  
  358. static BOOL 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.  
  459. static BOOL 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.  
  685. APIRET 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.  
  796. BOOL 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.  
  913. BOOL 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.  
  949.