1 #include "SettingsHandler.h"
10 #include <Directory.h>
13 #include <FindDirectory.h>
16 #include <StopWatch.h>
19 #undef B_TRANSLATION_CONTEXT
20 #define B_TRANSLATION_CONTEXT "SettingsHandler"
25 Compare(const SettingsArgvDispatcher
* p1
, const SettingsArgvDispatcher
* p2
)
27 return strcmp(p1
->Name(), p2
->Name());
34 CompareByNameOne(const SettingsArgvDispatcher
* item1
,
35 const SettingsArgvDispatcher
* item2
)
37 return strcmp(item1
->Name(), item2
->Name());
43 ArgvParser class opens a text file and passes the context in argv
44 format to a specified handler
48 ArgvParser::ArgvParser(const char* name
)
58 fInDoubleQuote(false),
59 fInSingleQuote(false),
63 fFile
= fopen(fFileName
, "r");
65 PRINT((B_TRANSLATE("Error opening %s\n"), fFileName
));
68 fBuffer
= new char [kBufferSize
];
69 fCurrentArgv
= new char* [1024];
73 ArgvParser::~ArgvParser()
78 delete [] fCurrentArgv
;
86 ArgvParser::MakeArgvEmpty()
88 // done with current argv, free it up
89 for (int32 index
= 0; index
< fArgc
; index
++)
90 delete fCurrentArgv
[index
];
97 ArgvParser::SendArgv(ArgvHandler argvHandlerFunc
, void* passThru
)
101 fCurrentArgv
[fArgc
] = 0;
102 const char *result
= (argvHandlerFunc
)(fArgc
, fCurrentArgv
, passThru
);
104 printf(B_TRANSLATE("File %s; Line %ld # %s"), fFileName
, fLineNo
, result
);
115 ArgvParser::NextArgv()
118 fCurrentArgs
[++fCurrentArgsPos
] = '\\';
119 fSawBackslash
= false;
121 fCurrentArgs
[++fCurrentArgsPos
] = '\0';
122 // terminate current arg pos
124 // copy it as a string to the current argv slot
125 fCurrentArgv
[fArgc
] = new char [strlen(fCurrentArgs
) + 1];
126 strcpy(fCurrentArgv
[fArgc
], fCurrentArgs
);
127 fCurrentArgsPos
= -1;
133 ArgvParser::NextArgvIfNotEmpty()
135 if (!fSawBackslash
&& fCurrentArgsPos
< 0)
145 if (fPos
< 0 || fBuffer
[fPos
] == 0) {
148 if (fgets(fBuffer
, kBufferSize
, fFile
) == 0)
152 return fBuffer
[fPos
++];
157 ArgvParser::EachArgv(const char* name
, ArgvHandler argvHandlerFunc
,
160 ArgvParser
parser(name
);
161 return parser
.EachArgvPrivate(name
, argvHandlerFunc
, passThru
);
166 ArgvParser::EachArgvPrivate(const char* name
, ArgvHandler argvHandlerFunc
,
175 if (fInDoubleQuote
|| fInSingleQuote
) {
176 printf(B_TRANSLATE("File %s # unterminated quote at end of "
181 result
= SendArgv(argvHandlerFunc
, passThru
);
185 if (ch
== '\n' || ch
== '\r') {
188 if (!fSawBackslash
&& (fInDoubleQuote
|| fInSingleQuote
)) {
189 printf(B_TRANSLATE("File %s ; Line %ld # unterminated "
190 "quote\n"), name
, fLineNo
);
196 fSawBackslash
= false;
199 // end of line, flush all argv
200 result
= SendArgv(argvHandlerFunc
, passThru
);
201 if (result
!= B_NO_ERROR
)
209 if (!fSawBackslash
) {
210 if (!fInDoubleQuote
&& !fInSingleQuote
) {
212 // semicolon is a command separator, pass on the whole argv
213 result
= SendArgv(argvHandlerFunc
, passThru
);
214 if (result
!= B_NO_ERROR
)
217 } else if (ch
== '#') {
218 // ignore everything on this line after this character
221 } else if (ch
== ' ' || ch
== '\t') {
222 // space or tab separates the individual arg strings
223 NextArgvIfNotEmpty();
225 } else if (!fSawBackslash
&& ch
== '\\') {
226 // the next character is escaped
227 fSawBackslash
= true;
231 if (!fInSingleQuote
&& ch
== '"') {
232 // enter/exit double quote handling
233 fInDoubleQuote
= !fInDoubleQuote
;
236 if (!fInDoubleQuote
&& ch
== '\'') {
237 // enter/exit single quote handling
238 fInSingleQuote
= !fInSingleQuote
;
242 // we just pass through the escape sequence as is
243 fCurrentArgs
[++fCurrentArgsPos
] = '\\';
244 fSawBackslash
= false;
246 fCurrentArgs
[++fCurrentArgsPos
] = ch
;
256 SettingsArgvDispatcher::SettingsArgvDispatcher(const char* name
)
264 SettingsArgvDispatcher::SaveSettings(Settings
* settings
, bool onlyIfNonDefault
)
266 if (!onlyIfNonDefault
|| NeedsSaving()) {
267 settings
->Write("%s ", Name());
268 SaveSettingValue(settings
);
269 settings
->Write("\n");
275 SettingsArgvDispatcher::HandleRectValue(BRect
&result
, const char* const *argv
,
280 printf("rect left expected");
283 result
.left
= atoi(*argv
);
286 printf("rect top expected");
289 result
.top
= atoi(*argv
);
292 printf("rect right expected");
295 result
.right
= atoi(*argv
);
298 printf("rect bottom expected");
301 result
.bottom
= atoi(*argv
);
307 SettingsArgvDispatcher::WriteRectValue(Settings
* setting
, BRect rect
)
309 setting
->Write("%d %d %d %d", (int32
)rect
.left
, (int32
)rect
.top
,
310 (int32
)rect
.right
, (int32
)rect
.bottom
);
318 this class represents a list of all the settings handlers, reads and
319 saves the settings file
323 Settings::Settings(const char* filename
, const char* settingsDirName
)
326 fSettingsDir(settingsDirName
),
332 #ifdef SINGLE_SETTING_FILE
333 settingsHandler
= this;
335 fList
= (SettingsArgvDispatcher
**)calloc(fListSize
, sizeof(SettingsArgvDispatcher
*));
339 Settings::~Settings()
341 for (int32 index
= 0; index
< fCount
; index
++)
349 Settings::_ParseUserSettings(int, const char* const *argv
, void* castToThis
)
354 #ifdef SINGLE_SETTING_FILE
355 Settings
* settings
= settingsHandler
;
357 Settings
* settings
= (Settings
*)castToThis
;
360 SettingsArgvDispatcher
* handler
= settings
->_Find(*argv
);
362 return B_TRANSLATE("unknown command");
363 return handler
->Handle(argv
);
368 Returns false if argv dispatcher with the same name already
372 Settings::Add(SettingsArgvDispatcher
* setting
)
374 // check for uniqueness
375 if (_Find(setting
->Name()))
378 if (fCount
>= fListSize
) {
380 fList
= (SettingsArgvDispatcher
**)realloc(fList
,
381 fListSize
* sizeof(SettingsArgvDispatcher
*));
383 fList
[fCount
++] = setting
;
388 SettingsArgvDispatcher
*
389 Settings::_Find(const char* name
)
391 for (int32 index
= 0; index
< fCount
; index
++)
392 if (strcmp(name
, fList
[index
]->Name()) == 0)
400 Settings::TryReadingSettings()
403 if (find_directory(B_USER_SETTINGS_DIRECTORY
, &prefsPath
, true) == B_OK
) {
404 prefsPath
.Append(fSettingsDir
);
406 BPath
path(prefsPath
);
407 path
.Append(fFileName
);
408 ArgvParser::EachArgv(path
.Path(), Settings::_ParseUserSettings
, this);
414 Settings::SaveSettings(bool onlyIfNonDefault
)
416 ASSERT(SettingsHandler());
417 SettingsHandler()->_SaveCurrentSettings(onlyIfNonDefault
);
422 Settings::_MakeSettingsDirectory(BDirectory
*resultingSettingsDir
)
425 if (find_directory(B_USER_SETTINGS_DIRECTORY
, &path
, true) != B_OK
)
428 // make sure there is a directory
429 path
.Append(fSettingsDir
);
430 mkdir(path
.Path(), 0777);
431 resultingSettingsDir
->SetTo(path
.Path());
436 Settings::_SaveCurrentSettings(bool onlyIfNonDefault
)
438 BDirectory fSettingsDir
;
439 _MakeSettingsDirectory(&fSettingsDir
);
441 if (fSettingsDir
.InitCheck() != B_OK
)
444 printf("+++++++++++ Settings::_SaveCurrentSettings %s\n", fFileName
);
446 BEntry
entry(&fSettingsDir
, fFileName
);
449 BFile
prefs(&entry
, O_RDWR
| O_CREAT
);
450 if (prefs
.InitCheck() != B_OK
)
453 fCurrentSettings
= &prefs
;
454 for (int32 index
= 0; index
< fCount
; index
++) {
455 fList
[index
]->SaveSettings(this, onlyIfNonDefault
);
458 fCurrentSettings
= 0;
463 Settings::Write(const char* format
, ...)
467 va_start(args
, format
);
468 VSWrite(format
, args
);
474 Settings::VSWrite(const char* format
, va_list arg
)
477 vsprintf(buffer
, format
, arg
);
478 ASSERT(fCurrentSettings
&& fCurrentSettings
->InitCheck() == B_OK
);
479 fCurrentSettings
->Write(buffer
, strlen(buffer
));
483 #ifdef SINGLE_SETTING_FILE
484 Settings
* Settings::settingsHandler
= 0;