home *** CD-ROM | disk | FTP | other *** search
-
- /* options.c */
-
- #include <stdlib.h>
- #include <stdio.h>
- #include <ctype.h>
- #include <string.h>
-
- #include "options.h"
- #include "various.h"
- #include "debug.h"
-
-
- /* When adding options, there are 5 parts that must be added to:
- * An entry in the `Choices' file.
- * The structure in options.h.
- * Default values in loader.
- * Value reader in loader.
- * Extra line in destructor.
- */
-
-
- static int process_lines(thiniconbar_options *obj,
- FILE *file, bool enabled);
- static bool read_option(thiniconbar_options *obj,
- const char *opt, const char *val);
- char *file_readline(FILE *file);
-
-
- /* Options are loaded to here, in main(). */
- thiniconbar_options *options = 0;
-
- /* Create an options object with default options filled in. Will return 0
- if the structure could not be allocated. */
- thiniconbar_options *thiniconbar_options_create(void)
- {
- thiniconbar_options *obj;
- DEBUGF("Options: creating object\n");
-
- /* Allocate structure. */
- obj = malloc(sizeof(thiniconbar_options));
- if(!obj) return 0;
-
- /* Fill in default values. */
- /* Gaps */
- obj->end_gap = 8;
- obj->between_gap = 0;
- obj->central_gap = 40;
- obj->top_gap = 0;
- obj->sprite_margin = 14;
- obj->text_margin = 8;
- obj->sprite_text_gap = 10;
- obj->icon_h_margins = 10;
- /* Heights */
- obj->icon_height = 100;
- obj->window_height = 100;
- /* Scrolling */
- obj->scroll_type = scroll_type_LINEAR_S;
- obj->scroll_margin = 12;
- obj->scroll_step = 12;
- obj->scroll_speed = 12;
- /* Colours */
- obj->text_colour = 7;
- obj->icon_bg_colour = 1;
- obj->window_bg_colour = 1;
- /* Borders */
- obj->icon_borders = border_type_SLAB_OUT;
- obj->border_size = 4;
- obj->window_border = 0;
- /* Menus */
- obj->menu_y_offset = 12;
- /* Misc */
- obj->small_icons = 0;
- obj->use_task_name = 0;
- obj->text_height = 32;
- obj->font = 0;
- obj->font_size = 0;
- obj->font_width = 0;
- obj->arrangement = arrangement_TEXT_BOTTOM;
- /* Pinboard */
- obj->patch_pinboard = 1;
- obj->pinboard_bg_colour = -1;
-
- return obj;
- }
-
- /* Reads the options from a file to fill out an options object. Returns
- non-zero for failure (ie. file could not be opened). */
- bool thiniconbar_options_from_file(thiniconbar_options *obj,
- const char *filename)
- {
- FILE *file;
- if(!obj) return 1; /* Fail */
- DEBUGF1("Options: opening options file `%s'\n", filename);
-
- /* Open the options file. */
- file = fopen(filename, "r");
- if(!file) {
- DEBUGF("Options: could not open file\n");
- return 1; /* Fail */
- }
- DEBUGF("Options: reading file\n");
-
- if(!process_lines(obj, file, 1))
- { fclose(file); return 1; } /* Fail */
-
- /* Close file and finish. */
- fclose(file);
- DEBUGF("Options: finished reading file\n");
- return 0; /* Success */
- }
-
- /* Processes lines from an option file. Returns when a closing } is
- found. Will return non-zero for success, 0 if malloc failed. */
- static int process_lines(thiniconbar_options *obj, FILE *file, bool enabled)
- {
- /* Read options from the file. */
- /* Each line is of the form: option (whitespace) value */
- while(!feof(file)) {
- char *line = file_readline(file), *c = line, *l = 0;
- char *opt, *val;
- if(!line) return 0; /* malloc failed, so whinge. */
-
- /* Extract option and value from line. */
- while(isspace(*c) && *c) ++c;
-
- /* Skip line if empty or a comment. */
- if(!*c || *c == '#') { free(line); continue; }
- /* Return if this is the end of a group. */
- if(*c == '}') { free(line); return 1; }
- /* If not switched on, ignore the line now. */
- if(!enabled) { free(line); continue; }
-
- opt = c;
- /* Option keyword. */
- while(!isspace(*c) && *c) {
- if(*c == '-') *c = '_';
- ++c;
- }
- if(*c) *c++ = 0;
- while(isspace(*c) && *c) ++c;
- val = c;
- /* Snip any comments and their whitespace, after the value. */
- while(*c) {
- if(isspace(*c)) { l = c; }
- else { if(*c == '#') { *(l ? l : c) = 0; break; } }
- ++c;
- }
-
- /* Is this an option group? */
- if(!strcmp(opt, "group")) {
- const char *name = val;
- bool enable, content;
-
- /* Split value into group name and its state (on or off). */
- char *c = val;
- const char *state = 0;
- /* Look for second arg. */
- while(*c && !isspace(*c)) ++c;
- if(*c) {
- *c++ = 0;
- state = c;
- }
- /* Look for group's opening bracket. */
- while(*c && !isspace(*c)) ++c;
- if(*c) *c++ = 0;
- while(*c && isspace(*c) && *c != '{') ++c;
- content = (*c == '{');
-
- /* Is this group enabled? */
- if(!state) { enable = 0; }
- else if(!strcmp(state, "on")) { enable = 1; }
- else if(!strcmp(state, "off")) { enable = 0; }
- else { enable = atoi(state); }
-
- /* Process group according to whether it is enabled. */
- if(content) {
- DEBUGF2("Options: begin group `%s' (state `%s')\n", name, state);
- if(!process_lines(obj, file, enable))
- { free(line); return 0; } /* Fail */
- DEBUGF2("Options: end group `%s' (state `%s')\n", name, state);
- }
- else {
- DEBUGF2("Options: group `%s' (state `%s') has no content\n",
- name, state);
- }
- free(line);
- continue;
- }
-
- /* Match options. */
- if(read_option(obj, opt, val)) {
- free(line);
- return 0; /* Failure */
- }
- free(line);
- }
- DEBUGF("Options: reached end of file\n");
- return 1; /* Success */
- }
-
- /* Reads options from a command line, filling out the given options object.
- Might return non-zero for malloc failure. This looks at *all* the
- command line parameters you give it (so don't pass the command's
- filename). */
- bool thiniconbar_options_from_cli(thiniconbar_options *obj,
- int argc, char *argv[])
- {
- /* Command line should consist of pairs of the form `--option value'.
- Any parameters not conforming are ignored without error. */
- int i;
- for(i=0; i<(argc-1); ++i) {
- if(argv[i][0] == '-' && argv[i][1] == '-') {
- /* Copy argument so that `-'s can become `_'s. */
- char *opt = my_strdup(argv[i] + 2), *c;
- if(!opt) return 1; /* Failure */
- for(c=opt; *c; ++c) if(*c == '-') *c = '_';
- if(read_option(obj, opt, argv[i+1])) return 1; /* Failure */
- ++i;
- }
- }
- return 0; /* Success */
- }
-
- /* Reads an option. Returns non-zero for a malloc failure. */
- static bool read_option(thiniconbar_options *obj,
- const char *opt, const char *val)
- {
- /* A number of macros are defined here to read each data type for us. */
-
- /* Read an integer. */
- #define READ_INT(option) \
- if(!strcmp(opt, #option)) { \
- obj->option = atoi(val); \
- DEBUGF2("Options: option `%s' (value `%s') read as int\n", opt, val); \
- return 0; \
- }
-
- /* Read a floating point number. */
- #define READ_FLOAT(option) \
- if(!strcmp(opt, #option)) { \
- obj->option = atof(val); \
- DEBUGF2("Options: option `%s' (value `%s') read as " \
- "double\n", opt, val); \
- return 0; \
- }
-
- /* Read a string. */
- /* A string of `-' here means use a null char pointer. */
- #define READ_STRING(option) \
- if(!strcmp(opt, #option)) { \
- if(val[0] == '-' && !val[1]) \
- obj->option = 0; \
- else { \
- obj->option = my_strdup(val); \
- if(!obj->option) return 1; /* Fail */ \
- } \
- DEBUGF2("Options: option `%s' (value `%s') read as " \
- "string\n", opt, val); \
- return 0; \
- }
-
- /* Read an enumeration. */
- /* This may be one string of a set, or the number to use directly. */
- #define BEGIN_ENUM(option) \
- if(!strcmp(opt, #option)) { int *w = &obj->option;
- #define ENUM_VAL(symbol, num) \
- if(!strcmp(val, symbol)) { \
- *w = num; \
- DEBUGF3("Options: option `%s' (value `%s') read as enum, symbol `" \
- symbol "' value " #num " (%i)\n", opt, val, num); \
- return 0; \
- }
- #define END_ENUM \
- *w = atoi(val); \
- DEBUGF2("Options: option `%s' (value `%s') " \
- "unmatched enum, read as int\n", opt, val); \
- return 0; }
-
- /* Read a boolean variable (on, off, 1 or 0). */
- /* Implemented as an enumeration. */
- #define READ_BOOL(option) \
- BEGIN_ENUM(option) \
- ENUM_VAL("off", 0) \
- ENUM_VAL("on", 1) \
- END_ENUM;
-
- /* Read a colour. Only does Wimp colours at the moment. */
- /* You can use a colour name or a number. */
- #define READ_COLOUR(option) \
- BEGIN_ENUM(option) \
- ENUM_VAL("white", 0) \
- ENUM_VAL("grey-1", 1) \
- ENUM_VAL("grey-2", 2) \
- ENUM_VAL("grey-3", 3) \
- ENUM_VAL("grey-4", 4) \
- ENUM_VAL("grey-5", 5) \
- ENUM_VAL("grey-6", 6) \
- ENUM_VAL("black", 7) \
- ENUM_VAL("dark-blue", 8) \
- ENUM_VAL("yellow", 9) \
- ENUM_VAL("light-green", 10) \
- ENUM_VAL("red", 11) \
- ENUM_VAL("cream", 12) \
- ENUM_VAL("dark-green", 13) \
- ENUM_VAL("orange", 14) \
- ENUM_VAL("light-blue", 15) \
- ENUM_VAL("none", -1) \
- END_ENUM;
-
- /* Gaps */
- READ_INT(end_gap);
- READ_INT(between_gap);
- READ_INT(central_gap);
- READ_INT(top_gap);
- READ_INT(sprite_margin);
- READ_INT(text_margin);
- READ_INT(sprite_text_gap);
- READ_INT(icon_h_margins);
- /* Heights */
- READ_INT(icon_height);
- READ_INT(window_height);
- /* Scrolling */
- BEGIN_ENUM(scroll_type)
- ENUM_VAL("none", scroll_type_NONE)
- ENUM_VAL("linear", scroll_type_LINEAR)
- ENUM_VAL("linear-s", scroll_type_LINEAR_S)
- ENUM_VAL("prop", scroll_type_PROP)
- ENUM_VAL("move", scroll_type_MOVE)
- END_ENUM;
- READ_INT(scroll_margin);
- READ_INT(scroll_step);
- READ_INT(scroll_speed);
- /* Colours */
- READ_COLOUR(text_colour);
- READ_COLOUR(icon_bg_colour);
- READ_COLOUR(window_bg_colour);
- /* Borders */
- BEGIN_ENUM(icon_borders)
- ENUM_VAL("none", border_type_NONE)
- ENUM_VAL("plain", border_type_PLAIN)
- ENUM_VAL("slab-out", border_type_SLAB_OUT)
- ENUM_VAL("slab-in", border_type_SLAB_IN)
- END_ENUM;
- READ_INT(border_size);
- READ_BOOL(window_border);
- /* Menus */
- READ_INT(menu_y_offset);
- /* Misc */
- READ_BOOL(small_icons);
- READ_BOOL(use_task_name);
- READ_INT(text_height);
- READ_STRING(font);
- READ_FLOAT(font_size);
- READ_FLOAT(font_width);
- BEGIN_ENUM(arrangement)
- ENUM_VAL("text-bottom", arrangement_TEXT_BOTTOM);
- ENUM_VAL("text-right", arrangement_TEXT_RIGHT);
- END_ENUM;
- /* Pinboard */
- READ_BOOL(patch_pinboard);
- READ_COLOUR(pinboard_bg_colour);
-
- /* Don't need the macros any more. */
- #undef READ_INT
- #undef READ_FLOAT
- #undef READ_STRING
- #undef BEGIN_ENUM
- #undef ENUM_VAL
- #undef END_ENUM
- #undef READ_BOOL
-
- /* If not matched, make a note on debug. */
- DEBUGF2("Options: option `%s' not recognised (value `%s')\n", opt, val);
- return 0; /* Success */
- }
-
- /* Reads a line from a file. May return 0 if malloc failed at some point.
- Free the returned string yourself. */
- char *file_readline(FILE *file)
- {
- int ch, len = 40;
- char *line = malloc(len + 1), *c = line;
- if(!line) return 0;
- do {
- ch = fgetc(file);
- if(ch == EOF || ch == '\n') ch = 0;
- /* Extend buffer if necessary. */
- if((c - line) >= len) {
- char *old_line = line;
- len += 30;
- line = realloc(line, len + 1);
- if(!line) return 0;
- c = c - old_line + line;
- }
- *c++ = ch;
- } while(ch);
- return line;
- }
-
- /* Destroys an options object, freeing data it owns. */
- void thiniconbar_options_destroy(thiniconbar_options *obj)
- {
- if(!obj) return;
-
- /* Free strings owned. */
- free(obj->font);
-
- free(obj);
- }
-