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 of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or 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) * sizeof(char));
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     return;
00094 
00095 bail:
00096     mError = E_READ;
00097     return;
00098 }
00099 
00100 nsINIParser::~nsINIParser()
00101 {
00102     DUMP("~nsINIParser");
00103 }
00104 
00105 int
00106 nsINIParser::GetString( char *aSection, char *aKey, 
00107                         char *aValBuf, int *aIOValBufSize )
00108 {
00109     char *secPtr = NULL;
00110     mError = OK;
00111     DUMP("GetString");
00112 
00113     /* param check */
00114     if ( !aSection || !aKey || !aValBuf || 
00115          !aIOValBufSize || (*aIOValBufSize <= 0) )
00116         return E_PARAM;
00117 
00118     /* find the section if it exists */
00119     mError = FindSection(aSection, &secPtr);
00120     if (mError != OK)
00121         return mError;
00122 
00123     /* find the key if it exists in the valid section we found */
00124     mError = FindKey(secPtr, aKey, aValBuf, aIOValBufSize);
00125 
00126     return mError;
00127 }
00128 
00129 int
00130 nsINIParser::GetStringAlloc( char *aSection, char *aKey,
00131                              char **aOutBuf, int *aOutBufSize )
00132 {
00133     char buf[MAX_VAL_SIZE];
00134     int bufsize = MAX_VAL_SIZE;
00135     mError = OK;
00136     DUMP("GetStringAlloc");
00137 
00138     mError = GetString(aSection, aKey, buf, &bufsize);
00139     if (mError != OK)
00140         return mError;
00141 
00142     *aOutBuf = (char *) malloc(bufsize + 1);
00143     strncpy(*aOutBuf, buf, bufsize);
00144     *(*aOutBuf + bufsize) = 0;
00145     *aOutBufSize = bufsize + 1;
00146 
00147     return mError;
00148 }
00149 
00150 int
00151 nsINIParser::GetError()
00152 {
00153     DUMP("GetError");
00154     return mError;
00155 }
00156 
00157 char *
00158 nsINIParser::ResolveName(char *aINIRoot)
00159 {
00160     char *resolved = NULL;
00161     char *locale = NULL;
00162     struct stat st_exists;
00163 
00164     /* param check */
00165     if (!aINIRoot)
00166         return NULL;
00167 
00168     locale = setlocale(LC_CTYPE, NULL);
00169     if (!locale) 
00170         return NULL;
00171 
00172     /* resolved string: "<root>.ini.<locale>\0" */
00173     resolved = (char *) malloc(strlen(aINIRoot) + 5 + strlen(locale) + 1);
00174     if (!resolved)
00175         return NULL;
00176 
00177     /* locale specific ini file name */
00178     sprintf(resolved, "%s.ini.%s", aINIRoot, locale);
00179     if (0 == stat(resolved, &st_exists))
00180         return resolved;
00181 
00182     /* fallback to general ini file name */
00183     sprintf(resolved, "%s.ini", aINIRoot);
00184     if (0 == stat(resolved, &st_exists))
00185         return resolved;
00186     
00187     /* neither existed so error returned */
00188     return NULL;
00189 }
00190 
00191 int
00192 nsINIParser::FindSection(char *aSection, char **aOutSecPtr)
00193 {
00194     char *currChar = mFileBuf;
00195     char *nextSec = NULL;
00196     char *secClose = NULL;
00197     char *nextNL = NULL;
00198     int aSectionLen = strlen(aSection);
00199     mError = E_NO_SEC;
00200     DUMP("FindSection");
00201 
00202     // param check
00203     if (!aSection || !aOutSecPtr)
00204     {
00205         mError = E_PARAM;
00206         return mError;
00207     }
00208 
00209     while (currChar < (mFileBuf + mFileBufSize))
00210     {
00211         // look for first '['
00212         nextSec = NULL;
00213         nextSec = strchr(currChar, '[');
00214         if (!nextSec)
00215             break;
00216             
00217         currChar = nextSec + 1;
00218 
00219         // extract section name till first ']'
00220         secClose = NULL; nextNL = NULL;
00221         secClose = strchr(currChar, ']');
00222         nextNL = strchr(currChar, NL);
00223         if ((!nextNL) || (nextNL < secClose))
00224         {
00225             currChar = nextNL;
00226             continue;
00227         }
00228 
00229         // if section name matches we succeeded
00230         if (strncmp(aSection, currChar, aSectionLen) == 0
00231               && secClose-currChar == aSectionLen)
00232         {
00233             *aOutSecPtr = secClose + 1;
00234             mError = OK;
00235             break;
00236         }
00237     }
00238 
00239     return mError;
00240 }
00241 
00242 int
00243 nsINIParser::FindKey(char *aSecPtr, char *aKey, char *aVal, int *aIOValSize)
00244 {
00245     char *nextNL = NULL;
00246     char *secEnd = NULL;
00247     char *currLine = aSecPtr;
00248     char *nextEq = NULL;
00249     int  aKeyLen = strlen(aKey); 
00250     mError = E_NO_KEY;
00251     DUMP("FindKey");
00252 
00253     // param check
00254     if (!aSecPtr || !aKey || !aVal || !aIOValSize || (*aIOValSize <= 0))
00255     {
00256         mError = E_PARAM;
00257         return mError;
00258     }
00259 
00260     // determine the section end
00261     secEnd = aSecPtr;
00262 find_end:
00263     if (secEnd)
00264         secEnd = strchr(secEnd, '['); // search for next sec start
00265     if (!secEnd)
00266     {
00267         secEnd = strchr(aSecPtr, '\0'); // else search for file end
00268         if (!secEnd)
00269         {
00270             mError = E_SEC_CORRUPT; // else this data is corrupt
00271             return mError;
00272         }
00273     }
00274 
00275     // handle start section token ('[') in values for i18n
00276     if (*secEnd == '[' && !(secEnd == aSecPtr || *(secEnd-1) == NL))
00277     {
00278         secEnd++;
00279         goto find_end;
00280     }
00281 
00282     while (currLine < secEnd)
00283     {
00284         nextNL = NULL;
00285         nextNL = strchr(currLine, NL);
00286         if (!nextNL)
00287             nextNL = mFileBuf + mFileBufSize;
00288 
00289         // ignore commented lines (starting with ;)
00290         if (currLine == strchr(currLine, ';'))
00291         {
00292             currLine = nextNL + 1;
00293             continue;
00294         }
00295 
00296         // extract key before '='
00297         nextEq = NULL;
00298         nextEq = strchr(currLine, '=');
00299         if (!nextEq || nextEq > nextNL) 
00300         {
00301             currLine = nextNL + 1;
00302             continue;
00303         }
00304 
00305         // if key matches we succeeded
00306         if (strncmp(currLine, aKey, aKeyLen) == 0
00307               && nextEq-currLine == aKeyLen)
00308         {
00309             // extract the value and return
00310             if (*aIOValSize < nextNL - nextEq)
00311             {
00312                 mError = E_SMALL_BUF;
00313                 *aVal = '\0';
00314                 *aIOValSize = 0;
00315                 return mError;
00316             }
00317                 
00318             *aIOValSize = nextNL - (nextEq + 1); 
00319             strncpy(aVal, (nextEq + 1), *aIOValSize);
00320             *(aVal + *aIOValSize) = 0; // null terminate
00321             mError = OK;
00322             return mError;
00323         }
00324         else
00325         {
00326             currLine = nextNL + 1;
00327         }
00328     }
00329 
00330     return mError;
00331 }