home *** CD-ROM | disk | FTP | other *** search
/ ARM Club 3 / TheARMClub_PDCD3.iso / programs / desktop / newbar / Source / NewBar / c / options < prev    next >
Text File  |  1998-08-08  |  11KB  |  411 lines

  1.  
  2. /* options.c */
  3.  
  4. #include <stdlib.h>
  5. #include <stdio.h>
  6. #include <ctype.h>
  7. #include <string.h>
  8.  
  9. #include "options.h"
  10. #include "various.h"
  11. #include "debug.h"
  12.  
  13.  
  14. /* When adding options, there are 5 parts that must be added to:
  15.     * An entry in the `Choices' file.
  16.     * The structure in options.h.
  17.     * Default values in loader.
  18.     * Value reader in loader.
  19.     * Extra line in destructor.
  20. */
  21.  
  22.  
  23. static int process_lines(thiniconbar_options *obj,
  24.     FILE *file, bool enabled);
  25. static bool read_option(thiniconbar_options *obj,
  26.     const char *opt, const char *val);
  27. char *file_readline(FILE *file);
  28.  
  29.  
  30. /* Options are loaded to here, in main(). */
  31. thiniconbar_options *options = 0;
  32.  
  33. /* Create an options object with default options filled in.  Will return 0
  34.    if the structure could not be allocated. */
  35. thiniconbar_options *thiniconbar_options_create(void)
  36. {
  37.   thiniconbar_options *obj;
  38.   DEBUGF("Options: creating object\n");
  39.  
  40.   /* Allocate structure. */
  41.   obj = malloc(sizeof(thiniconbar_options));
  42.   if(!obj) return 0;
  43.  
  44.   /* Fill in default values. */
  45.   /* Gaps */
  46.     obj->end_gap = 8;
  47.     obj->between_gap = 0;
  48.     obj->central_gap = 40;
  49.     obj->top_gap = 0;
  50.     obj->sprite_margin = 14;
  51.     obj->text_margin = 8;
  52.     obj->sprite_text_gap = 10;
  53.     obj->icon_h_margins = 10;
  54.   /* Heights */
  55.     obj->icon_height = 100;
  56.     obj->window_height = 100;
  57.   /* Scrolling */
  58.     obj->scroll_type = scroll_type_LINEAR_S;
  59.     obj->scroll_margin = 12;
  60.     obj->scroll_step = 12;
  61.     obj->scroll_speed = 12;
  62.   /* Colours */
  63.     obj->text_colour = 7;
  64.     obj->icon_bg_colour = 1;
  65.     obj->window_bg_colour = 1;
  66.   /* Borders */
  67.     obj->icon_borders = border_type_SLAB_OUT;
  68.     obj->border_size = 4;
  69.     obj->window_border = 0;
  70.   /* Menus */
  71.     obj->menu_y_offset = 12;
  72.   /* Misc */
  73.     obj->small_icons = 0;
  74.     obj->use_task_name = 0;
  75.     obj->text_height = 32;
  76.     obj->font = 0;
  77.     obj->font_size = 0;
  78.     obj->font_width = 0;
  79.     obj->arrangement = arrangement_TEXT_BOTTOM;
  80.   /* Pinboard */
  81.     obj->patch_pinboard = 1;
  82.     obj->pinboard_bg_colour = -1;
  83.  
  84.   return obj;
  85. }
  86.  
  87. /* Reads the options from a file to fill out an options object.  Returns
  88.    non-zero for failure (ie. file could not be opened). */
  89. bool thiniconbar_options_from_file(thiniconbar_options *obj,
  90.     const char *filename)
  91. {
  92.   FILE *file;
  93.   if(!obj) return 1; /* Fail */
  94.   DEBUGF1("Options: opening options file `%s'\n", filename);
  95.  
  96.   /* Open the options file. */
  97.   file = fopen(filename, "r");
  98.   if(!file) {
  99.     DEBUGF("Options: could not open file\n");
  100.     return 1; /* Fail */
  101.   }
  102.   DEBUGF("Options: reading file\n");
  103.  
  104.   if(!process_lines(obj, file, 1))
  105.     { fclose(file); return 1; } /* Fail */
  106.  
  107.   /* Close file and finish. */
  108.   fclose(file);
  109.   DEBUGF("Options: finished reading file\n");
  110.   return 0; /* Success */
  111. }
  112.  
  113. /* Processes lines from an option file.  Returns when a closing } is
  114.    found.  Will return non-zero for success, 0 if malloc failed. */
  115. static int process_lines(thiniconbar_options *obj, FILE *file, bool enabled)
  116. {
  117.   /* Read options from the file. */
  118.   /* Each line is of the form:  option (whitespace) value */
  119.   while(!feof(file)) {
  120.     char *line = file_readline(file), *c = line, *l = 0;
  121.     char *opt, *val;
  122.     if(!line) return 0; /* malloc failed, so whinge. */
  123.  
  124.     /* Extract option and value from line. */
  125.     while(isspace(*c) && *c) ++c;
  126.  
  127.     /* Skip line if empty or a comment. */
  128.     if(!*c || *c == '#') { free(line); continue; }
  129.     /* Return if this is the end of a group. */
  130.     if(*c == '}') { free(line); return 1; }
  131.     /* If not switched on, ignore the line now. */
  132.     if(!enabled) { free(line); continue; }
  133.  
  134.     opt = c;
  135.     /* Option keyword. */
  136.     while(!isspace(*c) && *c) {
  137.       if(*c == '-') *c = '_';
  138.       ++c;
  139.     }
  140.     if(*c) *c++ = 0;
  141.     while(isspace(*c) && *c) ++c;
  142.     val = c;
  143.     /* Snip any comments and their whitespace, after the value. */
  144.     while(*c) {
  145.       if(isspace(*c)) { l = c; }
  146.         else { if(*c == '#') { *(l ? l : c) = 0; break; } }
  147.       ++c;
  148.     }
  149.  
  150.     /* Is this an option group? */
  151.     if(!strcmp(opt, "group")) {
  152.       const char *name = val;
  153.       bool enable, content;
  154.  
  155.       /* Split value into group name and its state (on or off). */
  156.       char *c = val;
  157.       const char *state = 0;
  158.       /* Look for second arg. */
  159.       while(*c && !isspace(*c)) ++c;
  160.       if(*c) {
  161.         *c++ = 0;
  162.         state = c;
  163.       }
  164.       /* Look for group's opening bracket. */
  165.       while(*c && !isspace(*c)) ++c;
  166.       if(*c) *c++ = 0;
  167.       while(*c && isspace(*c) && *c != '{') ++c;
  168.       content = (*c == '{');
  169.  
  170.       /* Is this group enabled? */
  171.       if(!state) { enable = 0; }
  172.       else if(!strcmp(state, "on")) { enable = 1; }
  173.       else if(!strcmp(state, "off")) { enable = 0; }
  174.       else { enable = atoi(state); }
  175.  
  176.       /* Process group according to whether it is enabled. */
  177.       if(content) {
  178.         DEBUGF2("Options: begin group `%s' (state `%s')\n", name, state);
  179.         if(!process_lines(obj, file, enable))
  180.           { free(line); return 0; } /* Fail */
  181.         DEBUGF2("Options: end group `%s' (state `%s')\n", name, state);
  182.       }
  183.       else {
  184.         DEBUGF2("Options: group `%s' (state `%s') has no content\n",
  185.         name, state);
  186.       }
  187.       free(line);
  188.       continue;
  189.     }
  190.  
  191.     /* Match options. */
  192.     if(read_option(obj, opt, val)) {
  193.       free(line);
  194.       return 0; /* Failure */
  195.     }
  196.     free(line);
  197.   }
  198.   DEBUGF("Options: reached end of file\n");
  199.   return 1; /* Success */
  200. }
  201.  
  202. /* Reads options from a command line, filling out the given options object.
  203.    Might return non-zero for malloc failure.  This looks at *all* the
  204.    command line parameters you give it (so don't pass the command's
  205.    filename). */
  206. bool thiniconbar_options_from_cli(thiniconbar_options *obj,
  207.     int argc, char *argv[])
  208. {
  209.   /* Command line should consist of pairs of the form `--option value'.
  210.      Any parameters not conforming are ignored without error. */
  211.   int i;
  212.   for(i=0; i<(argc-1); ++i) {
  213.     if(argv[i][0] == '-' && argv[i][1] == '-') {
  214.       /* Copy argument so that `-'s can become `_'s. */
  215.       char *opt = my_strdup(argv[i] + 2), *c;
  216.       if(!opt) return 1; /* Failure */
  217.       for(c=opt; *c; ++c) if(*c == '-') *c = '_';
  218.       if(read_option(obj, opt, argv[i+1])) return 1; /* Failure */
  219.       ++i;
  220.     }
  221.   }
  222.   return 0; /* Success */
  223. }
  224.  
  225. /* Reads an option.  Returns non-zero for a malloc failure. */
  226. static bool read_option(thiniconbar_options *obj,
  227.     const char *opt, const char *val)
  228. {
  229.   /* A number of macros are defined here to read each data type for us. */
  230.  
  231. /* Read an integer. */
  232. #define READ_INT(option)        \
  233.   if(!strcmp(opt, #option)) {        \
  234.     obj->option = atoi(val);        \
  235.     DEBUGF2("Options: option `%s' (value `%s') read as int\n", opt, val); \
  236.     return 0;                \
  237.   }
  238.  
  239. /* Read a floating point number. */
  240. #define READ_FLOAT(option)        \
  241.   if(!strcmp(opt, #option)) {        \
  242.     obj->option = atof(val);        \
  243.     DEBUGF2("Options: option `%s' (value `%s') read as "    \
  244.     "double\n", opt, val);        \
  245.     return 0;                \
  246.   }
  247.  
  248. /* Read a string. */
  249. /* A string of `-' here means use a null char pointer. */
  250. #define READ_STRING(option)        \
  251.   if(!strcmp(opt, #option)) {        \
  252.     if(val[0] == '-' && !val[1])    \
  253.       obj->option = 0;            \
  254.     else {                \
  255.       obj->option = my_strdup(val);    \
  256.       if(!obj->option) return 1; /* Fail */    \
  257.     }                    \
  258.     DEBUGF2("Options: option `%s' (value `%s') read as "    \
  259.     "string\n", opt, val);        \
  260.     return 0;                \
  261.   }
  262.  
  263. /* Read an enumeration. */
  264. /* This may be one string of a set, or the number to use directly. */
  265. #define BEGIN_ENUM(option)        \
  266.   if(!strcmp(opt, #option)) { int *w = &obj->option;
  267. #define ENUM_VAL(symbol, num)        \
  268.   if(!strcmp(val, symbol)) {        \
  269.     *w = num;                \
  270.     DEBUGF3("Options: option `%s' (value `%s') read as enum, symbol `"    \
  271.     symbol "' value " #num " (%i)\n", opt, val, num);        \
  272.     return 0;                \
  273.   }
  274. #define END_ENUM            \
  275.   *w = atoi(val);            \
  276.   DEBUGF2("Options: option `%s' (value `%s') "        \
  277.     "unmatched enum, read as int\n", opt, val);    \
  278.   return 0; }
  279.  
  280. /* Read a boolean variable (on, off, 1 or 0). */
  281. /* Implemented as an enumeration. */
  282. #define READ_BOOL(option)        \
  283.   BEGIN_ENUM(option)            \
  284.     ENUM_VAL("off", 0)            \
  285.     ENUM_VAL("on", 1)            \
  286.   END_ENUM;
  287.  
  288. /* Read a colour.  Only does Wimp colours at the moment. */
  289. /* You can use a colour name or a number. */
  290. #define READ_COLOUR(option)        \
  291.   BEGIN_ENUM(option)            \
  292.     ENUM_VAL("white", 0)        \
  293.     ENUM_VAL("grey-1", 1)        \
  294.     ENUM_VAL("grey-2", 2)        \
  295.     ENUM_VAL("grey-3", 3)        \
  296.     ENUM_VAL("grey-4", 4)        \
  297.     ENUM_VAL("grey-5", 5)        \
  298.     ENUM_VAL("grey-6", 6)        \
  299.     ENUM_VAL("black", 7)        \
  300.     ENUM_VAL("dark-blue", 8)        \
  301.     ENUM_VAL("yellow", 9)        \
  302.     ENUM_VAL("light-green", 10)        \
  303.     ENUM_VAL("red", 11)            \
  304.     ENUM_VAL("cream", 12)        \
  305.     ENUM_VAL("dark-green", 13)        \
  306.     ENUM_VAL("orange", 14)        \
  307.     ENUM_VAL("light-blue", 15)        \
  308.     ENUM_VAL("none", -1)        \
  309.   END_ENUM;
  310.  
  311.   /* Gaps */
  312.   READ_INT(end_gap);
  313.   READ_INT(between_gap);
  314.   READ_INT(central_gap);
  315.   READ_INT(top_gap);
  316.   READ_INT(sprite_margin);
  317.   READ_INT(text_margin);
  318.   READ_INT(sprite_text_gap);
  319.   READ_INT(icon_h_margins);
  320.   /* Heights */
  321.   READ_INT(icon_height);
  322.   READ_INT(window_height);
  323.   /* Scrolling */
  324.   BEGIN_ENUM(scroll_type)
  325.     ENUM_VAL("none", scroll_type_NONE)
  326.     ENUM_VAL("linear", scroll_type_LINEAR)
  327.     ENUM_VAL("linear-s", scroll_type_LINEAR_S)
  328.     ENUM_VAL("prop", scroll_type_PROP)
  329.     ENUM_VAL("move", scroll_type_MOVE)
  330.   END_ENUM;
  331.   READ_INT(scroll_margin);
  332.   READ_INT(scroll_step);
  333.   READ_INT(scroll_speed);
  334.   /* Colours */
  335.   READ_COLOUR(text_colour);
  336.   READ_COLOUR(icon_bg_colour);
  337.   READ_COLOUR(window_bg_colour);
  338.   /* Borders */
  339.   BEGIN_ENUM(icon_borders)
  340.     ENUM_VAL("none", border_type_NONE)
  341.     ENUM_VAL("plain", border_type_PLAIN)
  342.     ENUM_VAL("slab-out", border_type_SLAB_OUT)
  343.     ENUM_VAL("slab-in", border_type_SLAB_IN)
  344.   END_ENUM;
  345.   READ_INT(border_size);
  346.   READ_BOOL(window_border);
  347.   /* Menus */
  348.   READ_INT(menu_y_offset);
  349.   /* Misc */
  350.   READ_BOOL(small_icons);
  351.   READ_BOOL(use_task_name);
  352.   READ_INT(text_height);
  353.   READ_STRING(font);
  354.   READ_FLOAT(font_size);
  355.   READ_FLOAT(font_width);
  356.   BEGIN_ENUM(arrangement)
  357.     ENUM_VAL("text-bottom", arrangement_TEXT_BOTTOM);
  358.     ENUM_VAL("text-right", arrangement_TEXT_RIGHT);
  359.   END_ENUM;
  360.   /* Pinboard */
  361.   READ_BOOL(patch_pinboard);
  362.   READ_COLOUR(pinboard_bg_colour);
  363.  
  364.   /* Don't need the macros any more. */
  365. #undef READ_INT
  366. #undef READ_FLOAT
  367. #undef READ_STRING
  368. #undef BEGIN_ENUM
  369. #undef ENUM_VAL
  370. #undef END_ENUM
  371. #undef READ_BOOL
  372.  
  373.   /* If not matched, make a note on debug. */
  374.   DEBUGF2("Options: option `%s' not recognised (value `%s')\n", opt, val);
  375.   return 0; /* Success */
  376. }
  377.  
  378. /* Reads a line from a file.  May return 0 if malloc failed at some point.
  379.    Free the returned string yourself. */
  380. char *file_readline(FILE *file)
  381. {
  382.   int ch, len = 40;
  383.   char *line = malloc(len + 1), *c = line;
  384.   if(!line) return 0;
  385.   do {
  386.     ch = fgetc(file);
  387.     if(ch == EOF || ch == '\n') ch = 0;
  388.     /* Extend buffer if necessary. */
  389.     if((c - line) >= len) {
  390.       char *old_line = line;
  391.       len += 30;
  392.       line = realloc(line, len + 1);
  393.       if(!line) return 0;
  394.       c = c - old_line + line;
  395.     }
  396.     *c++ = ch;
  397.   } while(ch);
  398.   return line;
  399. }
  400.  
  401. /* Destroys an options object, freeing data it owns. */
  402. void thiniconbar_options_destroy(thiniconbar_options *obj)
  403. {
  404.   if(!obj) return;
  405.  
  406.   /* Free strings owned. */
  407.   free(obj->font);
  408.  
  409.   free(obj);
  410. }
  411.