Back to index

lightning-sunbird  0.9+nobinonly
nsINIParser.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla Communicator client code, released
00016  * March 31, 1998.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1998
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Samir Gehani <sgehani@netscape.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 
00041 #include "nsINIParser.h"
00042 
00043 nsINIParser::nsINIParser(char *aFilename)
00044 {
00045     FILE    *fd = NULL;
00046     long    eofpos = 0;
00047     int     rd = 0;
00048 
00049     mFileBuf = NULL;
00050     mFileBufSize = 0;
00051     mError = OK;
00052     DUMP("nsINIParser");
00053 
00054     /* param check */
00055     if (!aFilename)
00056     {
00057         mError = E_PARAM;
00058         return;
00059     }
00060 
00061     /* open the file */
00062     fd = fopen(aFilename, "r");
00063     if (!fd)
00064         goto bail;
00065     
00066     /* get file size */
00067     if (fseek(fd, 0, SEEK_END) != 0)
00068         goto bail;
00069     eofpos = ftell(fd);
00070     if (eofpos == 0)
00071         goto bail;
00072 
00073     /* malloc an internal buf the size of the file */
00074     mFileBuf = (char *) malloc(eofpos + 1);
00075     if (!mFileBuf)
00076     {
00077         mError = E_MEM;
00078         return;
00079     }
00080     mFileBufSize = eofpos;
00081 
00082     /* read the file in one swoop */
00083     if (fseek(fd, 0, SEEK_SET) != 0)
00084         goto bail;
00085     rd = fread((void *)mFileBuf, 1, eofpos, fd);
00086     if (!rd)
00087         goto bail;
00088     mFileBuf[mFileBufSize] = '\0';
00089 
00090     /* close file */
00091     fclose(fd);
00092 
00093     /* Make sure the buffer is null-terminated. */
00094     mFileBuf[eofpos] = '\0';
00095 
00096     return;
00097 
00098 bail:
00099     mError = E_READ;
00100     return;
00101 }
00102 
00103 nsINIParser::~nsINIParser()
00104 {
00105     DUMP("~nsINIParser");
00106 }
00107 
00108 int
00109 nsINIParser::GetString( char *aSection, char *aKey, 
00110                         char *aValBuf, int *aIOValBufSize )
00111 {
00112     char *secPtr = NULL;
00113     mError = OK;
00114     DUMP("GetString");
00115 
00116     /* param check */
00117     if ( !aSection || !aKey || !aValBuf || 
00118          !aIOValBufSize || (*aIOValBufSize <= 0) )
00119         return E_PARAM;
00120 
00121     /* find the section if it exists */
00122     mError = FindSection(aSection, &secPtr);
00123     if (mError != OK)
00124         return mError;
00125 
00126     /* find the key if it exists in the valid section we found */
00127     mError = FindKey(secPtr, aKey, aValBuf, aIOValBufSize);
00128 
00129     return mError;
00130 }
00131 
00132 int
00133 nsINIParser::GetStringAlloc( char *aSection, char *aKey,
00134                              char **aOutBuf, int *aOutBufSize )
00135 {
00136     char buf[MAX_VAL_SIZE];
00137     int bufsize = MAX_VAL_SIZE;
00138     mError = OK;
00139     DUMP("GetStringAlloc");
00140 
00141     mError = GetString(aSection, aKey, buf, &bufsize);
00142     if (mError != OK)
00143         return mError;
00144 
00145     *aOutBuf = (char *) malloc(bufsize + 1);
00146     strncpy(*aOutBuf, buf, bufsize);
00147     *(*aOutBuf + bufsize) = 0;
00148     *aOutBufSize = bufsize + 1;
00149 
00150     return mError;
00151 }
00152 
00153 int
00154 nsINIParser::GetError()
00155 {
00156     DUMP("GetError");
00157     return mError;
00158 }
00159 
00160 char *
00161 nsINIParser::ResolveName(char *aINIRoot)
00162 {
00163     char *resolved = NULL;
00164     char *locale = NULL;
00165     struct stat st_exists;
00166 
00167     /* param check */
00168     if (!aINIRoot)
00169         return NULL;
00170 
00171     locale = setlocale(LC_CTYPE, NULL);
00172     if (!locale) 
00173         return NULL;
00174 
00175     /* resolved string: "<root>.ini.<locale>\0" */
00176     resolved = (char *) malloc(strlen(aINIRoot) + 5 + strlen(locale) + 1);
00177     if (!resolved)
00178         return NULL;
00179 
00180     /* locale specific ini file name */
00181     sprintf(resolved, "%s.ini.%s", aINIRoot, locale);
00182     if (0 == stat(resolved, &st_exists))
00183         return resolved;
00184 
00185     /* fallback to general ini file name */
00186     sprintf(resolved, "%s.ini", aINIRoot);
00187     if (0 == stat(resolved, &st_exists))
00188         return resolved;
00189     
00190     /* neither existed so error returned */
00191     return NULL;
00192 }
00193 
00194 int
00195 nsINIParser::FindSection(char *aSection, char **aOutSecPtr)
00196 {
00197     char *currChar = mFileBuf;
00198     char *nextSec = NULL;
00199     char *secClose = NULL;
00200     char *nextNL = NULL;
00201     int aSectionLen = strlen(aSection);
00202     mError = E_NO_SEC;
00203     DUMP("FindSection");
00204 
00205     // param check
00206     if (!aSection || !aOutSecPtr)
00207     {
00208         mError = E_PARAM;
00209         return mError;
00210     }
00211 
00212     while (currChar < (mFileBuf + mFileBufSize))
00213     {
00214         // look for first '['
00215         nextSec = NULL;
00216         nextSec = strchr(currChar, '[');
00217         if (!nextSec)
00218             break;
00219             
00220         currChar = nextSec + 1;
00221 
00222         // extract section name till first ']'
00223         secClose = NULL; nextNL = NULL;
00224         secClose = strchr(currChar, ']');
00225         nextNL = strchr(currChar, NL);
00226         if ((!nextNL) || (nextNL < secClose))
00227         {
00228             currChar = nextNL;
00229             continue;
00230         }
00231 
00232         // if section name matches we succeeded
00233         if (strncmp(aSection, currChar, aSectionLen) == 0
00234               && secClose-currChar == aSectionLen)
00235         {
00236             *aOutSecPtr = secClose + 1;
00237             mError = OK;
00238             break;
00239         }
00240     }
00241 
00242     return mError;
00243 }
00244 
00245 int
00246 nsINIParser::FindKey(char *aSecPtr, char *aKey, char *aVal, int *aIOValSize)
00247 {
00248     char *nextNL = NULL;
00249     char *secEnd = NULL;
00250     char *currLine = aSecPtr;
00251     char *nextEq = NULL;
00252     int  aKeyLen = strlen(aKey); 
00253     mError = E_NO_KEY;
00254     DUMP("FindKey");
00255 
00256     // param check
00257     if (!aSecPtr || !aKey || !aVal || !aIOValSize || (*aIOValSize <= 0))
00258     {
00259         mError = E_PARAM;
00260         return mError;
00261     }
00262 
00263     // determine the section end
00264     secEnd = aSecPtr;
00265 find_end:
00266     if (secEnd)
00267         secEnd = strchr(secEnd, '['); // search for next sec start
00268     if (!secEnd)
00269     {
00270         secEnd = strchr(aSecPtr, '\0'); // else search for file end
00271         if (!secEnd)
00272         {
00273             mError = E_SEC_CORRUPT; // else this data is corrupt
00274             return mError;
00275         }
00276     }
00277 
00278     // handle start section token ('[') in values for i18n
00279     if (*secEnd == '[' && !(secEnd == aSecPtr || *(secEnd-1) == NL))
00280     {
00281         secEnd++;
00282         goto find_end;
00283     }
00284 
00285     while (currLine < secEnd)
00286     {
00287         nextNL = NULL;
00288         nextNL = strchr(currLine, NL);
00289         if (!nextNL)
00290             nextNL = mFileBuf + mFileBufSize;
00291 
00292         // ignore commented lines (starting with ;)
00293         if (currLine == strchr(currLine, ';'))
00294         {
00295             currLine = nextNL + 1;
00296             continue;
00297         }
00298 
00299         // extract key before '='
00300         nextEq = NULL;
00301         nextEq = strchr(currLine, '=');
00302         if (!nextEq || nextEq > nextNL) 
00303         {
00304             currLine = nextNL + 1;
00305             continue;
00306         }
00307 
00308         // if key matches we succeeded
00309         if (strncmp(currLine, aKey, aKeyLen) == 0
00310               && nextEq-currLine == aKeyLen)
00311         {
00312             // extract the value and return
00313             if (*aIOValSize < nextNL - nextEq)
00314             {
00315                 mError = E_SMALL_BUF;
00316                 *aVal = '\0';
00317                 *aIOValSize = 0;
00318                 return mError;
00319             }
00320                 
00321             *aIOValSize = nextNL - (nextEq + 1); 
00322             strncpy(aVal, (nextEq + 1), *aIOValSize);
00323             *(aVal + *aIOValSize) = 0; // null terminate
00324             mError = OK;
00325             return mError;
00326         }
00327         else
00328         {
00329             currLine = nextNL + 1;
00330         }
00331     }
00332 
00333     return mError;
00334 }