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.
36 #include <Directory.h>
38 #include <FindDirectory.h>
41 #include <StopWatch.h>
50 #include "SettingsHandler.h"
53 // #pragma mark - ArgvParser
56 ArgvParser::ArgvParser(const char* name
)
66 fInDoubleQuote(false),
67 fInSingleQuote(false),
71 fFile
= fopen(fFileName
, "r");
73 PRINT(("Error opening %s\n", fFileName
));
76 fBuffer
= new char [kBufferSize
];
77 fCurrentArgv
= new char * [1024];
81 ArgvParser::~ArgvParser()
86 delete[] fCurrentArgv
;
94 ArgvParser::MakeArgvEmpty()
96 // done with current argv, free it up
97 for (int32 index
= 0; index
< fArgc
; index
++)
98 delete[] fCurrentArgv
[index
];
105 ArgvParser::SendArgv(ArgvHandler argvHandlerFunc
, void* passThru
)
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
,
125 ArgvParser::NextArgv()
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;
143 ArgvParser::NextArgvIfNotEmpty()
145 if (!fSawBackslash
&& fCurrentArgsPos
< 0)
155 if (fPos
< 0 || fBuffer
[fPos
] == 0) {
158 if (fgets(fBuffer
, kBufferSize
, fFile
) == 0)
163 return fBuffer
[fPos
++];
168 ArgvParser::EachArgv(const char* name
, ArgvHandler argvHandlerFunc
,
171 ArgvParser
parser(name
);
173 return parser
.EachArgvPrivate(name
, argvHandlerFunc
, passThru
);
178 ArgvParser::EachArgvPrivate(const char* name
, ArgvHandler argvHandlerFunc
,
187 if (fInDoubleQuote
|| fInSingleQuote
) {
188 printf("File %s # unterminated quote at end of file\n", name
);
192 result
= SendArgv(argvHandlerFunc
, passThru
);
196 if (ch
== '\n' || ch
== '\r') {
199 if (!fSawBackslash
&& (fInDoubleQuote
|| fInSingleQuote
)) {
200 printf("File %s ; Line %" B_PRId32
" # unterminated quote\n",
208 fSawBackslash
= false;
212 // end of line, flush all argv
213 result
= SendArgv(argvHandlerFunc
, passThru
);
221 if (!fSawBackslash
) {
222 if (!fInDoubleQuote
&& !fInSingleQuote
) {
224 // semicolon is a command separator, pass on
226 result
= SendArgv(argvHandlerFunc
, passThru
);
230 } else if (ch
== '#') {
231 // ignore everything on this line after this character
234 } else if (ch
== ' ' || ch
== '\t') {
235 // space or tab separates the individual arg strings
236 NextArgvIfNotEmpty();
238 } else if (!fSawBackslash
&& ch
== '\\') {
239 // the next character is escaped
240 fSawBackslash
= true;
244 if (!fInSingleQuote
&& ch
== '"') {
245 // enter/exit double quote handling
246 fInDoubleQuote
= !fInDoubleQuote
;
249 if (!fInDoubleQuote
&& ch
== '\'') {
250 // enter/exit single quote handling
251 fInSingleQuote
= !fInSingleQuote
;
255 // we just pass through the escape sequence as is
256 fCurrentArgs
[++fCurrentArgsPos
] = '\\';
257 fSawBackslash
= false;
259 fCurrentArgs
[++fCurrentArgsPos
] = ch
;
266 // #pragma mark - SettingsArgvDispatcher
269 SettingsArgvDispatcher::SettingsArgvDispatcher(const char* name
)
277 SettingsArgvDispatcher::SaveSettings(Settings
* settings
,
278 bool onlyIfNonDefault
)
280 if (!onlyIfNonDefault
|| NeedsSaving()) {
281 settings
->Write("%s ", Name());
282 SaveSettingValue(settings
);
283 settings
->Write("\n");
289 SettingsArgvDispatcher::HandleRectValue(BRect
&result
,
290 const char* const* argv
, bool printError
)
294 printf("rect left expected");
297 result
.left
= atoi(*argv
);
301 printf("rect top expected");
304 result
.top
= atoi(*argv
);
308 printf("rect right expected");
311 result
.right
= atoi(*argv
);
315 printf("rect bottom expected");
318 result
.bottom
= atoi(*argv
);
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
)
335 fSettingsDir(settingsDirName
),
341 fList
= (SettingsArgvDispatcher
**)calloc((size_t)fListSize
,
342 sizeof(SettingsArgvDispatcher
*));
346 Settings::~Settings()
348 for (int32 index
= 0; index
< fCount
; index
++)
356 Settings::ParseUserSettings(int, const char* const* argv
, void* castToThis
)
361 SettingsArgvDispatcher
* handler
= ((Settings
*)castToThis
)->Find(*argv
);
363 return "unknown command";
365 return handler
->Handle(argv
);
370 Settings::Add(SettingsArgvDispatcher
* setting
)
372 // check for uniqueness
373 if (Find(setting
->Name()))
376 if (fCount
>= fListSize
) {
378 fList
= (SettingsArgvDispatcher
**)realloc(fList
,
379 fListSize
* sizeof(SettingsArgvDispatcher
*));
381 fList
[fCount
++] = setting
;
386 SettingsArgvDispatcher
*
387 Settings::Find(const char* name
)
389 for (int32 index
= 0; index
< fCount
; index
++)
390 if (strcmp(name
, fList
[index
]->Name()) == 0)
398 Settings::TryReadingSettings()
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);
412 Settings::SaveSettings(bool onlyIfNonDefault
)
414 SaveCurrentSettings(onlyIfNonDefault
);
419 Settings::MakeSettingsDirectory(BDirectory
* resultingSettingsDir
)
422 if (find_directory(B_USER_SETTINGS_DIRECTORY
, &path
, true) != B_OK
)
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
);
433 mid
= strchr(mid
, '/');
441 resultingSettingsDir
->SetTo(path
.Path());
446 Settings::SaveCurrentSettings(bool onlyIfNonDefault
)
448 BDirectory settingsDir
;
449 MakeSettingsDirectory(&settingsDir
);
451 if (settingsDir
.InitCheck() != B_OK
)
455 BEntry
entry(&settingsDir
, fFileName
);
458 BFile
prefs(&entry
, O_RDWR
| O_CREAT
);
459 if (prefs
.InitCheck() != B_OK
)
462 fCurrentSettings
= &prefs
;
463 for (int32 index
= 0; index
< fCount
; index
++)
464 fList
[index
]->SaveSettings(this, onlyIfNonDefault
);
466 fCurrentSettings
= NULL
;
471 Settings::Write(const char* format
, ...)
475 va_start(args
, format
);
476 VSWrite(format
, args
);
482 Settings::VSWrite(const char* format
, va_list arg
)
485 vsprintf(fBuffer
, format
, arg
);
486 ASSERT(fCurrentSettings
&& fCurrentSettings
->InitCheck() == B_OK
);
487 fCurrentSettings
->Write(fBuffer
, strlen(fBuffer
));