Move SettingsHandler to libshared

It's used by both Tracker and Codycam and others might find it useful.

Change-Id: I585d3a1bdc7f8fce7d36bedf6867464cd541ba2e
Reviewed-on: https://review.haiku-os.org/c/1637
Reviewed-by: waddlesplash <[email protected]>
This commit is contained in:
Adrien Destugues
2019-07-21 15:47:48 +00:00
committed by waddlesplash
parent d63cb7c8db
commit 194c483884
7 changed files with 26 additions and 655 deletions
@@ -35,11 +35,12 @@ All rights reserved.
#define _SETTINGS_FILE_H
#include <SupportDefs.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <string.h>
#include <SupportDefs.h>
class BFile;
@@ -111,7 +112,7 @@ public:
void SaveSettings(Settings* settings, bool onlyIfNonDefault);
const char* Name() const { return name; }
const char* Name() const { return fName; }
// name as it appears in the settings file
virtual const char* Handle(const char* const *argv) = 0;
@@ -134,7 +135,7 @@ protected:
// and does not need saving
private:
const char* name;
const char* fName;
};
+1 -3
View File
@@ -9,9 +9,8 @@ Application CodyCam :
FtpClient.cpp
SftpClient.cpp
Settings.cpp
SettingsHandler.cpp
VideoConsumer.cpp
: be localestub media translation $(TARGET_NETAPI_LIB)
: be localestub media shared translation $(TARGET_NETAPI_LIB)
[ TargetLibstdc++ ]
: CodyCam.rdef
;
@@ -22,7 +21,6 @@ DoCatalogs CodyCam :
CodyCam.cpp
FtpClient.cpp
Settings.cpp
SettingsHandler.cpp
SftpClient.cpp
VideoConsumer.cpp
;
-485
View File
@@ -1,485 +0,0 @@
#include "SettingsHandler.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <Catalog.h>
#include <Debug.h>
#include <Directory.h>
#include <Entry.h>
#include <File.h>
#include <FindDirectory.h>
#include <Locale.h>
#include <Path.h>
#include <StopWatch.h>
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "SettingsHandler"
#if 0
static int
Compare(const SettingsArgvDispatcher* p1, const SettingsArgvDispatcher* p2)
{
return strcmp(p1->Name(), p2->Name());
}
#endif
#if 0
static int
CompareByNameOne(const SettingsArgvDispatcher* item1,
const SettingsArgvDispatcher* item2)
{
return strcmp(item1->Name(), item2->Name());
}
#endif
/*! \class ArgvParser
ArgvParser class opens a text file and passes the context in argv
format to a specified handler
*/
ArgvParser::ArgvParser(const char* name)
:
fFile(0),
fBuffer(0),
fPos(-1),
fArgc(0),
fCurrentArgv(0),
fCurrentArgsPos(-1),
fSawBackslash(false),
fEatComment(false),
fInDoubleQuote(false),
fInSingleQuote(false),
fLineNo(0),
fFileName(name)
{
fFile = fopen(fFileName, "r");
if (!fFile) {
PRINT((B_TRANSLATE("Error opening %s\n"), fFileName));
return;
}
fBuffer = new char [kBufferSize];
fCurrentArgv = new char* [1024];
}
ArgvParser::~ArgvParser()
{
delete[] fBuffer;
MakeArgvEmpty();
delete [] fCurrentArgv;
if (fFile)
fclose(fFile);
}
void
ArgvParser::MakeArgvEmpty()
{
// done with current argv, free it up
for (int32 index = 0; index < fArgc; index++)
delete fCurrentArgv[index];
fArgc = 0;
}
status_t
ArgvParser::SendArgv(ArgvHandler argvHandlerFunc, void* passThru)
{
if (fArgc) {
NextArgv();
fCurrentArgv[fArgc] = 0;
const char *result = (argvHandlerFunc)(fArgc, fCurrentArgv, passThru);
if (result)
printf(B_TRANSLATE("File %s; Line %ld # %s"), fFileName, fLineNo, result);
MakeArgvEmpty();
if (result)
return B_ERROR;
}
return B_NO_ERROR;
}
void
ArgvParser::NextArgv()
{
if (fSawBackslash) {
fCurrentArgs[++fCurrentArgsPos] = '\\';
fSawBackslash = false;
}
fCurrentArgs[++fCurrentArgsPos] = '\0';
// terminate current arg pos
// copy it as a string to the current argv slot
fCurrentArgv[fArgc] = new char [strlen(fCurrentArgs) + 1];
strcpy(fCurrentArgv[fArgc], fCurrentArgs);
fCurrentArgsPos = -1;
fArgc++;
}
void
ArgvParser::NextArgvIfNotEmpty()
{
if (!fSawBackslash && fCurrentArgsPos < 0)
return;
NextArgv();
}
char
ArgvParser::GetCh()
{
if (fPos < 0 || fBuffer[fPos] == 0) {
if (fFile == 0)
return EOF;
if (fgets(fBuffer, kBufferSize, fFile) == 0)
return EOF;
fPos = 0;
}
return fBuffer[fPos++];
}
status_t
ArgvParser::EachArgv(const char* name, ArgvHandler argvHandlerFunc,
void* passThru)
{
ArgvParser parser(name);
return parser.EachArgvPrivate(name, argvHandlerFunc, passThru);
}
status_t
ArgvParser::EachArgvPrivate(const char* name, ArgvHandler argvHandlerFunc,
void* passThru)
{
status_t result;
for (;;) {
char ch = GetCh();
if (ch == EOF) {
// done with file
if (fInDoubleQuote || fInSingleQuote) {
printf(B_TRANSLATE("File %s # unterminated quote at end of "
"file\n"), name);
result = B_ERROR;
break;
}
result = SendArgv(argvHandlerFunc, passThru);
break;
}
if (ch == '\n' || ch == '\r') {
// handle new line
fEatComment = false;
if (!fSawBackslash && (fInDoubleQuote || fInSingleQuote)) {
printf(B_TRANSLATE("File %s ; Line %ld # unterminated "
"quote\n"), name, fLineNo);
result = B_ERROR;
break;
}
fLineNo++;
if (fSawBackslash) {
fSawBackslash = false;
continue;
}
// end of line, flush all argv
result = SendArgv(argvHandlerFunc, passThru);
if (result != B_NO_ERROR)
break;
continue;
}
if (fEatComment)
continue;
if (!fSawBackslash) {
if (!fInDoubleQuote && !fInSingleQuote) {
if (ch == ';') {
// semicolon is a command separator, pass on the whole argv
result = SendArgv(argvHandlerFunc, passThru);
if (result != B_NO_ERROR)
break;
continue;
} else if (ch == '#') {
// ignore everything on this line after this character
fEatComment = true;
continue;
} else if (ch == ' ' || ch == '\t') {
// space or tab separates the individual arg strings
NextArgvIfNotEmpty();
continue;
} else if (!fSawBackslash && ch == '\\') {
// the next character is escaped
fSawBackslash = true;
continue;
}
}
if (!fInSingleQuote && ch == '"') {
// enter/exit double quote handling
fInDoubleQuote = !fInDoubleQuote;
continue;
}
if (!fInDoubleQuote && ch == '\'') {
// enter/exit single quote handling
fInSingleQuote = !fInSingleQuote;
continue;
}
} else {
// we just pass through the escape sequence as is
fCurrentArgs[++fCurrentArgsPos] = '\\';
fSawBackslash = false;
}
fCurrentArgs[++fCurrentArgsPos] = ch;
}
return result;
}
// #pragma mark -
SettingsArgvDispatcher::SettingsArgvDispatcher(const char* name)
:
fName(name)
{
}
void
SettingsArgvDispatcher::SaveSettings(Settings* settings, bool onlyIfNonDefault)
{
if (!onlyIfNonDefault || NeedsSaving()) {
settings->Write("%s ", Name());
SaveSettingValue(settings);
settings->Write("\n");
}
}
bool
SettingsArgvDispatcher::HandleRectValue(BRect &result, const char* const *argv,
bool printError)
{
if (!*argv) {
if (printError)
printf("rect left expected");
return false;
}
result.left = atoi(*argv);
if (!*++argv) {
if (printError)
printf("rect top expected");
return false;
}
result.top = atoi(*argv);
if (!*++argv) {
if (printError)
printf("rect right expected");
return false;
}
result.right = atoi(*argv);
if (!*++argv) {
if (printError)
printf("rect bottom expected");
return false;
}
result.bottom = atoi(*argv);
return true;
}
void
SettingsArgvDispatcher::WriteRectValue(Settings* setting, BRect rect)
{
setting->Write("%d %d %d %d", (int32)rect.left, (int32)rect.top,
(int32)rect.right, (int32)rect.bottom);
}
// #pragma mark -
/*! \class Settings
this class represents a list of all the settings handlers, reads and
saves the settings file
*/
Settings::Settings(const char* filename, const char* settingsDirName)
:
fFileName(filename),
fSettingsDir(settingsDirName),
fList(0),
fCount(0),
fListSize(30),
fCurrentSettings(0)
{
#ifdef SINGLE_SETTING_FILE
settingsHandler = this;
#endif
fList = (SettingsArgvDispatcher**)calloc(fListSize, sizeof(SettingsArgvDispatcher *));
}
Settings::~Settings()
{
for (int32 index = 0; index < fCount; index++)
delete fList[index];
free(fList);
}
const char*
Settings::_ParseUserSettings(int, const char* const *argv, void* castToThis)
{
if (!*argv)
return 0;
#ifdef SINGLE_SETTING_FILE
Settings* settings = settingsHandler;
#else
Settings* settings = (Settings*)castToThis;
#endif
SettingsArgvDispatcher* handler = settings->_Find(*argv);
if (!handler)
return B_TRANSLATE("unknown command");
return handler->Handle(argv);
}
/*!
Returns false if argv dispatcher with the same name already
registered
*/
bool
Settings::Add(SettingsArgvDispatcher* setting)
{
// check for uniqueness
if (_Find(setting->Name()))
return false;
if (fCount >= fListSize) {
fListSize += 30;
fList = (SettingsArgvDispatcher **)realloc(fList,
fListSize * sizeof(SettingsArgvDispatcher *));
}
fList[fCount++] = setting;
return true;
}
SettingsArgvDispatcher*
Settings::_Find(const char* name)
{
for (int32 index = 0; index < fCount; index++)
if (strcmp(name, fList[index]->Name()) == 0)
return fList[index];
return 0;
}
void
Settings::TryReadingSettings()
{
BPath prefsPath;
if (find_directory(B_USER_SETTINGS_DIRECTORY, &prefsPath, true) == B_OK) {
prefsPath.Append(fSettingsDir);
BPath path(prefsPath);
path.Append(fFileName);
ArgvParser::EachArgv(path.Path(), Settings::_ParseUserSettings, this);
}
}
void
Settings::SaveSettings(bool onlyIfNonDefault)
{
ASSERT(SettingsHandler());
SettingsHandler()->_SaveCurrentSettings(onlyIfNonDefault);
}
void
Settings::_MakeSettingsDirectory(BDirectory *resultingSettingsDir)
{
BPath path;
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path, true) != B_OK)
return;
// make sure there is a directory
path.Append(fSettingsDir);
mkdir(path.Path(), 0777);
resultingSettingsDir->SetTo(path.Path());
}
void
Settings::_SaveCurrentSettings(bool onlyIfNonDefault)
{
BDirectory settingsDir;
_MakeSettingsDirectory(&settingsDir);
if (settingsDir.InitCheck() != B_OK)
return;
printf("+++++++++++ Settings::_SaveCurrentSettings %s\n", fFileName);
// nuke old settings
BEntry entry(&settingsDir, fFileName);
entry.Remove();
BFile prefs(&entry, O_RDWR | O_CREAT);
if (prefs.InitCheck() != B_OK)
return;
fCurrentSettings = &prefs;
for (int32 index = 0; index < fCount; index++) {
fList[index]->SaveSettings(this, onlyIfNonDefault);
}
fCurrentSettings = 0;
}
void
Settings::Write(const char* format, ...)
{
va_list args;
va_start(args, format);
VSWrite(format, args);
va_end(args);
}
void
Settings::VSWrite(const char* format, va_list arg)
{
char buffer[2048];
vsprintf(buffer, format, arg);
ASSERT(fCurrentSettings && fCurrentSettings->InitCheck() == B_OK);
fCurrentSettings->Write(buffer, strlen(buffer));
}
#ifdef SINGLE_SETTING_FILE
Settings* Settings::settingsHandler = 0;
#endif
-155
View File
@@ -1,155 +0,0 @@
#ifndef SETTINGS_HANDLER_H
#define SETTINGS_HANDLER_H
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <SupportDefs.h>
class BFile;
class BDirectory;
class BRect;
class Settings;
typedef const char* (*ArgvHandler)(int argc, const char *const *argv, void *params);
// return 0 or error string if parsing failed
const int32 kBufferSize = 1024;
class ArgvParser {
public:
static status_t EachArgv(const char* name,
ArgvHandler argvHandlerFunc, void* passThru);
private:
ArgvParser(const char* name);
~ArgvParser();
status_t EachArgvPrivate(const char* name,
ArgvHandler argvHandlerFunc, void* passThru);
char GetCh();
status_t SendArgv(ArgvHandler argvHandlerFunc, void* passThru);
// done with a whole line of argv, send it off and get ready
// to build a new one
void NextArgv();
// done with current string, get ready to start building next
void NextArgvIfNotEmpty();
// as above, don't commint current string if empty
void MakeArgvEmpty();
FILE* fFile;
char* fBuffer;
int32 fPos;
int32 fNumAvail;
int fArgc;
char** fCurrentArgv;
int32 fCurrentArgsPos;
char fCurrentArgs[1024];
bool fSawBackslash;
bool fEatComment;
bool fInDoubleQuote;
bool fInSingleQuote;
int32 fLineNo;
const char* fFileName;
};
class SettingsArgvDispatcher {
// base class for a single setting item
public:
SettingsArgvDispatcher(const char* name);
virtual ~SettingsArgvDispatcher() {};
void SaveSettings(Settings* settings, bool onlyIfNonDefault);
const char* Name() const
{
return fName;
}
virtual const char* Handle(const char* const *argv) = 0;
// override this adding an argv parser that reads in the
// values in argv format for this setting
// return a pointer to an error message or null if parsed OK
bool HandleRectValue(BRect&, const char* const *argv,
bool printError = true);
// static bool HandleColorValue(rgb_color &, const char *const *argv, bool printError = true);
void WriteRectValue(Settings*, BRect);
// void WriteColorValue(BRect);
protected:
virtual void SaveSettingValue(Settings* settings) = 0;
// override this to save the current value of this setting in a
// text format
virtual bool NeedsSaving() const
{
return true;
}
// override to return false if current value is equal to the default
// and does not need saving
private:
const char* fName;
};
class Settings {
public:
Settings(const char* filename, const char* settingsDirName);
~Settings();
void TryReadingSettings();
void SaveSettings(bool onlyIfNonDefault = true);
#ifdef SINGLE_SETTING_FILE
static Settings* SettingsHandler()
{
return settingsHandler;
}
#else
Settings* SettingsHandler()
{
return this;
}
#endif
bool Add(SettingsArgvDispatcher *);
void Write(const char* format, ...);
void VSWrite(const char*, va_list);
#ifdef SINGLE_SETTING_FILE
static Settings* settingsHandler;
#endif
private:
void _MakeSettingsDirectory(BDirectory*);
SettingsArgvDispatcher* _Find(const char*);
static const char* _ParseUserSettings(int, const char *const *argv, void*);
void _SaveCurrentSettings(bool onlyIfNonDefault);
const char* fFileName;
const char* fSettingsDir;
SettingsArgvDispatcher** fList;
int32 fCount;
int32 fListSize;
BFile* fCurrentSettings;
};
#endif // SETTINGS_HANDLER_H
+1
View File
@@ -54,6 +54,7 @@ for architectureObject in [ MultiArchSubDirSetup ] {
RegExp.cpp
RWLocker.cpp
RWLockManager.cpp
SettingsHandler.cpp
ShakeTrackingFilter.cpp
StringForRate.cpp
StringForSize.cpp
@@ -35,8 +35,8 @@ All rights reserved.
#include <Debug.h>
#include <Directory.h>
#include <Entry.h>
#include <FindDirectory.h>
#include <File.h>
#include <FindDirectory.h>
#include <Path.h>
#include <StopWatch.h>
@@ -53,6 +53,10 @@ All rights reserved.
// #pragma mark - ArgvParser
/*! \class ArgvParser
ArgvParser class opens a text file and passes the context in argv
format to a specified handler
*/
ArgvParser::ArgvParser(const char* name)
:
fFile(0),
@@ -95,7 +99,7 @@ ArgvParser::MakeArgvEmpty()
{
// done with current argv, free it up
for (int32 index = 0; index < fArgc; index++)
delete[] fCurrentArgv[index];
delete fCurrentArgv[index];
fArgc = 0;
}
@@ -129,7 +133,7 @@ ArgvParser::NextArgv()
fSawBackslash = false;
}
fCurrentArgs[++fCurrentArgsPos] = '\0';
// terminate current arg pos
// terminate current arg pos
// copy it as a string to the current argv slot
fCurrentArgv[fArgc] = new char [strlen(fCurrentArgs) + 1];
@@ -268,7 +272,7 @@ ArgvParser::EachArgvPrivate(const char* name, ArgvHandler argvHandlerFunc,
SettingsArgvDispatcher::SettingsArgvDispatcher(const char* name)
:
name(name)
fName(name)
{
}
@@ -329,6 +333,10 @@ SettingsArgvDispatcher::WriteRectValue(Settings* setting, BRect rect)
}
/*! \class Settings
this class represents a list of all the settings handlers, reads and
saves the settings file
*/
Settings::Settings(const char* filename, const char* settingsDirName)
:
fFileName(filename),
@@ -366,6 +374,10 @@ Settings::ParseUserSettings(int, const char* const* argv, void* castToThis)
}
/*!
Returns false if argv dispatcher with the same name already
registered
*/
bool
Settings::Add(SettingsArgvDispatcher* setting)
{
@@ -481,8 +493,8 @@ Settings::Write(const char* format, ...)
void
Settings::VSWrite(const char* format, va_list arg)
{
char fBuffer[2048];
vsprintf(fBuffer, format, arg);
char buffer[2048];
vsprintf(buffer, format, arg);
ASSERT(fCurrentSettings && fCurrentSettings->InitCheck() == B_OK);
fCurrentSettings->Write(fBuffer, strlen(fBuffer));
fCurrentSettings->Write(buffer, strlen(buffer));
}
-1
View File
@@ -68,7 +68,6 @@ for architectureObject in [ MultiArchSubDirSetup ] {
RegExp.cpp
SelectionWindow.cpp
Settings.cpp
SettingsHandler.cpp
SettingsViews.cpp
SlowContextPopup.cpp
SlowMenu.cpp