home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR13 / INIFIL.ZIP / INIFILE.CPP < prev    next >
C/C++ Source or Header  |  1993-10-13  |  11KB  |  431 lines

  1. /*
  2.     Copyright (c) 1993, George Byrkit
  3.                 Software Professionals Limited
  4.                 1809 Saxon Street
  5.                 Ann Arbor, MI 48103
  6.                 (313)-663-1009
  7.  
  8.                 ALL RIGHTS RESERVED
  9.  
  10.     THIS FILE MAY BE INCLUDED ROYALTY-FREE in any program as long as the
  11.     above copyright notice also appears in the text of the program executable.
  12.  
  13.     I hereby certify that I did NOT examine the internals of the equivalent
  14.     Windows (reg TM of MicroSoft) functions in order to create these
  15.     approximately functionally equivalent routines.
  16.  
  17.     Differences are:
  18.         I don't look for a windows installation directory.  If you use the
  19.         non-private functions, the file 'win.ini' is looked for in the CURRENT
  20.         DIRECTORY
  21.  
  22.     filename:    inifile.cpp
  23.  
  24.     purpose:    emulate windows API functions to access the ini files
  25.  
  26.     instructions for building:
  27.         compile:
  28.         link:
  29.         other:
  30.  
  31.     change log:
  32.     When        Version    Who        Why
  33.     01-jan-93    1.0        ghb        created
  34. */
  35.  
  36. /*
  37.         PRAGMAS
  38. */
  39.  
  40. /*
  41.         INCLUDE FILES
  42. */
  43. #include <stdio.h>
  44. #include <stdlib.h>
  45. #include <string.h>
  46. #include <ctype.h>
  47. #include "inifile.h"
  48.  
  49. /*
  50.         LOCAL DEFINES AND MACROS
  51. */
  52.  
  53. /*
  54.         LOCAL STRUCTURES AND TYPEDEFS
  55. */
  56.  
  57. /*
  58.         FORWARD REFERENCES TO FUNCTIONS DEFINED IN THIS SOURCE FILE
  59. */
  60.  
  61. /*
  62.         EXTERN FUNCTION AND DATA REFERENCES
  63. */
  64.  
  65. /*
  66.         LOCAL DATA  (MAY BE GLOBAL OR STATIC)
  67. */
  68. /*
  69.     this string MUST be part of the executable file for the functions in
  70.     this file to be used in a non-infringing way
  71. */
  72. static char *pCWN =    "inifile code is Copyright (c) 1993, George Byrkit\n"
  73.                 "Software Professionals Limited\n"
  74.                 "1809 Saxon Street\n"
  75.                 "Ann Arbor, MI 48103\n"
  76.                 "(313)-663-1009\n"
  77.                 "ALL RIGHTS RESERVED\n";
  78.  
  79. /*
  80.     Note that appname and keyname are treated case-insensitively.
  81. */
  82.  
  83. /*
  84.     returns a pointer to the line that contains the desired string
  85.  
  86.     open for write opens a file from the beginning
  87. */
  88.  
  89. /*
  90.     basic finding function for reads.
  91.  
  92.     see ScanForCopy for use with writes
  93. */
  94. int ScanFor ( LPCSTR lpAppName, LPCSTR lpKeyName,
  95.             LPSTR lpReturnedString, int nSize,
  96.             FILE *pIniFile )
  97. {
  98.     int appLen = strlen ( lpAppName );
  99.     int keyLen = strlen ( lpKeyName );
  100.     char *rc;
  101.  
  102.     // find application name, if present
  103.     do {
  104.         rc = fgets ( lpReturnedString, nSize, pIniFile );
  105.         // check for error, possibly EOF.
  106.         if ( rc != lpReturnedString ) {
  107.             // didn't find the application.  Return not found
  108.             return 0;
  109.         }
  110.     } while ( lpReturnedString[0] != '['
  111.         || strnicmp ( lpAppName, &lpReturnedString[1], appLen )
  112.         || lpReturnedString[1+appLen] != ']' );
  113.  
  114.     // OK, we found the application section.  Now look for the keyword
  115.     do {
  116.         rc = fgets ( lpReturnedString, nSize, pIniFile );
  117.         // check for error, possibly EOF.
  118.         if ( rc != lpReturnedString ) {
  119.             // didn't find the application.  Return not found
  120.             return 0;
  121.         }
  122.         // at the end of an application.  Obviously we didn't find the keyword
  123.         if ( lpReturnedString[0] == '[' ) {
  124.             // didn't find the keyword.  Return not found
  125.             return 0;
  126.         }
  127.     } while ( strnicmp ( lpKeyName, lpReturnedString, keyLen )
  128.         || lpReturnedString[keyLen] != '=' );
  129.  
  130.     // OK, we found it, and it's in the current buffer.  Return success.
  131.     // Success is the nonzero index into the return string of where
  132.     // the result (after the equal sign) is located
  133.     return keyLen+1;
  134. }
  135.  
  136. /*
  137.     basic finding function for writes.
  138.  
  139.     see ScanFor for use with reads
  140. */
  141. InsertSection ( LPCSTR lpAppName, LPCSTR lpKeyName,
  142.             LPCSTR lpValue, FILE *pFile )
  143. {
  144.     return fprintf ( pFile, "[%s]\n%s=%s\n", lpAppName, lpKeyName, lpValue );
  145. }
  146.  
  147. InsertKey ( LPCSTR lpKeyName, LPCSTR lpValue, FILE *pFile )
  148. {
  149.     return fprintf ( pFile, "%s=%s\n", lpKeyName, lpValue );
  150. }
  151.  
  152. /*
  153.     return of zero means no more copy to do.
  154. */
  155. int ScanForCopyInsert ( LPCSTR lpAppName, LPCSTR lpKeyName,
  156.             LPCSTR lpValue,
  157.             FILE *pIniFile, FILE *pIniFileCopy )
  158. {
  159.     int appLen = strlen ( lpAppName );
  160.     int keyLen = strlen ( lpKeyName );
  161.     char    lpReturnedString [256];
  162.     char *rc;
  163.  
  164.     // find application name, if present
  165.     do {
  166.         rc = fgets ( lpReturnedString, 256, pIniFile );
  167.         // check for error, possibly EOF.
  168.         if ( rc != lpReturnedString ) {
  169.             // didn't find the application.  Return not found
  170.             InsertSection ( lpAppName, lpKeyName, lpValue, pIniFileCopy );
  171.             return 0;
  172.         }
  173.         // copy to output
  174.         fputs ( lpReturnedString, pIniFileCopy );
  175.     } while ( lpReturnedString[0] != '['
  176.         || strnicmp ( lpAppName, &lpReturnedString[1], appLen )
  177.         || lpReturnedString[1+appLen] != ']' );
  178.  
  179.     // OK, we found the application section.  Now look for the keyword
  180.     do {
  181.         rc = fgets ( lpReturnedString, 256, pIniFile );
  182.         // check for error, possibly EOF.
  183.         if ( rc != lpReturnedString ) {
  184.             // didn't find the application.  Return not found
  185.             InsertKey ( lpKeyName, lpValue, pIniFileCopy );
  186.             return 1;
  187.         }
  188.         // at the end of an application.  Obviously we didn't find the keyword
  189.         if ( lpReturnedString[0] == '[' ) {
  190.             InsertKey ( lpKeyName, lpValue, pIniFileCopy );
  191.             // copy the line in the buffer, that we just read, that starts
  192.             // a new section
  193.             fputs ( lpReturnedString, pIniFileCopy );
  194.  
  195.             // didn't find the keyword.  Return not found
  196.             return 1;
  197.         }
  198.         if ( !strnicmp ( lpKeyName, lpReturnedString, keyLen )
  199.             && lpReturnedString[keyLen] == '=' ) {
  200.             // this is the place
  201.             break;
  202.         }
  203.     } while ( fputs ( lpReturnedString, pIniFileCopy ) != EOF );
  204.  
  205.     // OK, we found it, and it's in the current buffer.  Replace what's after
  206.     // the equal sign and up to any comment, with what's in the string we got
  207.     // here to write in
  208.     rc = strchr ( &lpReturnedString[keyLen+1], ';' );
  209.     // we got a trailing comment.  Now back up over whitespace
  210.     if ( rc ) {
  211.         while ( isspace(*(rc-1)) ) {
  212.             rc--;    // back up
  213.         } 
  214.         // note that rc usually includes a newline character
  215.         if ( !strchr ( rc, '\n' ) ) {
  216.             // must provide a newline char, one wasn't there
  217.             fprintf ( pIniFileCopy, "%s=%s%s\n", lpKeyName, lpValue, rc );
  218.         }
  219.         else {
  220.             fprintf ( pIniFileCopy, "%s=%s%s", lpKeyName, lpValue, rc );
  221.         }
  222.     }
  223.     else {
  224.         fprintf ( pIniFileCopy, "%s=%s\n", lpKeyName, lpValue );
  225.     }
  226.  
  227.     // indicate probably more to copy
  228.     return 1;
  229. }
  230.  
  231. UINT    WINAPI GetPrivateProfileInt(LPCSTR lpAppName, LPCSTR lpKeyName,
  232.             int nDefault,
  233.             LPCSTR lpFileName)
  234. {
  235.     char returnedString[256];
  236.     UINT    rc;
  237.  
  238.     FILE *pIniFile = fopen ( lpFileName, "rt" );
  239.     if ( !pIniFile ) {
  240.         return nDefault;
  241.     }
  242.  
  243.     rc = ScanFor ( lpAppName, lpKeyName, returnedString, 256, pIniFile );
  244.     if ( !rc ) {
  245.         return nDefault;
  246.     }
  247.  
  248.     // get integer value
  249.     return (UINT) atol ( &returnedString[ rc ] );
  250. }
  251.  
  252. int     WINAPI GetPrivateProfileString(LPCSTR lpAppName, LPCSTR lpKeyName,
  253.             LPCSTR lpDefault, LPSTR lpReturnedString, int nSize,
  254.             LPCSTR lpFileName)
  255. {
  256.     char returnedString[256];
  257.     int    rc;
  258.     int i;
  259.     int len;
  260.     char *p;
  261.  
  262.     FILE *pIniFile = fopen ( lpFileName, "rt" );
  263.     if ( !pIniFile ) {
  264.         strcpy ( lpReturnedString, lpDefault );
  265.         return strlen ( lpDefault );
  266.     }
  267.  
  268.     rc = ScanFor ( lpAppName, lpKeyName, returnedString, 256, pIniFile );
  269.     if ( !rc ) {
  270.         strcpy ( lpReturnedString, lpDefault );
  271.         return strlen ( lpDefault );
  272.     }
  273.  
  274.     // get string.  Copy out and back, to get rid of leading line info
  275.     strcpy ( returnedString, &returnedString[ rc ] );
  276.     // look for a double quote
  277.     if ( returnedString[0] == '\"' ) {
  278.         // find terminating quote
  279.         p = strchr ( &returnedString[1], '\"' );
  280.         p++;
  281.         *p = '\0';    // string is terminated after end quote
  282.     }
  283.     else if ( NULL != ( p = strchr ( returnedString, ';' ) ) ) {
  284.         // found a comment char
  285.         // terminate string there.  Trailing whitespace trim will still work.
  286.         *p = '\0';
  287.     }
  288.  
  289.     // trim off trailing whitespace
  290.     len = strlen ( returnedString );
  291.     for ( i = len-1; i > 0; i-- ) {
  292.         if ( isspace(returnedString[i]) ) {
  293.             returnedString[i] = '\0';    // trim it
  294.         }
  295.         else {
  296.             break;
  297.         }
  298.     }
  299.     strncpy ( lpReturnedString, returnedString, nSize - 1 );
  300.     lpReturnedString[nSize] = '\0';    // force null termination
  301.  
  302.     return strlen ( lpReturnedString );
  303. }
  304.  
  305. BOOL    WINAPI WritePrivateProfileString(LPCSTR lpAppName, LPCSTR lpKeyName,
  306.             LPCSTR lpValue,
  307.             LPCSTR lpFileName)
  308. {
  309.     char tmpFileName[256];
  310.     char tmpFileName2[256];
  311.     char buffer[256];
  312.     int    rc;
  313.  
  314.     FILE *pIniFileCopy;
  315.     FILE *pIniFile = fopen ( lpFileName, "rt" );
  316.  
  317.     // if it doesn't exist, create it and insert this section
  318.     if ( !pIniFile ) {
  319.         pIniFile = fopen ( lpFileName, "wt" );
  320.         if ( !pIniFile ) {
  321.             return 0;    // failure
  322.         }
  323.     
  324.         InsertSection ( lpAppName, lpKeyName, lpValue, pIniFile );
  325.         fclose ( pIniFile );
  326.         return 0;
  327.     }
  328.  
  329.     // get a temporary file name that is unique
  330.     strcpy ( tmpFileName, lpFileName );
  331.     tmpFileName[strlen ( tmpFileName )-1] = '$';    // turn last char into $
  332.  
  333.     pIniFileCopy = fopen ( tmpFileName, "wt" );
  334.     // if can't open a temporary file, fail
  335.     if ( !pIniFileCopy ) {
  336.         rc = errno;
  337.         fclose ( pIniFile );
  338.         return 0;
  339.     }
  340.  
  341.     rc = ScanForCopyInsert ( lpAppName, lpKeyName, lpValue,
  342.             pIniFile, pIniFileCopy );
  343.  
  344.     if ( rc ) {
  345.         while ( !feof ( pIniFile ) ) {
  346.             if ( buffer != fgets ( buffer, sizeof ( buffer ) -1, pIniFile ) ) {
  347.                 if ( !feof ( pIniFile ) ) {
  348.                     rc = errno;
  349.                     fclose ( pIniFile );
  350.                     fclose ( pIniFileCopy );
  351.                     remove ( tmpFileName );
  352.                     return 0;
  353.                 }
  354.                 else {
  355.                     // it is end of file.  All is copied.  Swap files
  356.                     break;
  357.                 }
  358.             }
  359.             // while writing to the copy file, if an error is encountered
  360.             if ( fputs ( buffer, pIniFileCopy ) == EOF ) {
  361.                 // error while writing
  362.                 rc = errno;
  363.                 fclose ( pIniFile );
  364.                 fclose ( pIniFileCopy );
  365.                 remove ( tmpFileName );
  366.                 return 0;
  367.             }
  368.         } // end while not eof
  369.     }
  370.  
  371.     // close the files
  372.     fclose ( pIniFile );
  373.     fclose ( pIniFileCopy );
  374.  
  375.     // form the name of what to rename the current file to.
  376.     strcpy ( tmpFileName2, lpFileName );
  377.     tmpFileName2[strlen ( tmpFileName )-1] = '$';    // turn last char into $
  378.     tmpFileName2[strlen ( tmpFileName )-2] = '$';    // also nextlast char into $
  379.     rc = rename ( lpFileName, tmpFileName2 );
  380.     if ( rc ) {
  381.         // error on rename. can't do it.  bail out
  382.         rc = errno;
  383.         remove ( tmpFileName );
  384.         return 0;
  385.     }
  386.  
  387.     rc = rename ( tmpFileName, lpFileName );
  388.     if ( rc ) {
  389.         // error on rename. can't do it.  bail out
  390.         rc = errno;
  391.         // rename back original file.  Pray for no error!
  392.         rename ( tmpFileName2, lpFileName );
  393.         remove ( tmpFileName );    // delete temp file
  394.         return 0;
  395.     }
  396.  
  397.     // all went OK.  Now just delete the temp file that is the original file
  398.     remove ( tmpFileName2 );    // delete temp file that is original file
  399.  
  400.     return 1;
  401. }
  402.  
  403. UINT    WINAPI GetProfileInt(LPCSTR lpAppName, LPCSTR lpKeyName,
  404.             int nDefault)
  405. {
  406.     return GetPrivateProfileInt (lpAppName, lpKeyName, nDefault, "win.ini" );
  407. }
  408.  
  409. int     WINAPI GetProfileString(LPCSTR lpAppName, LPCSTR lpKeyName,
  410.             LPCSTR lpDefault, LPSTR lpReturnedString, int nSize)
  411. {
  412.     return GetPrivateProfileString (lpAppName, lpKeyName, lpDefault,
  413.                     lpReturnedString, nSize, "win.ini" );
  414. }
  415.  
  416. BOOL    WINAPI WriteProfileString(LPCSTR lpAppName, LPCSTR lpKeyName,
  417.             LPCSTR lpValue)
  418. {
  419.     return WritePrivateProfileString (lpAppName, lpKeyName, lpValue, "win.ini");
  420. }
  421.  
  422. #ifdef    TEST
  423. main ()
  424. {
  425.     char rv[256];
  426.     GetPrivateProfileString ( "myapp2", "key2", "none", rv, 256, "myapp.ini" );
  427.  
  428.     printf ("Value of key %s in section %s is %s\n", "key2", "myapp2", rv );
  429. }
  430. #endif
  431.