home *** CD-ROM | disk | FTP | other *** search
/ Launch & Play / spustahrej2.iso / Egoboo / code / configfile.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-12-03  |  22.9 KB  |  844 lines

  1.  
  2. //---------------------------------------------------------------------
  3. //
  4. //    ConfigFile.c
  5. //
  6. //    - All functions to manage a ConfigFile
  7. //
  8. //  A ConfigFile contains sections which themselves contains values.
  9. //    A section name is contained between "{}" Ex: {Section Name}
  10. //
  11. //    A value has a Key, a string value and an optional commentary.
  12. //    The Key is contained between "[]" Ex: [Key Name]
  13. //    The string value is contained between '"' Ex: "TRUE"
  14. //  To include a '"' in a string value, the '"' are doubled
  15. //  The commentary follows the string value on the same line and 
  16. //    begins with "//"
  17. //
  18. //    Exemple of a ConfigFile:
  19. //    {Section 1}
  20. //    [Key1] : "TRUE" // This is a commentary
  21. //    [Key2] : "Hello ""MAN""" // this will become : Hello "MAN"
  22. //
  23. // To do :    
  24. //            optimisation
  25. //            error checking
  26. //            Run-time commentary editing
  27. //
  28. // Bugs:
  29. //        -    Multiple section with the same name will be loaded and saved but only the first
  30. //            one will be looked for value. Should not load sections with same name.
  31. //
  32. //
  33. // History:
  34. //
  35. //    2001-01-09
  36. //        - Implemented ConvertToKeyCharacters in SetConfigValue
  37. //
  38. //    2000-12-10
  39. //        -    Added the length of the string buffer used as parameter for GetConfigValue.
  40. //        -    Added SetConfigBooleanValue, SetConfigIntVaalue and SetConfigFloatValue to standardise
  41. //            the way to set usual data types.
  42. //        -    Added GetConfigBooleanValue, GetConfigIntValue and GetConfigFloatValue.
  43. //---------------------------------------------------------------------
  44.  
  45.  
  46. #include "configfile.h"
  47.  
  48. // Change any non alphanumeric character or space or underscore to an underscore
  49. // It is use for the section and key name
  50. void ConvertToKeyCharacters( char *pStr )
  51. {
  52.     Sint32 lCompt = 0;
  53.     char lc;
  54.  
  55.     if ( pStr == NULL )
  56.     {
  57.         return;
  58.     }
  59.     
  60.  
  61.     lc = pStr[lCompt];
  62.     while( lc != 0 )
  63.     {
  64.         if ( !(isalnum( lc ) || isspace( lc ) || lc == '_') )
  65.             {
  66.             pStr[lCompt] = '_';
  67.             }
  68.         lc = pStr[++lCompt];
  69.     }
  70. }
  71.  
  72.  
  73. // PassOverConfigCommentary reads the pConfigFile's file until the end of a line.
  74. Sint32 PassOverConfigCommentary( ConfigFilePtr pConfigFile )
  75. {
  76.     char lc;
  77.  
  78.     lc = fgetc( pConfigFile->f );
  79.     while ( lc != 13 && lc != 10 && !feof( pConfigFile->f ) )
  80.     {
  81.         lc = fgetc( pConfigFile->f );
  82.     }
  83.     return 0;
  84. }
  85.  
  86. // ReadSectionName reads characters from the config file until it encounters
  87. // an end of section name "}". The resulting string is copied in pSection->SectionName.
  88. // The length of the name is returned, or 0 if there is an error.
  89. //
  90. // if the string is longer than MAX_CONFIG_SECTION_LENGTH, the string is truncated
  91. //
  92. Sint32 ReadConfigSectionName( ConfigFilePtr pConfigFile, ConfigFileSectionPtr pSection )
  93. {
  94.     Sint32 lLenghtName = 0;
  95.     char lc;
  96.  
  97.     lc = fgetc( pConfigFile->f );
  98.     memset( pSection->SectionName, 0, MAX_CONFIG_SECTION_LENGTH );
  99.     while ( lc != '}' && !feof( pConfigFile->f ) )
  100.     {
  101.         if ( lLenghtName < MAX_CONFIG_SECTION_LENGTH )
  102.         {
  103.             pSection->SectionName[lLenghtName] = lc;
  104.         }
  105.         lLenghtName++;
  106.         lc = fgetc( pConfigFile->f );
  107.     }
  108.     if ( feof( pConfigFile->f ) )
  109.     {
  110.         return 0;
  111.     }
  112.     return lLenghtName;
  113. }
  114.  
  115. // ReadKeyName reads characters from the config file until it encounters
  116. // an end of key name "]". The resulting string is copied in pValue->KeyName.
  117. // The length of the name is returned, or 0 if there is an error.
  118. //
  119. // if the string is longuer than MAX_CONFIG_KEY_LENGTH, the string is truncated
  120. //
  121. long ReadConfigKeyName( ConfigFilePtr pConfigFile, ConfigFileValuePtr pValue )
  122. {
  123.     Sint32 lLenghtName = 0;
  124.     char lc;
  125.  
  126.     lc = fgetc( pConfigFile->f );
  127.     memset( pValue->KeyName, 0, MAX_CONFIG_KEY_LENGTH );
  128.     while ( lc != ']' && !feof( pConfigFile->f ) )
  129.     {
  130.         if ( lLenghtName < MAX_CONFIG_KEY_LENGTH )
  131.         {
  132.             pValue->KeyName[lLenghtName] = lc;
  133.         }
  134.         lLenghtName++;
  135.         lc = fgetc( pConfigFile->f );
  136.     }
  137.     if ( feof( pConfigFile->f ) )
  138.     {
  139.         return 0;
  140.     }
  141.     return lLenghtName;
  142. }
  143.  
  144. // ReadConfigValue reads characters from the config file until it encounters
  145. // an end of value '"'. The resulting string is copied in pValue->Value.
  146. // The length of the value is returned, or -1 if there is an error.
  147. //
  148. // The memory for pValue->Value is allocated here.
  149. //
  150. Sint32 ReadConfigValue( ConfigFilePtr pConfigFile, ConfigFileValuePtr pValue )
  151. {
  152.     static char lTempStr[MAX_CONFIG_VALUE_LENGTH];
  153.     char lc;
  154.     Sint32        lEndScan = 0;
  155.     Sint32        lState = 0;
  156.     Sint32    lLenghtName = 0;
  157.  
  158.     memset( lTempStr, 0, MAX_CONFIG_VALUE_LENGTH );
  159.     while ( !lEndScan )
  160.     {
  161.         lc = fgetc( pConfigFile->f );
  162.         switch ( lState )
  163.         {
  164.             case 0:
  165.                 // search for end of string '"'
  166.                 if ( lc == '"' )
  167.                 {
  168.                     // state change : 
  169.                     lState = 1;
  170.                 }
  171.                 else if ( lc == 13 || lc == 10 || feof( pConfigFile->f ) )
  172.                 {
  173.                     // error
  174.                     lEndScan = 1;
  175.                 }
  176.                 else
  177.                 {
  178.                     // add in string
  179.                     if ( lLenghtName < MAX_CONFIG_VALUE_LENGTH )
  180.                     {
  181.                         lTempStr[lLenghtName] = lc;
  182.                         lLenghtName++;
  183.                     }
  184.                 }
  185.                 break;
  186.             case 1:
  187.                 // check if really end of string
  188.                 if ( lc == '"' )
  189.                 {
  190.                     // add '"' in string
  191.                     if ( lLenghtName < MAX_CONFIG_VALUE_LENGTH )
  192.                     {
  193.                         lTempStr[lLenghtName] = lc;
  194.                         lLenghtName++;
  195.                     }
  196.                     lState = 0;
  197.                     // continue scan
  198.                 }
  199.                 else
  200.                 {
  201.                     // restore the char for next scan
  202.                     ungetc( lc, pConfigFile->f );
  203.                     // succesfull scan
  204.                     // allocate memory for value
  205.                     pValue->Value = ( char * ) malloc( lLenghtName + 1 );
  206.                     // copy string 
  207.                     strcpy( pValue->Value, lTempStr );
  208.                     // exit scan
  209.                     lEndScan = 1;
  210.                 } 
  211.                 break;
  212.             default:
  213.                 // error
  214.                 lEndScan = 1;
  215.                 break;
  216.         }
  217.     }
  218.     return lLenghtName;
  219. }
  220.  
  221. // ReadConfigCommentary reads characters from the config file until it encounters
  222. // an end of commentary chr(13). The resulting string is copied in pValue->Value.
  223. // The length of the value is returned, or -1 if there is an error.
  224. //
  225. // The memory for pValue->Commentary is allocated here.
  226. //
  227. Sint32 ReadConfigCommentary( ConfigFilePtr pConfigFile, ConfigFileValuePtr pValue )
  228. {
  229.     static char lTempStr[MAX_CONFIG_COMMENTARY_LENGTH];
  230.     char lc;
  231.     Sint32        lEndScan = 0;
  232.     Sint32        lState = 0;
  233.     Sint32    lLenghtName = 0;
  234.  
  235.     memset( lTempStr, 0, MAX_CONFIG_COMMENTARY_LENGTH );
  236.     while ( !lEndScan )
  237.     {
  238.         lc = fgetc( pConfigFile->f );
  239.         switch ( lState )
  240.         {
  241.             case 0:
  242.                 // search for end of string '"'
  243.                 if ( lc == '/' ||  lc == ' ')
  244.                 {
  245.                     // continue scan until a letter appears 
  246.                     
  247.                 }
  248.                 else if ( lc == 13 || lc == 10 || feof(pConfigFile->f) )
  249.                 {
  250.                     // error
  251.                     lEndScan = 1;
  252.                 }
  253.                 else
  254.                 {
  255.                     // add in string
  256.                     if ( lLenghtName < MAX_CONFIG_COMMENTARY_LENGTH )
  257.                     {
  258.                         lTempStr[lLenghtName] = lc;
  259.                         lLenghtName++;
  260.                     }
  261.                     // state change : continu until endl
  262.                     lState = 1;
  263.                 }
  264.                 break;
  265.             case 1:
  266.                 // check if really end of string
  267.                 if ( lc == 13 || lc == 10 || feof( pConfigFile->f ) )
  268.                 {
  269.                     // allocate memory for commentary
  270.                     pValue->Commentary = ( char * ) malloc( lLenghtName + 1 );
  271.                     // copy string 
  272.                     strcpy( pValue->Commentary, lTempStr );
  273.                     // exit scan
  274.                     lEndScan = 1;
  275.                 }
  276.                 else
  277.                 {
  278.                     // add in string
  279.                     if ( lLenghtName < MAX_CONFIG_COMMENTARY_LENGTH )
  280.                     {
  281.                         lTempStr[lLenghtName] = lc;
  282.                         lLenghtName++;
  283.                     }
  284.                 } 
  285.                 break;
  286.             default:
  287.                 // error
  288.                 lEndScan = 1;
  289.                 break;
  290.         }
  291.     }
  292.     return lLenghtName;
  293. }
  294.  
  295. // OpenConfigFile opens a ConfigFile for reading values.
  296. // 
  297. // If the path doesn't exist, OpenConfigFile returns NULL.
  298. // OpenConfigFile allocates the memory for the ConfigFile. To
  299. // deallocate the memory, use CloseConfigFile
  300. ConfigFilePtr OpenConfigFile( const char *pPath )
  301. {
  302.     ConfigFilePtr            lTempConfig = NULL;
  303.     FILE                    *lTempFile;
  304.     ConfigFileSectionPtr    lCurSection = NULL;
  305.     ConfigFileValuePtr        lCurValue = NULL;
  306.     Sint32                        lError = 0;
  307.     Sint32                        lState = 0;
  308.     char                    lc;
  309.  
  310.     lTempFile = fopen( pPath, "rt+" );
  311.     if ( lTempFile != NULL )
  312.     {
  313.         lTempConfig = (ConfigFilePtr) malloc( sizeof(ConfigFile) );
  314.         lTempConfig->f = lTempFile;
  315.         lTempConfig->ConfigSectionList = NULL;
  316.         lTempConfig->CurrentSection = NULL;
  317.         lTempConfig->CurrentValue = NULL;
  318.  
  319.         // load all values in memory
  320.         while ( !lError && !feof( lTempConfig->f ) )
  321.         {
  322.             lc = fgetc( lTempConfig->f );
  323.             switch( lState )
  324.             {
  325.                 case 0:
  326.                     // search for section ( start )
  327.                     if ( lc == '{' )
  328.                     {
  329.                         // create first section and load name
  330.                         lTempConfig->ConfigSectionList = ( ConfigFileSectionPtr ) malloc( sizeof( ConfigFileSection ) );
  331.                         memset( lTempConfig->ConfigSectionList, 0, sizeof( ConfigFileSection ) );
  332.                         lCurSection = lTempConfig->ConfigSectionList;
  333.                         ReadConfigSectionName( lTempConfig, lTempConfig->ConfigSectionList );
  334.                         lCurValue = NULL; // just to be safe
  335.                         // state change : look for new value or section
  336.                         lState = 1;
  337.                     }
  338.                     else if ( lc == '/' )
  339.                     {
  340.                         // pass over commentary ( bad!!! will be lost )
  341.                         PassOverConfigCommentary( lTempConfig );
  342.                     }
  343.                     break;
  344.                 case 1:
  345.                     // search for next value ( key name ) or next section
  346.                     if ( lc == '{' )
  347.                     {
  348.                         // create new section and load name
  349.                         lCurSection->NextSection = ( ConfigFileSectionPtr ) malloc( sizeof( ConfigFileSection ) );
  350.                         lCurSection = lCurSection->NextSection;
  351.                         memset( lCurSection, 0, sizeof( ConfigFileSection ) );
  352.                         ReadConfigSectionName( lTempConfig, lCurSection );
  353.                         lCurValue = NULL;
  354.                     }
  355.                     else if ( lc == '[' )
  356.                     {
  357.                         // create new value in current section and load key name
  358.                         if ( lCurValue == NULL )
  359.                         {
  360.                             // first value in section
  361.                             lCurSection->FirstValue = ( ConfigFileValuePtr ) malloc( sizeof( ConfigFileValue ) );
  362.                             lCurValue = lCurSection->FirstValue;
  363.                         }
  364.                         else
  365.                         {
  366.                             // link to new value
  367.                             lCurValue->NextValue = ( ConfigFileValuePtr ) malloc( sizeof( ConfigFileValue ) );
  368.                             lCurValue = lCurValue->NextValue;
  369.                         }
  370.                         memset( lCurValue, 0, sizeof( ConfigFileValue ) );
  371.                         ReadConfigKeyName( lTempConfig, lCurValue );
  372.                         
  373.                         // state change : get value
  374.                         lState = 2;
  375.                     }
  376.                     else if ( lc == '/' )
  377.                     {
  378.                         // pass over commentary ( bad!!! will be lost )
  379.                         PassOverConfigCommentary( lTempConfig );
  380.                     }
  381.                     break;
  382.                 case 2:
  383.                     // search for value
  384.                     if ( lc == '"' )
  385.                     {
  386.                         // load value in current value
  387.                         ReadConfigValue( lTempConfig, lCurValue );
  388.                         // state change : look for commentary
  389.                         lState = 3;
  390.                     }
  391.                     break;
  392.                 case 3:
  393.                     // search for commentary
  394.                     if ( lc == '/' )
  395.                     {
  396.                         //load commentary in current value
  397.                         ReadConfigCommentary( lTempConfig, lCurValue );
  398.                         // state change : look for new value or section
  399.                         lState = 1;
  400.                     }
  401.                     else if ( lc == 10 || lc == 13)
  402.                     {
  403.                         // state change : look for new value or section
  404.                         lState = 1;
  405.                     }
  406.                     break;
  407.                 case 100:
  408.                     // error
  409.                     lError = 1;
  410.                     break;
  411.                 default:
  412.                     // error
  413.                     lError = 1;
  414.                     break;
  415.             }
  416.         }
  417.     }
  418.     return lTempConfig;
  419. }
  420.  
  421. // SetConfigCurrentSection 
  422. //
  423. // Set the current section of pConfigFile to the one specified by pSection
  424. // If the section doesn't exist, the current section is set to NULL and the 
  425. // function returns 0, otherwise the it returns 1.
  426. long SetConfigCurrentSection( ConfigFilePtr pConfigFile, const char *pSection )
  427. {
  428.     long lFound = 0;
  429.     if ( pConfigFile == NULL || pSection == NULL )
  430.     {
  431.         return 0;
  432.     }
  433.     if ( pConfigFile->CurrentSection == NULL )
  434.     {
  435.         pConfigFile->CurrentSection = pConfigFile->ConfigSectionList;
  436.         while ( !lFound && (pConfigFile->CurrentSection != NULL) )
  437.         {
  438.             if ( strcmp( pConfigFile->CurrentSection->SectionName, pSection ) == 0 )
  439.             {
  440.                 lFound = 1;
  441.             }
  442.             else
  443.             {
  444.                 pConfigFile->CurrentSection = pConfigFile->CurrentSection->NextSection;
  445.             }
  446.         }
  447.     }
  448.     else
  449.     {
  450.         if ( strcmp( pConfigFile->CurrentSection->SectionName, pSection ) == 0 )
  451.         {
  452.             lFound = 1;
  453.         }
  454.         else
  455.         {
  456.             pConfigFile->CurrentSection = pConfigFile->ConfigSectionList;
  457.             while ( !lFound && (pConfigFile->CurrentSection != NULL) )
  458.             {
  459.                 if ( strcmp( pConfigFile->CurrentSection->SectionName, pSection ) == 0 )
  460.                 {
  461.                     lFound = 1;
  462.                 }
  463.                 else
  464.                 {
  465.                     pConfigFile->CurrentSection = pConfigFile->CurrentSection->NextSection;
  466.                 }
  467.             }
  468.         }
  469.     }
  470.     return lFound;
  471. }
  472.  
  473. // SetConfigCurrentValueFromCurrentSection looks for a value in the current
  474. // section having pKey as KeyName
  475. //
  476. // If a value is found, the function returns 1, otherwise the function returns 0
  477. // and CurrentValue is set to NULL.
  478. Sint32 SetConfigCurrentValueFromCurrentSection( ConfigFilePtr pConfigFile, const char *pKey )
  479. {
  480.     Sint32 lFound = 0;
  481.     if ( pConfigFile == NULL || pKey == NULL )
  482.     {
  483.         return 0;
  484.     }
  485.     if ( pConfigFile->CurrentSection == NULL )
  486.     {
  487.         return 0;
  488.     }
  489.  
  490.     // search for a value->KeyName = pKey in current section
  491.     pConfigFile->CurrentValue = pConfigFile->CurrentSection->FirstValue;
  492.     while ( !lFound && ( pConfigFile->CurrentValue != NULL ) )
  493.     {
  494.         if ( strcmp( pConfigFile->CurrentValue->KeyName, pKey ) == 0 )
  495.         {
  496.             lFound = 1;
  497.         }
  498.         else
  499.         {
  500.             pConfigFile->CurrentValue = pConfigFile->CurrentValue->NextValue;
  501.         }
  502.     }
  503.     return lFound;
  504. }
  505.  
  506. // SetConfigCurrentValue set the current value of pConfigFile to the one specified by  
  507. // pSection and pKey
  508. // Returns 0 if failed 
  509. Sint32 SetConfigCurrentValue( ConfigFilePtr pConfigFile, const char *pSection, const char *pKey )
  510. {
  511.     Sint32 lFound = 0;
  512.     // search for section
  513.     lFound = SetConfigCurrentSection( pConfigFile, pSection );
  514.     if ( lFound )
  515.     {
  516.         // search for key in current section
  517.         lFound = SetConfigCurrentValueFromCurrentSection( pConfigFile, pKey );
  518.     }
  519.     return lFound;
  520. }
  521.  
  522. // GetConfigValue search for the value from section pSection with the key pKey.
  523. // 
  524. // If the value is found, the value is copied in pValue and the function returns 1.
  525. // If the length of pValue is less than the length of the string value, the string is truncated.
  526. // If the value isn't found, the function returns 0.
  527. Sint32 GetConfigValue( ConfigFilePtr pConfigFile, const char *pSection, const char *pKey, char *pValue,
  528.                 Sint32 pValueBufferLength )
  529. {
  530.     if ( pConfigFile == NULL || pValue == NULL || pSection == NULL || pKey == NULL || pValueBufferLength <= 0)
  531.     {
  532.         return 0;
  533.     }
  534.     
  535.     if ( !SetConfigCurrentValue( pConfigFile, pSection, pKey ) )
  536.     {
  537.         return 0;
  538.     }
  539.     if ( strlen( pConfigFile->CurrentValue->Value ) >= (size_t)pValueBufferLength )
  540.     {
  541.         strncpy( pValue, pConfigFile->CurrentValue->Value, pValueBufferLength - 1 );
  542.         pValue[pValueBufferLength] = 0;
  543.     }
  544.     else
  545.     {
  546.         strcpy( pValue, pConfigFile->CurrentValue->Value );
  547.     }
  548.     return 1;
  549. }
  550.     
  551. // GetConfigBooleanValue set to true or false pBool. If the function can't find the value, it 
  552. // returns 0. If the value can't be identified as true or false, the default is false.
  553. Sint32 GetConfigBooleanValue( ConfigFilePtr pConfigFile, const char *pSection, const char *pKey, BOOL *pBool )
  554. {
  555.     char lBoolStr[16];
  556.     Sint32 lRet;
  557.     
  558.     memset( lBoolStr, 0, 16 );
  559.     lRet = GetConfigValue( pConfigFile, pSection, pKey, lBoolStr, 16 );
  560.     if ( lRet != 0 )
  561.     {
  562.         // check for true 
  563.         if ( strcmp( lBoolStr, "TRUE" ) == 0 )
  564.         {
  565.             *pBool = TRUE;
  566.         }
  567.         else
  568.         {
  569.             *pBool = FALSE;
  570.         }
  571.     }
  572.     return lRet;
  573. }
  574.  
  575. // GetConfigIntValue set pInt. If the function can't find the value, it 
  576. // returns 0.
  577. Sint32    GetConfigIntValue( ConfigFilePtr pConfigFile, const char *pSection, const char *pKey, Sint32 *pInt )
  578. {
  579.     char lIntStr[24];
  580.     Sint32 lRet;
  581.     
  582.     memset( lIntStr, 0, 16 );
  583.     lRet = GetConfigValue( pConfigFile, pSection, pKey, lIntStr, 24 );
  584.     if ( lRet != 0 )
  585.     {
  586.         // convert value
  587.         sscanf( lIntStr, "%d", pInt );
  588.     }
  589.     return lRet;
  590. }
  591.  
  592. // SetConfigValue set the value specified by pSection and pKey. If the value
  593. // doesn't exist, it is created
  594. Sint32 SetConfigValue( ConfigFilePtr pConfigFile, const char *pSection, const char *pKey, const char *pValue )
  595. {
  596.     ConfigFileSectionPtr    lTempSection = NULL;
  597.     ConfigFileValuePtr        lTempValue = NULL;
  598.     Sint32 lOK = 0;
  599.     Sint32 lLentghtNewValue, lLengthValue;
  600.     char                    lNewSectionName[MAX_CONFIG_SECTION_LENGTH];
  601.     char                    lNewKeyName[MAX_CONFIG_KEY_LENGTH];
  602.  
  603.     if ( pConfigFile == NULL )
  604.     {
  605.         return 0;
  606.     }
  607.     if ( pValue == NULL || pSection == NULL || pKey == NULL)
  608.     {
  609.         return 0;
  610.     }
  611.     
  612.     // make sure section name and key name are made of valid char
  613.     strcpy( lNewSectionName, pSection );
  614.     strcpy( lNewKeyName, pKey );
  615.     ConvertToKeyCharacters( lNewSectionName );
  616.     ConvertToKeyCharacters( lNewKeyName );
  617.     // look for section = pSection
  618.     if ( ( lOK = SetConfigCurrentSection( pConfigFile, lNewSectionName ) )  == 0)
  619.     {
  620.         // section doesn't exist so create it and create value
  621.         lTempSection = ( ConfigFileSectionPtr ) malloc( sizeof( ConfigFileValue ) );
  622.         memset( lTempSection, 0, sizeof( ConfigFileValue ) );
  623.         lTempSection->NextSection = pConfigFile->ConfigSectionList;
  624.         pConfigFile->ConfigSectionList = lTempSection;
  625.         strcpy( lTempSection->SectionName, lNewSectionName );
  626.  
  627.         // create the new value
  628.         lTempValue = ( ConfigFileValuePtr ) malloc( sizeof( ConfigFileValue ) );
  629.         memset( lTempValue, 0, sizeof( ConfigFileValue ) );
  630.         lTempSection->FirstValue = lTempValue;
  631.         strcpy( lTempValue->KeyName, lNewKeyName ); 
  632.  
  633.         // set current section and value
  634.         pConfigFile->CurrentSection = lTempSection;
  635.         pConfigFile->CurrentValue = lTempValue;
  636.     }
  637.  
  638.     // if the section already existed
  639.     if ( lOK )
  640.     {
  641.         // search for value
  642.         if ( !SetConfigCurrentValueFromCurrentSection( pConfigFile, lNewKeyName ) )
  643.         {
  644.             // create new value in current section
  645.             lTempValue = ( ConfigFileValuePtr ) malloc( sizeof( ConfigFileValue ) );
  646.             memset( lTempValue, 0, sizeof( ConfigFileValue ) );
  647.             lTempValue->NextValue = pConfigFile->CurrentSection->FirstValue;
  648.             pConfigFile->CurrentSection->FirstValue = lTempValue;
  649.             strcpy( lTempValue->KeyName, lNewKeyName ); 
  650.  
  651.             // set current section and value
  652.             pConfigFile->CurrentValue = lTempValue;
  653.         }
  654.     }
  655.     
  656.     lLentghtNewValue = strlen( pValue );
  657.     if ( pConfigFile->CurrentValue->Value == NULL )
  658.     {
  659.         // if the stirng value doesn't exist than allocate memory for it
  660.         pConfigFile->CurrentValue->Value = ( char * ) malloc( lLentghtNewValue  + 1);
  661.         memset( pConfigFile->CurrentValue->Value, 0, lLentghtNewValue + 1);
  662.     }
  663.     else
  664.     {
  665.         lLengthValue = sizeof( pConfigFile->CurrentValue->Value );
  666.         // if value already exist, verify if allocated memory is enough
  667.         // if not allocate more memory
  668.         if ( lLentghtNewValue >= MAX_CONFIG_VALUE_LENGTH )
  669.         {
  670.             lLentghtNewValue = MAX_CONFIG_VALUE_LENGTH - 1;
  671.         }
  672.         if ( lLentghtNewValue >= lLengthValue )
  673.         {
  674.             free( pConfigFile->CurrentValue->Value );
  675.             pConfigFile->CurrentValue->Value = ( char * ) malloc( lLentghtNewValue  + 1);
  676.             memset( pConfigFile->CurrentValue->Value, 0, lLentghtNewValue + 1);
  677.         }
  678.         else
  679.         {
  680.             memset( pConfigFile->CurrentValue->Value, 0, lLengthValue );
  681.         }
  682.     }
  683.     strncpy( pConfigFile->CurrentValue->Value, pValue, lLentghtNewValue );
  684.     return 1;
  685. }
  686.  
  687. // SetConfigBooleanValue saves a boolean in a value specified by pSection and pKey
  688. Sint32 SetConfigBooleanValue( ConfigFilePtr pConfigFile, const char *pSection, const char *pKey, int pBool)
  689. {
  690.     if ( pBool == TRUE )
  691.     {
  692.         // save the value with TRUE
  693.         return SetConfigValue( pConfigFile, pSection, pKey, "TRUE" );
  694.     }
  695.     // since it's false
  696.     return SetConfigValue( pConfigFile, pSection, pKey, "FALSE" );
  697. }
  698.  
  699. // SetConfigIntValue saves an integer in a value specified by pSection and pKey
  700. Sint32 SetConfigIntValue( ConfigFilePtr pConfigFile, const char *pSection, const char *pKey, int pInt)
  701. {
  702.     static char lIntStr[16];
  703.     
  704.     sprintf( lIntStr, "%i", pInt );
  705.     return SetConfigValue( pConfigFile, pSection, pKey, lIntStr );
  706. }
  707.  
  708. // SetConfigFloatValue saves a float in a value specified by pSection and pKey
  709. Sint32 SetConfigFloatValue( ConfigFilePtr pConfigFile, const char *pSection, const char *pKey, float pFloat)
  710. {
  711.     static char lFloatStr[16];
  712.     
  713.     sprintf( lFloatStr, "%f", pFloat );
  714.     return SetConfigValue( pConfigFile, pSection, pKey, lFloatStr );
  715. }
  716.  
  717. // CloseConfigFile close the ConfigFile and deallocate all its memory.
  718. void CloseConfigFile( ConfigFilePtr pConfigFile )
  719. {
  720.     ConfigFileSectionPtr lTempSection, lDoomedSection;
  721.     ConfigFileValuePtr   lTempValue, lDoomedValue;
  722.  
  723.     if ( pConfigFile == NULL )
  724.     {
  725.         return;
  726.     }
  727.     if ( pConfigFile->f != NULL )
  728.     {
  729.         fclose( pConfigFile->f );
  730.     }
  731.     // delete all sections form the ConfigFile
  732.     lTempSection = pConfigFile->ConfigSectionList;
  733.     while ( lTempSection != NULL )
  734.     {
  735.         // delete all values form the current section
  736.         lTempValue = lTempSection->FirstValue;
  737.         while ( lTempValue != NULL )
  738.         {
  739.             if ( lTempValue->Value != NULL )
  740.             {
  741.                 free( lTempValue->Value );
  742.             }
  743.             if ( lTempValue->Commentary != NULL )
  744.             {
  745.                 free( lTempValue->Commentary );
  746.             }
  747.             lDoomedValue = lTempValue;
  748.             lTempValue = lTempValue->NextValue;
  749.             free( lDoomedValue );
  750.         }
  751.         lDoomedSection = lTempSection;
  752.         lTempSection = lTempSection->NextSection;
  753.         free( lDoomedSection );
  754.     }
  755.     free( pConfigFile );
  756. }
  757.  
  758. // SaveConfigValue saves the value from pValue at the current position
  759. // of the pConfigFile file. The '"' are doubled.
  760. Sint32 SaveConfigValue( FILE *pFile, ConfigFileValuePtr pValue )
  761. {
  762.     Sint32 lPos = 0;
  763.  
  764.     if ( pValue->Value != NULL )
  765.     {
  766.         fputc( '"', pFile );
  767.         while ( pValue->Value[lPos] != 0 )
  768.         {
  769.             fputc( pValue->Value[lPos], pFile );
  770.             if ( pValue->Value[lPos] == '"' )
  771.             {
  772.                 // double the '"'
  773.                 fputc( '"', pFile );
  774.             }
  775.             lPos++;
  776.         }
  777.         fputc( '"', pFile );
  778.     }
  779.     return 0;
  780. }
  781.  
  782. // SaveConfigFile
  783. void SaveConfigFile( ConfigFilePtr pConfigFile )
  784. {
  785.     ConfigFileSectionPtr lTempSection;
  786.     ConfigFileValuePtr   lTempValue;
  787.  
  788.     if ( pConfigFile == NULL )
  789.     {
  790.         return;
  791.     }
  792.     if ( pConfigFile->f == NULL )
  793.     {
  794.         return;
  795.     }
  796.  
  797.     lTempSection = pConfigFile->ConfigSectionList;
  798.     // rewrite the file
  799.     rewind( pConfigFile->f );
  800.     // saves all sections
  801.     while ( lTempSection != NULL )
  802.     {
  803.         fprintf( pConfigFile->f, "{%s}\n", lTempSection->SectionName );
  804.         // saves all values form the current section
  805.         lTempValue = lTempSection->FirstValue;
  806.         while ( lTempValue != NULL )
  807.         {
  808.             fprintf( pConfigFile->f, "[%s] : ", lTempValue->KeyName );
  809.             if ( lTempValue->Value != NULL )
  810.             {
  811.                 SaveConfigValue( pConfigFile->f, lTempValue );
  812.             }
  813.             if ( lTempValue->Commentary != NULL )
  814.             {
  815.                 fprintf( pConfigFile->f, " // %s", lTempValue->Commentary );
  816.             }
  817.             fprintf( pConfigFile->f, "\n" );
  818.             lTempValue = lTempValue->NextValue;
  819.         }
  820.         fprintf( pConfigFile->f, "\n" );
  821.         lTempSection = lTempSection->NextSection;
  822.     }
  823. }
  824.  
  825. // SaveConfigFileAs saves pConfigFile at pPath
  826. // pConfigFile's file is close and set to the new file
  827. Sint32 SaveConfigFileAs( ConfigFilePtr pConfigFile, const char *pPath )
  828. {
  829.     FILE *lFileTemp;
  830.  
  831.     lFileTemp = fopen( pPath, "wt" );
  832.     if ( lFileTemp == NULL )
  833.     {
  834.         return 0;
  835.     }
  836.     if ( pConfigFile->f != NULL )
  837.     {
  838.         fclose( pConfigFile->f );
  839.     }
  840.     pConfigFile->f = lFileTemp;
  841.     SaveConfigFile( pConfigFile );
  842.     return 1;
  843. }
  844.