/*
* Copyright (c) 2002-2007 Hypertriton, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Global configuration object. Used for Agar-related settings, but
* applications are free to insert additional properties into the
* object.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#if defined(HAVE_GETPWUID) && defined(HAVE_GETUID)
#include
#endif
/* XXX XXX move to agar-gui */
int agKbdDelay = 250; /* Key repeat delay */
int agKbdRepeat = 35; /* Key repeat interval */
int agMouseDblclickDelay = 250; /* Mouse double-click delay */
int agMouseSpinDelay = 250; /* Spinbutton repeat delay */
int agMouseSpinIval = 50; /* Spinbutton repeat interval */
int agTextComposition = 1; /* Built-in input composition */
int agTextBidi = 0; /* Bidirectionnal text display */
int agTextAntialiasing = 1; /* Use font antialiasing */
int agTextTabWidth = 40; /* Tab width (px) */
int agTextBlinkRate = 250; /* Cursor blink rate (ms) */
int agTextSymbols = 1; /* Process special symbols in text */
int agPageIncrement = 4; /* Pgup/Pgdn scrolling increment */
int agIdleThresh = 20; /* Idling threshold */
int agScreenshotQuality = 100; /* JPEG quality in % */
int agMsgDelay = 500; /* Display duration of infoboxes (ms) */
int
AG_CreateDataDir(void)
{
char dataDir[AG_PATHNAME_MAX];
char tmpDir[AG_PATHNAME_MAX];
AG_CopyCfgString("save-path", dataDir, sizeof(dataDir));
AG_CopyCfgString("tmp-path", tmpDir, sizeof(tmpDir));
if (AG_FileExists(dataDir) == 0 && AG_MkDir(dataDir) != 0)
return (-1);
if (AG_FileExists(tmpDir) == 0 && AG_MkDir(tmpDir) != 0)
return (-1);
return (0);
}
int
AG_ConfigSave(void)
{
if (AG_CreateDataDir() == -1 ||
AG_ObjectSave(agConfig) == -1) {
return (-1);
}
return (0);
}
int
AG_ConfigLoad(void)
{
return AG_ObjectLoad(agConfig);
}
int
AG_ConfigInit(AG_Config *cfg, Uint flags)
{
char udatadir[AG_PATHNAME_MAX];
#if defined(HAVE_GETPWUID) && defined(HAVE_GETUID)
struct passwd *pwd = getpwuid(getuid());
#endif
AG_ObjectInit(cfg, &agConfigClass);
AG_ObjectSetName(cfg, "config");
OBJECT(cfg)->flags |= AG_OBJECT_RELOAD_PROPS|AG_OBJECT_RESIDENT;
OBJECT(cfg)->save_pfx = NULL;
AG_SetInt(cfg, "initial-run", 1);
AG_SetInt(cfg, "no-confirm-quit", 0);
/* XXX XXX move to agar-gui */
AG_SetInt(cfg, "view.full-screen", 0);
AG_SetInt(cfg, "view.async-blits", 0);
AG_SetInt(cfg, "view.opengl", 0);
AG_SetUint16(cfg, "view.w", 800);
AG_SetUint16(cfg, "view.h", 600);
AG_SetUint16(cfg, "view.min-w", 16);
AG_SetUint16(cfg, "view.min-h", 16);
AG_SetUint8(cfg, "view.depth", 32);
AG_SetUint(cfg, "view.nominal-fps", 40);
AG_SetInt(cfg, "input.joysticks", 1);
AG_SetInt(cfg, "input.composition", 1);
/* Set the save directory path and create it as needed. */
#if defined(HAVE_GETPWUID) && defined(HAVE_GETUID)
Strlcpy(udatadir, pwd->pw_dir, sizeof(udatadir));
Strlcat(udatadir, AG_PATHSEP, sizeof(udatadir));
Strlcat(udatadir, ".", sizeof(udatadir));
Strlcat(udatadir, agProgName, sizeof(udatadir));
AG_SetString(cfg, "home", pwd->pw_dir);
#else
udatadir[0] = '.';
Strlcpy(&udatadir[1], agProgName, sizeof(udatadir)-1);
AG_SetString(cfg, "home", ".");
#endif
AG_SetString(cfg, "save-path", udatadir);
AG_PrtString(cfg, "tmp-path", "%s/tmp", udatadir);
#if defined(_WIN32)
AG_SetString(cfg, "den-path", ".");
AG_PrtString(cfg, "load-path", "%s:.", udatadir);
#else
AG_SetString(cfg, "den-path", SHAREDIR);
AG_PrtString(cfg, "load-path", "%s:%s", udatadir, SHAREDIR);
#endif
if (flags & AG_CREATE_DATADIR) {
if (AG_CreateDataDir() == -1)
return (-1);
}
return (0);
}
static int
Load(void *p, AG_DataSource *ds, const AG_Version *ver)
{
#ifdef AG_DEBUG
agDebugLvl = AG_ReadUint8(ds);
#else
(void)AG_ReadUint8(ds);
#endif
if (ver->minor < 2) { (void)AG_ReadUint8(ds); } /* agServerMode */
agIdleThresh = (int)AG_ReadUint8(ds);
if (ver->minor >= 3) { (void)AG_ReadUint8(ds); } /* agWindowAnySize */
if (ver->minor >= 4) { agMsgDelay = (int)AG_ReadUint32(ds); }
agTextComposition = AG_ReadUint8(ds);
agTextBidi = AG_ReadUint8(ds);
(void)AG_ReadUint8(ds); /* agKbdUnicode */
agKbdDelay = (int)AG_ReadUint32(ds);
agKbdRepeat = (int)AG_ReadUint32(ds);
agMouseDblclickDelay = (int)AG_ReadUint32(ds);
agMouseSpinDelay = (int)AG_ReadUint16(ds);
agMouseSpinIval = (int)AG_ReadUint16(ds);
agScreenshotQuality = (int)AG_ReadUint8(ds);
agTextTabWidth = (int)AG_ReadUint16(ds);
if (ver->minor >= 1) { agTextAntialiasing = AG_ReadUint8(ds); }
agRcsMode = (int)AG_ReadUint8(ds);
AG_CopyString(agRcsHostname, ds, sizeof(agRcsHostname));
agRcsPort = (Uint)AG_ReadUint16(ds);
AG_CopyString(agRcsUsername, ds, sizeof(agRcsUsername));
AG_CopyString(agRcsPassword, ds, sizeof(agRcsPassword));
return (0);
}
static int
Save(void *obj, AG_DataSource *ds)
{
AG_Config *cfg = obj;
AG_SetInt(cfg, "initial-run", 0);
#ifdef AG_DEBUG
AG_WriteUint8(ds, (Uint8)agDebugLvl);
#else
AG_WriteUint8(ds, 0);
#endif
AG_WriteUint8(ds, (Uint8)agIdleThresh);
AG_WriteUint8(ds, 0); /* agWindowAnySize */
AG_WriteUint32(ds, (Uint32)agMsgDelay);
AG_WriteUint8(ds, (Uint8)agTextComposition);
AG_WriteUint8(ds, (Uint8)agTextBidi);
AG_WriteUint8(ds, 0); /* agKbdUnicode */
AG_WriteUint32(ds, (Uint32)agKbdDelay);
AG_WriteUint32(ds, (Uint32)agKbdRepeat);
AG_WriteUint32(ds, (Uint32)agMouseDblclickDelay);
AG_WriteUint16(ds, (Uint16)agMouseSpinDelay);
AG_WriteUint16(ds, (Uint16)agMouseSpinIval);
AG_WriteUint8(ds, (Uint8)agScreenshotQuality);
AG_WriteUint16(ds, (Uint16)agTextTabWidth);
AG_WriteUint8(ds, (Uint8)agTextAntialiasing);
AG_WriteUint8(ds, (Uint8)agRcsMode);
AG_WriteString(ds, agRcsHostname);
AG_WriteUint16(ds, (Uint16)agRcsPort);
AG_WriteString(ds, agRcsUsername);
AG_WriteString(ds, agRcsPassword);
return (0);
}
/* Copy the full pathname of a data file to a sized buffer. */
int
AG_ConfigFile(const char *path_key, const char *name, const char *ext,
char *path, size_t path_len)
{
char file[AG_PATHNAME_MAX];
char *dir, *pathp = path;
int rv;
AG_GetString(agConfig, path_key, path, path_len);
for (dir = Strsep(&pathp, ":");
dir != NULL;
dir = Strsep(&pathp, ":")) {
Strlcpy(file, dir, sizeof(file));
if (name[0] != AG_PATHSEPCHAR) {
Strlcat(file, AG_PATHSEP, sizeof(file));
}
Strlcat(file, name, sizeof(file));
if (ext != NULL) {
Strlcat(file, ".", sizeof(file));
Strlcat(file, ext, sizeof(file));
}
if ((rv = AG_FileExists(file)) == 1) {
if (Strlcpy(path, file, path_len) >= path_len) {
AG_SetError(_("The search path is too big."));
return (-1);
}
return (0);
} else if (rv == -1) {
AG_SetError("%s: %s", file, AG_GetError());
return (-1);
}
}
AG_GetString(agConfig, path_key, path, path_len);
AG_SetError(_("Cannot find %s.%s (in <%s>:%s)."), name,
(ext != NULL) ? ext : "", path_key, path);
return (-1);
}
void
AG_SetCfgString(const char *key, const char *fmt, ...)
{
va_list ap;
char *s;
va_start(ap, fmt);
Vasprintf(&s, fmt, ap);
va_end(ap);
(void)AG_SetProp(agConfig, key, AG_PROP_STRING, s);
}
AG_ObjectClass agConfigClass = {
"Agar(Config)",
sizeof(AG_Config),
{ 9, 4 },
NULL,
NULL,
NULL,
Load,
Save,
NULL
};