#include <config.h>
#include <glib.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <glib/gstdio.h>
#include "orbit-options.h"
#ifdef G_OS_WIN32
extern const gchar *ORBit_win32_system_rcfile;
#undef ORBIT_SYSTEM_RCFILE
#define ORBIT_SYSTEM_RCFILE ORBit_win32_system_rcfile
#endif
#undef DEBUG
/*
* ORBit_option_set:
* @option: an #ORBit_option describing the option.
* @val: a pointer to the option value string.
*
* Sets @option's arg member member to the appropiate form
* of @val.
*
* If the option is an string option the string will be
* duplicated, if the option if a 'none' option it will
* be treated as a boolean option of value TRUE.
*/
static void
ORBit_option_set (const ORBit_option *option,
const gchar *val)
{
g_assert (option != NULL);
if (!option->arg)
return;
#ifdef DEBUG
fprintf (stderr, "Setting option %s to %s\n", option->name,
val ? val : "(none)" );
#endif
switch (option->type) {
case ORBIT_OPTION_NONE:
*(gboolean *)option->arg = TRUE;
break;
case ORBIT_OPTION_BOOLEAN:
*(gboolean *)option->arg = (gboolean)atoi (val);
break;
case ORBIT_OPTION_INT:
*(gint *)option->arg = atoi (val);
break;
case ORBIT_OPTION_ULONG:
*(guint *)option->arg = strtoul(val, (char **)NULL, 10);
break;
case ORBIT_OPTION_STRING: {
gchar **str_arg = (char **) option->arg;
if (*str_arg)
g_free (*str_arg);
*str_arg = g_strdup (val);
break;
}
case ORBIT_OPTION_KEY_VALUE: {
GSList **list = (GSList**) option->arg;
/* split string into tuple */
gchar **str_vec = g_strsplit (val, "=", 2);
if (!str_vec || !str_vec[0] || !str_vec[1])
{
g_warning ("Option %s requieres key=value pair: %s", option->name, val);
if (str_vec) g_strfreev (str_vec);
break;
}
g_assert (str_vec[0] != NULL);
g_assert (str_vec[1] != NULL);
{
ORBit_OptionKeyValue *tuple
= g_new0 (ORBit_OptionKeyValue, 1);
tuple->key = g_strdup (str_vec[0]);
tuple->value = g_strdup (str_vec[1]);
*list = g_slist_append (*list, tuple);
}
g_strfreev (str_vec);
break;
}
default:
g_assert_not_reached ();
break;
}
}
/*
* ORBit_option_rc_parse:
* @rcfile: the path of the orbitrc file.
* @option_list: the #ORBit_options to parse from the file.
*
* Parses @rcfile for any of the options in @option_list. The syntax
* of rcfile is simple : 'option=value'.
*
* Note: leading or trailing whitespace is allowed for both the option
* and its value.
*/
static void
ORBit_option_rc_parse (const gchar *rcfile,
const ORBit_option *option_list)
{
gchar line [1024];
FILE *fh;
fh = g_fopen (rcfile, "r");
if (!fh)
return;
#ifdef DEBUG
fprintf (stderr, "Parsing file %s for options\n", rcfile);
#endif
while (fgets (line, sizeof (line), fh)) {
const ORBit_option *option = NULL;
gchar **strvec;
gchar *key;
gchar *value;
if (line [0] == '#')
continue;
strvec = g_strsplit (line, "=", 3);
if (!strvec || !strvec[0] || !strvec[1])
continue;
key = g_strchomp (g_strchug (strvec[0]));
for (option = option_list; option->name; option++)
if (!strcmp (key, option->name))
break;
if (!option->name) {
option = NULL;
continue;
}
value = g_strchomp (g_strchug (strvec[1]));
ORBit_option_set (option, value);
g_strfreev (strvec);
}
fclose (fh);
}
/*
* ORBit_option_command_line_parse:
* @argc: main's @argc param.
* @argv: main's @argv param.
* @option_list: list of #ORBit_options to parse from @argv.
*
* Parse @argv looking for options contained in @option_list and
* setting values as appropriate. Also strip these options from
* @argv and adjust @argc.
*/
static void
ORBit_option_command_line_parse (int *argc,
char **argv,
const ORBit_option *option_list)
{
gboolean *erase;
gint i, j, numargs;
gchar name [1024];
gchar *tmpstr;
const ORBit_option *option = NULL;
#ifdef DEBUG
fprintf (stderr, "Parsing command line for options\n");
#endif
if (!argc || !argv)
return;
erase = g_new0 (gboolean, *argc);
for (i = 1, numargs = *argc; i < *argc; i++) {
if (argv [i][0] != '-') {
if (!option)
continue;
erase [i] = TRUE;
numargs--;
if (!option->arg) {
option = NULL;
continue;
}
ORBit_option_set (option, argv [i]);
option = NULL;
continue;
} else if (option && option->type != ORBIT_OPTION_NONE)
g_warning ("Option %s requires an argument\n",
option->name);
tmpstr = argv [i];
while (*tmpstr && *tmpstr == '-')
tmpstr++;
strncpy (name, tmpstr, sizeof (name) - 1);
name [sizeof (name) - 1] = '\0';
tmpstr = strchr (name, '=');
if (tmpstr)
*tmpstr++ = '\0';
for (option = option_list; option->name; option++)
if (!strcmp (name, option->name))
break;
if (!option->name) {
option = NULL;
continue;
}
erase [i] = TRUE;
numargs--;
if (option->type != ORBIT_OPTION_NONE && tmpstr) {
ORBit_option_set (option, tmpstr);
option = NULL;
}
}
/* erase all consumed arguments from @argv list */
for (i = j = 1; i < *argc; i++) {
if (erase [i])
continue;
if (j < numargs)
argv [j++] = argv [i];
else
argv [j++] = "";
}
*argc = numargs;
g_free (erase);
}
static gboolean no_sysrc = FALSE;
static gboolean no_userrc = FALSE;
static ORBit_option orbit_sysrc_options [] = {
{"ORBNoSystemRC", ORBIT_OPTION_NONE, &no_sysrc},
{"ORBNoUserRC", ORBIT_OPTION_NONE, &no_userrc},
{NULL, 0, NULL}
};
/*
* ORBit_option_parse:
* @argc: main's @argc param.
* @argv: main's @argv param.
* @option_list: list of #ORBit_options.
*
* First parses the command line - @argv - to check for orbitrc related
* options, then parses the relevant orbitrc files and finally parse the
* command line for all other ORB related options.
*
* All ORBit options are stripped from @argv and @argc is adjusted.
*
* Note: Command line arguments override orbitrc options and ~/.orbitrc
* overrides ${sysconfdir}/orbitrc.
*/
void
ORBit_option_parse (int *argc,
char **argv,
const ORBit_option *option_list)
{
ORBit_option_command_line_parse (argc, argv, orbit_sysrc_options);
if (!no_sysrc)
ORBit_option_rc_parse (ORBIT_SYSTEM_RCFILE, option_list);
if (!no_userrc) {
gchar *rcfile;
const gchar *home = g_get_home_dir ();
if (home != NULL) {
rcfile = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "%s", home, ORBIT_USER_RCFILE);
ORBit_option_rc_parse (rcfile, option_list);
g_free (rcfile);
}
}
ORBit_option_command_line_parse (argc, argv, option_list);
}
syntax highlighted by Code2HTML, v. 0.9.1