This is resources.c in view mode; [Download] [Up]
/*
* resources.c - Resource (setting) handling for VICE.
*
* Written by
* Ettore Perazzoli (ettore@comm2000.it)
*
* This file is part of VICE, the Versatile Commodore Emulator.
* See README for copyright notice.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA.
*
*/
/* This implements simple facilities to handle the resources and command-line
options. All the resources for the emulators can be stored in a single
file, and they are separated by an `emulator identifier', i.e. the machine
name between brackets (e.g. ``[C64]''). All the resources are stored in
the form ``ResourceName=ResourceValue'', and separated by newline
characters. Leading and trailing spaces are removed from the
ResourceValue unless it is put between quotes ("). */
#include "vice.h"
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#ifdef __MSDOS__
#include <dir.h>
#endif
#include "resources.h"
#include "utils.h"
#include "ui.h"
static int num_resources, num_allocated_resources;
static resource_t *resources;
static const char *machine_id;
/* FIXME: I don't like this to be here. */
#ifdef __MSDOS__
#define RESOURCE_FILE_NAME "VICERC"
#else
#define RESOURCE_FILE_NAME ".vicerc"
#endif
#if 0
#define RWARNING(s) printf s
#else
#define RWARNING(s)
#endif
/* ------------------------------------------------------------------------- */
/* FIXME: We might want to use a hash table instead of a linear search some
day. */
int resources_register(const resource_t *r)
{
const resource_t *sp;
resource_t *dp;
sp = r;
dp = resources + num_resources;
while (sp->name != NULL) {
if (num_allocated_resources <= num_resources) {
num_allocated_resources *= 2;
resources = xrealloc(resources,
num_allocated_resources * sizeof(resource_t));
dp = resources + num_resources;
}
dp->name = sp->name;
dp->type = sp->type;
dp->factory_value = sp->factory_value;
dp->value_ptr = sp->value_ptr;
dp->set_func = sp->set_func;
num_resources++, sp++, dp++;
}
return 0;
}
static resource_t *lookup(const char *name)
{
int i;
for (i = 0; i < num_resources; i++)
if (strcasecmp(resources[i].name, name) == 0)
return resources + i;
return NULL;
}
/* ------------------------------------------------------------------------- */
int resources_init(const char *machine)
{
machine_id = stralloc(machine);
num_allocated_resources = 100;
num_resources = 0;
resources = (resource_t *) xmalloc(num_allocated_resources
* sizeof(resource_t));
return 0;
}
int resources_set_value(const char *name, resource_value_t value)
{
resource_t *r = lookup(name);
if (r == NULL) {
RWARNING(("Warning: Trying to assign value to unknown resource `%s'\n",
name));
return -1;
}
return r->set_func(value);
}
int resources_set_value_string(const char *name, const char *value)
{
resource_t *r = lookup(name);
if (r == NULL) {
RWARNING(("Warning: Trying to assign value to unknown resource `%s'\n",
name));
return -1;
}
switch (r->type) {
case RES_INTEGER:
return r->set_func((resource_value_t) atoi(value));
case RES_STRING:
return r->set_func((resource_value_t) value);
default:
fprintf(stderr, "Warning: unknown resource type for `%s'\n",
name);
return -1;
}
return -1;
}
int resources_get_value(const char *name, resource_value_t *value_return)
{
resource_t *r = lookup(name);
if (r == NULL) {
RWARNING(("Warning: Trying to read value from unknown resource `%s'\n",
name));
return -1;
}
switch (r->type) {
case RES_INTEGER:
*(int *)value_return = *(int *)r->value_ptr;
break;
case RES_STRING:
*(char **)value_return = *(char **)r->value_ptr;
break;
default:
fprintf(stderr, "Warning: unknown resource type for `%s'\n",
name);
return -1;
}
return 0;
}
void resources_set_defaults(void)
{
int i;
for (i = 0; i < num_resources; i++)
resources[i].set_func(resources[i].factory_value);
ui_update_menus();
}
int resources_toggle(const char *name, resource_value_t *new_value_return)
{
resource_t *r = lookup(name);
int value;
if (r == NULL) {
RWARNING((stderr, "Warning: Trying to toggle boolean value of unknown resource `%s'\n",
name));
return -1;
}
value = !(*(int *)r->value_ptr);
if (new_value_return != NULL)
*(int *)new_value_return = value;
return r->set_func((resource_value_t) value);
}
/* ------------------------------------------------------------------------- */
#ifndef __MSDOS__
/* Return a malloced string with the name of the backup file corresponding to
`fname'. */
static char *make_backup_file_name(const char *fname)
{
return concat(fname, "~", NULL);
}
#else /* __MSDOS__ */
/* Return a malloced string with the name of the backup file corresponding to
`fname'. FIXME: Only works with 8+3 names. */
static char *make_backup_file_name(const char *fname)
{
static char backup_name[MAXPATH];
char drive[MAXDRIVE];
char dir[MAXDIR];
char name[MAXFILE];
char ext[MAXEXT];
fnsplit(fname, drive, dir, name, ext);
fnmerge(backup_name, drive, dir, name, "BAK");
return stralloc(backup_name);
}
#endif /* __MSDOS__ */
/* Check whether `buf' is the emulator ID for the machine we are emulating. */
static int check_emu_id(const char *buf)
{
int machine_id_len, buf_len;
buf_len = strlen(buf);
if (*buf != '[' || *(buf + buf_len - 1) != ']')
return 0;
if (machine_id == NULL)
return 1;
machine_id_len = strlen(machine_id);
if (machine_id_len != buf_len - 2)
return 0;
if (strncmp(buf + 1, machine_id, machine_id_len) == 0)
return 1;
else
return 0;
}
/* Return a malloced string containing the name of the default user-specific
resource file. Warning: assumes `boot_path' does not change (it should be
always so). */
static const char *default_resource_file(void)
{
static char *fname = NULL;
if (fname == NULL) {
#if defined __MSDOS__ || defined WIN32
/* On MS-DOS, always boot from the directory in which the binary is
stored. */
fname = concat(boot_path, "\\", RESOURCE_FILE_NAME, NULL);
#else
fname = concat(getenv("HOME"), "/", RESOURCE_FILE_NAME, NULL);
#endif
}
return (const char *)fname;
}
/* ------------------------------------------------------------------------- */
/* Read one resource line from the file descriptor `f'. Return 1 on success,
-1 on failure, 0 on EOF or end of emulator section. */
static int read_resource_item(FILE *f)
{
char buf[1024];
char *arg_ptr;
int line_len, resname_len, arg_len;
resource_t *r;
line_len = get_line(buf, 1024, f);
if (line_len < 0)
return 0;
/* Ignore empty lines. */
if (*buf == '\0')
return 1;
if (*buf == '[') {
/* End of emulator-specific section. */
return 0;
}
arg_ptr = strchr(buf, '=');
if (!arg_ptr)
return -1;
resname_len = arg_ptr - buf;
arg_ptr++;
arg_len = strlen(arg_ptr);
/* If the value is between quotes, remove them. */
if (*arg_ptr == '"' && *(arg_ptr + arg_len - 1) == '"') {
*(arg_ptr + arg_len - 1) = '\0';
arg_ptr++;
}
*(buf + resname_len) = '\0';
{
int result;
r = lookup(buf);
if (r == NULL) {
fprintf(stderr, "Unknown resource `%s'.\n", buf);
return -1;
}
switch (r->type) {
case RES_INTEGER:
result = r->set_func((resource_value_t) atoi(arg_ptr));
break;
case RES_STRING:
result = r->set_func((resource_value_t) arg_ptr);
break;
default:
fprintf(stderr, "Warning: Unknown resource type for `%s'.\n",
r->name);
result = -1;
}
if (result < 0) {
RWARNING((stderr, "Warning: Cannot assign value to resource `%s'.\n",
r->name));
return -1;
}
return 1;
}
}
/* Load the resources from file `fname'. If `fname' is NULL, load them from
the default resource file. */
int resources_load(const char *fname)
{
FILE *f;
int retval;
int line_num;
int err = 0;
if (fname == NULL)
fname = default_resource_file();
#ifdef __MSDOS__
f = fopen(fname, "rt");
#else
f = fopen(fname, "r");
#endif
if (f == NULL) {
/*perror(fname);*/
return RESERR_FILE_NOT_FOUND;
}
printf("Reading configuration file `%s'.\n", fname);
/* Find the start of the configuration section for this emulator. */
for (line_num = 1; ; line_num++) {
char buf[1024];
if (get_line(buf, 1024, f) < 0) {
fclose(f);
return RESERR_READ_ERROR;
}
if (check_emu_id(buf)) {
line_num++;
break;
}
}
do {
retval = read_resource_item(f);
if (retval == -1) {
fprintf(stderr, "%s: Invalid resource specification at line %d.\n",
fname, line_num);
err = 1;
}
line_num++;
} while (retval != 0);
fclose(f);
/* Update the values in the UI menus. */
ui_update_menus();
return err ? RESERR_FILE_INVALID : 0;
}
/* Write the resource specification for resource number `num' to file
descriptor `f'. */
static void write_resource_item(FILE *f, int num)
{
resource_value_t v;
fprintf(f, "%s=", resources[num].name);
switch (resources[num].type) {
case RES_INTEGER:
v = (resource_value_t)*(int *)resources[num].value_ptr;
fprintf(f, "%d", (int)v);
break;
case RES_STRING:
v = *resources[num].value_ptr;
if ((char *)v != NULL)
fprintf(f, "\"%s\"", (char *)v);
break;
default:
fprintf(stderr, "Warning: Unknown value type for resource `%s'.\n",
resources[num].name);
}
fputc('\n', f);
}
/* Save all the resources into file `fname'. If `fname' is NULL, save them
in the default resource file. Writing the resources does not destroy the
resources for the other emulators. */
int resources_save(const char *fname)
{
char *backup_name;
FILE *in_file, *out_file;
int have_old;
int i;
if (fname == NULL)
fname = default_resource_file();
/* Make a backup copy of the existing configuration file. */
backup_name = make_backup_file_name(fname);
if (rename(fname, backup_name) == 0)
have_old = 1;
else
have_old = 0;
printf("Writing configuration file `%s'.\n", fname);
#ifdef __MSDOS__
out_file = fopen(fname, "wt");
#else
out_file = fopen(fname, "w");
#endif
if (!out_file) {
perror(fname);
free (backup_name);
return RESERR_CANNOT_CREATE_FILE;
}
if (have_old) {
#ifdef __MSDOS__
in_file = fopen(backup_name, "rt");
#else
in_file = fopen(backup_name, "r");
#endif
if (!in_file) {
fclose(out_file);
perror(backup_name);
free(backup_name);
return RESERR_READ_ERROR;
}
/* Copy the configuration for the other emulators. */
while (1) {
char buf[1024];
if (get_line(buf, 1024, in_file) < 0)
break;
if (check_emu_id(buf))
break;
fprintf(out_file, "%s\n", buf);
}
} else
in_file = NULL;
/* Write our current configuration. */
fprintf(out_file,"[%s]\n", machine_id);
for (i = 0; i < num_resources; i++)
write_resource_item(out_file, i);
if (have_old) {
char buf[1024];
/* Skip the old configuration for this emulator. */
while (1) {
if (get_line(buf, 1024, in_file) < 0)
break;
/* Check if another emulation section starts. */
if (*buf == '[') {
fprintf(out_file, "%s\n", buf);
break;
}
}
if (!feof(in_file)) {
/* Copy the configuration for the other emulators. */
while (get_line(buf, 1024, in_file) >= 0)
fprintf(out_file, "%s\n", buf);
}
}
if (in_file)
fclose(in_file);
fclose(out_file);
free(backup_name);
return 0;
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.