Assorted whitespace cleanup and typo fixes.
[haiku.git] / src / kits / tracker / SettingsHandler.cpp
blob006281e4c2f78097428a9f06cefc2a4864c78136
1 /*
2 Open Tracker License
4 Terms and Conditions
6 Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
8 Permission is hereby granted, free of charge, to any person obtaining a copy of
9 this software and associated documentation files (the "Software"), to deal in
10 the Software without restriction, including without limitation the rights to
11 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12 of the Software, and to permit persons to whom the Software is furnished to do
13 so, subject to the following conditions:
15 The above copyright notice and this permission notice applies to all licensees
16 and shall be included in all copies or substantial portions of the Software.
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
23 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 Except as contained in this notice, the name of Be Incorporated shall not be
26 used in advertising or otherwise to promote the sale, use or other dealings in
27 this Software without prior written authorization from Be Incorporated.
29 Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
30 of Be Incorporated in the United States and other countries. Other brand product
31 names are registered trademarks or trademarks of their respective holders.
32 All rights reserved.
35 #include <Debug.h>
36 #include <Directory.h>
37 #include <Entry.h>
38 #include <FindDirectory.h>
39 #include <File.h>
40 #include <Path.h>
41 #include <StopWatch.h>
43 #include <alloca.h>
44 #include <stdlib.h>
45 #include <stdio.h>
46 #include <string.h>
47 #include <stdarg.h>
50 #include "SettingsHandler.h"
53 // #pragma mark - ArgvParser
56 ArgvParser::ArgvParser(const char* name)
58 fFile(0),
59 fBuffer(NULL),
60 fPos(-1),
61 fArgc(0),
62 fCurrentArgv(0),
63 fCurrentArgsPos(-1),
64 fSawBackslash(false),
65 fEatComment(false),
66 fInDoubleQuote(false),
67 fInSingleQuote(false),
68 fLineNo(0),
69 fFileName(name)
71 fFile = fopen(fFileName, "r");
72 if (!fFile) {
73 PRINT(("Error opening %s\n", fFileName));
74 return;
76 fBuffer = new char [kBufferSize];
77 fCurrentArgv = new char * [1024];
81 ArgvParser::~ArgvParser()
83 delete[] fBuffer;
85 MakeArgvEmpty();
86 delete[] fCurrentArgv;
88 if (fFile)
89 fclose(fFile);
93 void
94 ArgvParser::MakeArgvEmpty()
96 // done with current argv, free it up
97 for (int32 index = 0; index < fArgc; index++)
98 delete[] fCurrentArgv[index];
100 fArgc = 0;
104 status_t
105 ArgvParser::SendArgv(ArgvHandler argvHandlerFunc, void* passThru)
107 if (fArgc) {
108 NextArgv();
109 fCurrentArgv[fArgc] = 0;
110 const char* result = (argvHandlerFunc)(fArgc, fCurrentArgv, passThru);
111 if (result != NULL) {
112 printf("File %s; Line %" B_PRId32 " # %s", fFileName, fLineNo,
113 result);
115 MakeArgvEmpty();
116 if (result != NULL)
117 return B_ERROR;
120 return B_OK;
124 void
125 ArgvParser::NextArgv()
127 if (fSawBackslash) {
128 fCurrentArgs[++fCurrentArgsPos] = '\\';
129 fSawBackslash = false;
131 fCurrentArgs[++fCurrentArgsPos] = '\0';
132 // terminate current arg pos
134 // copy it as a string to the current argv slot
135 fCurrentArgv[fArgc] = new char [strlen(fCurrentArgs) + 1];
136 strcpy(fCurrentArgv[fArgc], fCurrentArgs);
137 fCurrentArgsPos = -1;
138 fArgc++;
142 void
143 ArgvParser::NextArgvIfNotEmpty()
145 if (!fSawBackslash && fCurrentArgsPos < 0)
146 return;
148 NextArgv();
152 char
153 ArgvParser::GetCh()
155 if (fPos < 0 || fBuffer[fPos] == 0) {
156 if (fFile == 0)
157 return EOF;
158 if (fgets(fBuffer, kBufferSize, fFile) == 0)
159 return EOF;
160 fPos = 0;
163 return fBuffer[fPos++];
167 status_t
168 ArgvParser::EachArgv(const char* name, ArgvHandler argvHandlerFunc,
169 void* passThru)
171 ArgvParser parser(name);
173 return parser.EachArgvPrivate(name, argvHandlerFunc, passThru);
177 status_t
178 ArgvParser::EachArgvPrivate(const char* name, ArgvHandler argvHandlerFunc,
179 void* passThru)
181 status_t result;
183 for (;;) {
184 char ch = GetCh();
185 if (ch == EOF) {
186 // done with fFile
187 if (fInDoubleQuote || fInSingleQuote) {
188 printf("File %s # unterminated quote at end of file\n", name);
189 result = B_ERROR;
190 break;
192 result = SendArgv(argvHandlerFunc, passThru);
193 break;
196 if (ch == '\n' || ch == '\r') {
197 // handle new line
198 fEatComment = false;
199 if (!fSawBackslash && (fInDoubleQuote || fInSingleQuote)) {
200 printf("File %s ; Line %" B_PRId32 " # unterminated quote\n",
201 name, fLineNo);
202 result = B_ERROR;
203 break;
206 fLineNo++;
207 if (fSawBackslash) {
208 fSawBackslash = false;
209 continue;
212 // end of line, flush all argv
213 result = SendArgv(argvHandlerFunc, passThru);
215 continue;
218 if (fEatComment)
219 continue;
221 if (!fSawBackslash) {
222 if (!fInDoubleQuote && !fInSingleQuote) {
223 if (ch == ';') {
224 // semicolon is a command separator, pass on
225 // the whole argv
226 result = SendArgv(argvHandlerFunc, passThru);
227 if (result != B_OK)
228 break;
229 continue;
230 } else if (ch == '#') {
231 // ignore everything on this line after this character
232 fEatComment = true;
233 continue;
234 } else if (ch == ' ' || ch == '\t') {
235 // space or tab separates the individual arg strings
236 NextArgvIfNotEmpty();
237 continue;
238 } else if (!fSawBackslash && ch == '\\') {
239 // the next character is escaped
240 fSawBackslash = true;
241 continue;
244 if (!fInSingleQuote && ch == '"') {
245 // enter/exit double quote handling
246 fInDoubleQuote = !fInDoubleQuote;
247 continue;
249 if (!fInDoubleQuote && ch == '\'') {
250 // enter/exit single quote handling
251 fInSingleQuote = !fInSingleQuote;
252 continue;
254 } else {
255 // we just pass through the escape sequence as is
256 fCurrentArgs[++fCurrentArgsPos] = '\\';
257 fSawBackslash = false;
259 fCurrentArgs[++fCurrentArgsPos] = ch;
262 return result;
266 // #pragma mark - SettingsArgvDispatcher
269 SettingsArgvDispatcher::SettingsArgvDispatcher(const char* name)
271 name(name)
276 void
277 SettingsArgvDispatcher::SaveSettings(Settings* settings,
278 bool onlyIfNonDefault)
280 if (!onlyIfNonDefault || NeedsSaving()) {
281 settings->Write("%s ", Name());
282 SaveSettingValue(settings);
283 settings->Write("\n");
288 bool
289 SettingsArgvDispatcher::HandleRectValue(BRect &result,
290 const char* const* argv, bool printError)
292 if (!*argv) {
293 if (printError)
294 printf("rect left expected");
295 return false;
297 result.left = atoi(*argv);
299 if (!*++argv) {
300 if (printError)
301 printf("rect top expected");
302 return false;
304 result.top = atoi(*argv);
306 if (!*++argv) {
307 if (printError)
308 printf("rect right expected");
309 return false;
311 result.right = atoi(*argv);
313 if (!*++argv) {
314 if (printError)
315 printf("rect bottom expected");
316 return false;
318 result.bottom = atoi(*argv);
320 return true;
324 void
325 SettingsArgvDispatcher::WriteRectValue(Settings* setting, BRect rect)
327 setting->Write("%d %d %d %d", (int32)rect.left, (int32)rect.top,
328 (int32)rect.right, (int32)rect.bottom);
332 Settings::Settings(const char* filename, const char* settingsDirName)
334 fFileName(filename),
335 fSettingsDir(settingsDirName),
336 fList(0),
337 fCount(0),
338 fListSize(30),
339 fCurrentSettings(0)
341 fList = (SettingsArgvDispatcher**)calloc((size_t)fListSize,
342 sizeof(SettingsArgvDispatcher*));
346 Settings::~Settings()
348 for (int32 index = 0; index < fCount; index++)
349 delete fList[index];
351 free(fList);
355 const char*
356 Settings::ParseUserSettings(int, const char* const* argv, void* castToThis)
358 if (!*argv)
359 return 0;
361 SettingsArgvDispatcher* handler = ((Settings*)castToThis)->Find(*argv);
362 if (!handler)
363 return "unknown command";
365 return handler->Handle(argv);
369 bool
370 Settings::Add(SettingsArgvDispatcher* setting)
372 // check for uniqueness
373 if (Find(setting->Name()))
374 return false;
376 if (fCount >= fListSize) {
377 fListSize += 30;
378 fList = (SettingsArgvDispatcher**)realloc(fList,
379 fListSize * sizeof(SettingsArgvDispatcher*));
381 fList[fCount++] = setting;
382 return true;
386 SettingsArgvDispatcher*
387 Settings::Find(const char* name)
389 for (int32 index = 0; index < fCount; index++)
390 if (strcmp(name, fList[index]->Name()) == 0)
391 return fList[index];
393 return NULL;
397 void
398 Settings::TryReadingSettings()
400 BPath prefsPath;
401 if (find_directory(B_USER_SETTINGS_DIRECTORY, &prefsPath, true) == B_OK) {
402 prefsPath.Append(fSettingsDir);
404 BPath path(prefsPath);
405 path.Append(fFileName);
406 ArgvParser::EachArgv(path.Path(), Settings::ParseUserSettings, this);
411 void
412 Settings::SaveSettings(bool onlyIfNonDefault)
414 SaveCurrentSettings(onlyIfNonDefault);
418 void
419 Settings::MakeSettingsDirectory(BDirectory* resultingSettingsDir)
421 BPath path;
422 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path, true) != B_OK)
423 return;
425 // make sure there is a directory
426 // mkdir() will only make one leaf at a time, unfortunately
427 path.Append(fSettingsDir);
428 char* ptr = (char *)alloca(strlen(path.Path()) + 1);
429 strcpy(ptr, path.Path());
430 char* end = ptr+strlen(ptr);
431 char* mid = ptr+1;
432 while (mid < end) {
433 mid = strchr(mid, '/');
434 if (!mid) break;
435 *mid = 0;
436 mkdir(ptr, 0777);
437 *mid = '/';
438 mid++;
440 mkdir(ptr, 0777);
441 resultingSettingsDir->SetTo(path.Path());
445 void
446 Settings::SaveCurrentSettings(bool onlyIfNonDefault)
448 BDirectory settingsDir;
449 MakeSettingsDirectory(&settingsDir);
451 if (settingsDir.InitCheck() != B_OK)
452 return;
454 // nuke old settings
455 BEntry entry(&settingsDir, fFileName);
456 entry.Remove();
458 BFile prefs(&entry, O_RDWR | O_CREAT);
459 if (prefs.InitCheck() != B_OK)
460 return;
462 fCurrentSettings = &prefs;
463 for (int32 index = 0; index < fCount; index++)
464 fList[index]->SaveSettings(this, onlyIfNonDefault);
466 fCurrentSettings = NULL;
470 void
471 Settings::Write(const char* format, ...)
473 va_list args;
475 va_start(args, format);
476 VSWrite(format, args);
477 va_end(args);
481 void
482 Settings::VSWrite(const char* format, va_list arg)
484 char fBuffer[2048];
485 vsprintf(fBuffer, format, arg);
486 ASSERT(fCurrentSettings && fCurrentSettings->InitCheck() == B_OK);
487 fCurrentSettings->Write(fBuffer, strlen(fBuffer));