On x86 compilers without fastcall, simulate it when invoking traces and un-simulate...
[wine-gecko.git] / xpcom / glue / nsINIParser.cpp
blobf0a15c805198d0fa5e2e2f34312314a54d5ed6a8
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is Mozilla Communicator client code, released
16 * March 31, 1998.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 1998
21 * the Initial Developer. All Rights Reserved.
23 * Contributor(s):
24 * Samir Gehani <sgehani@netscape.com>
25 * Benjamin Smedberg <bsmedberg@covad.net>
27 * Alternatively, the contents of this file may be used under the terms of
28 * either the GNU General Public License Version 2 or later (the "GPL"), or
29 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
41 #include "nsINIParser.h"
42 #include "nsError.h"
43 #include "nsILocalFile.h"
44 #include "nsCRTGlue.h"
46 #include <stdlib.h>
47 #include <stdio.h>
49 #if defined(XP_WIN) || defined(XP_OS2)
50 #define BINARY_MODE "b"
51 #else
52 #define BINARY_MODE
53 #endif
55 // Stack based FILE wrapper to ensure that fclose is called, copied from
56 // toolkit/mozapps/update/src/updater/readstrings.cpp
58 class AutoFILE {
59 public:
60 AutoFILE(FILE *fp = nsnull) : fp_(fp) {}
61 ~AutoFILE() { if (fp_) fclose(fp_); }
62 operator FILE *() { return fp_; }
63 FILE** operator &() { return &fp_; }
64 void operator=(FILE *fp) { fp_ = fp; }
65 private:
66 FILE *fp_;
69 nsresult
70 nsINIParser::Init(nsILocalFile* aFile)
72 nsresult rv;
74 /* open the file. Don't use OpenANSIFileDesc, because you mustn't
75 pass FILE* across shared library boundaries, which may be using
76 different CRTs */
78 AutoFILE fd;
80 #ifdef XP_WIN
81 nsAutoString path;
82 rv = aFile->GetPath(path);
83 NS_ENSURE_SUCCESS(rv, rv);
85 fd = _wfopen(path.get(), L"rb");
86 #else
87 nsCAutoString path;
88 rv = aFile->GetNativePath(path);
89 NS_ENSURE_SUCCESS(rv, rv);
91 fd = fopen(path.get(), "r" BINARY_MODE);
92 #endif
93 if (!fd)
94 return NS_ERROR_FAILURE;
96 return InitFromFILE(fd);
99 nsresult
100 nsINIParser::Init(const char *aPath)
102 /* open the file */
103 AutoFILE fd = fopen(aPath, "r" BINARY_MODE);
104 if (!fd)
105 return NS_ERROR_FAILURE;
107 return InitFromFILE(fd);
110 static const char kNL[] = "\r\n";
111 static const char kEquals[] = "=";
112 static const char kWhitespace[] = " \t";
113 static const char kRBracket[] = "]";
115 nsresult
116 nsINIParser::InitFromFILE(FILE *fd)
118 if (!mSections.Init())
119 return NS_ERROR_OUT_OF_MEMORY;
121 /* get file size */
122 if (fseek(fd, 0, SEEK_END) != 0)
123 return NS_ERROR_FAILURE;
125 long flen = ftell(fd);
126 if (flen == 0)
127 return NS_ERROR_FAILURE;
129 /* malloc an internal buf the size of the file */
130 mFileContents = new char[flen + 1];
131 if (!mFileContents)
132 return NS_ERROR_OUT_OF_MEMORY;
134 /* read the file in one swoop */
135 if (fseek(fd, 0, SEEK_SET) != 0)
136 return NS_BASE_STREAM_OSERROR;
138 int rd = fread(mFileContents, sizeof(char), flen, fd);
139 if (rd != flen)
140 return NS_BASE_STREAM_OSERROR;
142 mFileContents[flen] = '\0';
144 char *buffer = mFileContents;
145 char *currSection = nsnull;
146 INIValue *last = nsnull;
148 // outer loop tokenizes into lines
149 while (char *token = NS_strtok(kNL, &buffer)) {
150 if (token[0] == '#' || token[0] == ';') // it's a comment
151 continue;
153 token = (char*) NS_strspnp(kWhitespace, token);
154 if (!*token) // empty line
155 continue;
157 if (token[0] == '[') { // section header!
158 ++token;
159 currSection = token;
160 last = nsnull;
162 char *rb = NS_strtok(kRBracket, &token);
163 if (!rb || NS_strtok(kWhitespace, &token)) {
164 // there's either an unclosed [Section or a [Section]Moretext!
165 // we could frankly decide that this INI file is malformed right
166 // here and stop, but we won't... keep going, looking for
167 // a well-formed [section] to continue working with
168 currSection = nsnull;
171 continue;
174 if (!currSection) {
175 // If we haven't found a section header (or we found a malformed
176 // section header), don't bother parsing this line.
177 continue;
180 char *key = token;
181 char *e = NS_strtok(kEquals, &token);
182 if (!e)
183 continue;
185 INIValue *val = new INIValue(key, token);
186 if (!val)
187 return NS_ERROR_OUT_OF_MEMORY;
189 // If we haven't already added something to this section, "last" will
190 // be null.
191 if (!last) {
192 mSections.Get(currSection, &last);
193 while (last && last->next)
194 last = last->next;
197 if (last) {
198 // Add this element on to the tail of the existing list
200 last->next = val;
201 last = val;
202 continue;
205 // We've never encountered this section before, add it to the head
206 mSections.Put(currSection, val);
209 return NS_OK;
212 nsresult
213 nsINIParser::GetString(const char *aSection, const char *aKey,
214 nsACString &aResult)
216 INIValue *val;
217 mSections.Get(aSection, &val);
219 while (val) {
220 if (strcmp(val->key, aKey) == 0) {
221 aResult.Assign(val->value);
222 return NS_OK;
225 val = val->next;
228 return NS_ERROR_FAILURE;
231 nsresult
232 nsINIParser::GetString(const char *aSection, const char *aKey,
233 char *aResult, PRUint32 aResultLen)
235 INIValue *val;
236 mSections.Get(aSection, &val);
238 while (val) {
239 if (strcmp(val->key, aKey) == 0) {
240 strncpy(aResult, val->value, aResultLen);
241 aResult[aResultLen - 1] = '\0';
242 if (strlen(val->value) >= aResultLen)
243 return NS_ERROR_LOSS_OF_SIGNIFICANT_DATA;
245 return NS_OK;
248 val = val->next;
251 return NS_ERROR_FAILURE;
254 PLDHashOperator
255 nsINIParser::GetSectionsCB(const char *aKey, INIValue *aData,
256 void *aClosure)
258 GSClosureStruct *cs = reinterpret_cast<GSClosureStruct*>(aClosure);
260 return cs->usercb(aKey, cs->userclosure) ? PL_DHASH_NEXT : PL_DHASH_STOP;
263 nsresult
264 nsINIParser::GetSections(INISectionCallback aCB, void *aClosure)
266 GSClosureStruct gs = {
267 aCB,
268 aClosure
271 mSections.EnumerateRead(GetSectionsCB, &gs);
272 return NS_OK;
275 nsresult
276 nsINIParser::GetStrings(const char *aSection,
277 INIStringCallback aCB, void *aClosure)
279 INIValue *val;
281 for (mSections.Get(aSection, &val);
282 val;
283 val = val->next) {
285 if (!aCB(val->key, val->value, aClosure))
286 return NS_OK;
289 return NS_OK;