home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 25 / AACD 25.iso / AACD / Utilities / BasiliskII / src / prefs.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-05-15  |  9.1 KB  |  458 lines

  1. /*
  2.  *  prefs.cpp - Preferences handling
  3.  *
  4.  *  Basilisk II (C) 1997-2001 Christian Bauer
  5.  *
  6.  *  This program is free software; you can redistribute it and/or modify
  7.  *  it under the terms of the GNU General Public License as published by
  8.  *  the Free Software Foundation; either version 2 of the License, or
  9.  *  (at your option) any later version.
  10.  *
  11.  *  This program is distributed in the hope that it will be useful,
  12.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  *  GNU General Public License for more details.
  15.  *
  16.  *  You should have received a copy of the GNU General Public License
  17.  *  along with this program; if not, write to the Free Software
  18.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19.  */
  20.  
  21. #include <string.h>
  22. #include <stdlib.h>
  23. #include <stdio.h>
  24. #include <ctype.h>
  25.  
  26. #include "sysdeps.h"
  27. #include "sys.h"
  28. #include "prefs.h"
  29.  
  30.  
  31. // Prefs items are stored in a linked list of these nodes
  32. struct prefs_node {
  33.     prefs_node *next;
  34.     const char *name;
  35.     prefs_type type;
  36.     void *data;
  37. };
  38.  
  39. // List of prefs nodes
  40. static prefs_node *the_prefs = NULL;
  41.  
  42. // Prototypes
  43. static const prefs_desc *find_prefs_desc(const char *name);
  44.  
  45.  
  46. /*
  47.  *  Initialize preferences
  48.  */
  49.  
  50. void PrefsInit(int &argc, char **&argv)
  51. {
  52.     // Set defaults
  53.     AddPrefsDefaults();
  54.     AddPlatformPrefsDefaults();
  55.  
  56.     // Load preferences from settings file
  57.     LoadPrefs();
  58.  
  59.     // Override prefs with command line options
  60.     for (int i=1; i<argc; i++) {
  61.  
  62.         // Options are of the form '--keyword'
  63.         const char *option = argv[i];
  64.         if (strlen(option) < 3 || option[0] != '-' || option[1] != '-')
  65.             continue;
  66.         const char *keyword = option + 2;
  67.  
  68.         // Find descriptor for keyword
  69.         const prefs_desc *d = find_prefs_desc(keyword);
  70.         if (d == NULL)
  71.             continue;
  72.         argv[i] = NULL;
  73.  
  74.         // Get value
  75.         i++;
  76.         if (i >= argc) {
  77.             fprintf(stderr, "Option '%s' must be followed by a value\n", option);
  78.             continue;
  79.         }
  80.         const char *value = argv[i];
  81.         argv[i] = NULL;
  82.  
  83.         // Add/replace prefs item
  84.         switch (d->type) {
  85.             case TYPE_STRING:
  86.                 if (d->multiple)
  87.                     PrefsAddString(keyword, value);
  88.                 else
  89.                     PrefsReplaceString(keyword, value);
  90.                 break;
  91.  
  92.             case TYPE_BOOLEAN: {
  93.                 if (!strcmp(value, "true") || !strcmp(value, "on") || !strcmp(value, "yes"))
  94.                     PrefsReplaceBool(keyword, true);
  95.                 else if (!strcmp(value, "false") || !strcmp(value, "off") || !strcmp(value, "no"))
  96.                     PrefsReplaceBool(keyword, false);
  97.                 else
  98.                     fprintf(stderr, "Value for option '%s' must be 'true' or 'false'\n", option);
  99.                 break;
  100.             }
  101.  
  102.             case TYPE_INT32:
  103.                 PrefsReplaceInt32(keyword, atoi(value));
  104.                 break;
  105.  
  106.             default:
  107.                 break;
  108.         }
  109.     }
  110.  
  111.     // Remove processed arguments
  112.     for (int i=1; i<argc; i++) {
  113.         int k;
  114.         for (k=i; k<argc; k++)
  115.             if (argv[k] != NULL)
  116.                 break;
  117.         if (k > i) {
  118.             k -= i;
  119.             for (int j=i+k; j<argc; j++)
  120.                 argv[j-k] = argv[j];
  121.             argc -= k;
  122.         }
  123.     }
  124. }
  125.  
  126.  
  127. /*
  128.  *  Deinitialize preferences
  129.  */
  130.  
  131. void PrefsExit(void)
  132. {
  133.     // Free prefs list
  134.     prefs_node *p = the_prefs, *next;
  135.     while (p) {
  136.         next = p->next;
  137.         free((void *)p->name);
  138.         free(p->data);
  139.         delete p;
  140.         p = next;
  141.     }
  142.     the_prefs = NULL;
  143. }
  144.  
  145.  
  146. /*
  147.  *  Print preferences options help
  148.  */
  149.  
  150. static void print_options(const prefs_desc *list)
  151. {
  152.     while (list->type != TYPE_END) {
  153.         if (list->help) {
  154.             const char *typestr, *defstr;
  155.             char numstr[32];
  156.             switch (list->type) {
  157.                 case TYPE_STRING:
  158.                     typestr = "STRING";
  159.                     defstr = PrefsFindString(list->name);
  160.                     if (defstr == NULL)
  161.                         defstr = "none";
  162.                     break;
  163.                 case TYPE_BOOLEAN:
  164.                     typestr = "BOOL";
  165.                     if (PrefsFindBool(list->name))
  166.                         defstr = "true";
  167.                     else
  168.                         defstr = "false";
  169.                     break;
  170.                 case TYPE_INT32:
  171.                     typestr = "NUMBER";
  172.                     sprintf(numstr, "%d", PrefsFindInt32(list->name));
  173.                     defstr = numstr;
  174.                     break;
  175.                 default:
  176.                     typestr = "<unknown>";
  177.                     defstr = "none";
  178.                     break;
  179.             }
  180.             printf("  --%s %s\n    %s [default=%s]\n", list->name, typestr, list->help, defstr);
  181.         }
  182.         list++;
  183.     }
  184. }
  185.  
  186. void PrefsPrintUsage(void)
  187. {
  188.     printf("\nGeneral options:\n");
  189.     print_options(common_prefs_items);
  190.     printf("\nPlatform-specific options:\n");
  191.     print_options(platform_prefs_items);
  192.     printf("\nBoolean options are specified as '--OPTION true|on|yes' or\n'--OPTION false|off|no'.\n");
  193. }
  194.  
  195.  
  196. /*
  197.  *  Find preferences descriptor by keyword
  198.  */
  199.  
  200. static const prefs_desc *find_prefs_desc(const char *name, const prefs_desc *list)
  201. {
  202.     while (list->type != TYPE_ANY) {
  203.         if (strcmp(list->name, name) == 0)
  204.             return list;
  205.         list++;
  206.     }
  207.     return NULL;
  208. }
  209.  
  210. static const prefs_desc *find_prefs_desc(const char *name)
  211. {
  212.     const prefs_desc *d = find_prefs_desc(name, common_prefs_items);
  213.     if (d == NULL)
  214.         d = find_prefs_desc(name, platform_prefs_items);
  215.     return d;
  216. }
  217.  
  218.  
  219. /*
  220.  *  Set prefs items
  221.  */
  222.  
  223. static void add_data(const char *name, prefs_type type, void *data, int size)
  224. {
  225.     void *d = malloc(size);
  226.     if (d == NULL)
  227.         return;
  228.     memcpy(d, data, size);
  229.     prefs_node *p = new prefs_node;
  230.     p->next = 0;
  231.     p->name = strdup(name);
  232.     p->type = type;
  233.     p->data = d;
  234.     if (the_prefs) {
  235.         prefs_node *prev = the_prefs;
  236.         while (prev->next)
  237.             prev = prev->next;
  238.         prev->next = p;
  239.     } else
  240.         the_prefs = p;
  241. }
  242.  
  243. void PrefsAddString(const char *name, const char *s)
  244. {
  245.     add_data(name, TYPE_STRING, (void *)s, strlen(s) + 1);
  246. }
  247.  
  248. void PrefsAddBool(const char *name, bool b)
  249. {
  250.     add_data(name, TYPE_BOOLEAN, &b, sizeof(bool));
  251. }
  252.  
  253. void PrefsAddInt32(const char *name, int32 val)
  254. {
  255.     add_data(name, TYPE_INT32, &val, sizeof(int32));
  256. }
  257.  
  258.  
  259. /*
  260.  *  Replace prefs items
  261.  */
  262.  
  263. static prefs_node *find_node(const char *name, prefs_type type, int index = 0)
  264. {
  265.     prefs_node *p = the_prefs;
  266.     int i = 0;
  267.     while (p) {
  268.         if ((type == TYPE_ANY || p->type == type) && !strcmp(p->name, name)) {
  269.             if (i == index)
  270.                 return p;
  271.             else
  272.                 i++;
  273.         }
  274.         p = p->next;
  275.     }
  276.     return NULL;
  277. }
  278.  
  279. void PrefsReplaceString(const char *name, const char *s, int index)
  280. {
  281.     prefs_node *p = find_node(name, TYPE_STRING, index);
  282.     if (p) {
  283.         free(p->data);
  284.         p->data = strdup(s);
  285.     } else
  286.         add_data(name, TYPE_STRING, (void *)s, strlen(s) + 1);
  287. }
  288.  
  289. void PrefsReplaceBool(const char *name, bool b)
  290. {
  291.     prefs_node *p = find_node(name, TYPE_BOOLEAN);
  292.     if (p)
  293.         *(bool *)(p->data) = b;
  294.     else
  295.         add_data(name, TYPE_BOOLEAN, &b, sizeof(bool));
  296. }
  297.  
  298. void PrefsReplaceInt32(const char *name, int32 val)
  299. {
  300.     prefs_node *p = find_node(name, TYPE_INT32);
  301.     if (p)
  302.         *(int32 *)(p->data) = val;
  303.     else
  304.         add_data(name, TYPE_INT32, &val, sizeof(int32));
  305. }
  306.  
  307.  
  308. /*
  309.  *  Get prefs items
  310.  */
  311.  
  312. const char *PrefsFindString(const char *name, int index)
  313. {
  314.     prefs_node *p = find_node(name, TYPE_STRING, index);
  315.     if (p)
  316.         return (char *)(p->data);
  317.     else
  318.         return NULL;
  319. }
  320.  
  321. bool PrefsFindBool(const char *name)
  322. {
  323.     prefs_node *p = find_node(name, TYPE_BOOLEAN, 0);
  324.     if (p)
  325.         return *(bool *)(p->data);
  326.     else
  327.         return false;
  328. }
  329.  
  330. int32 PrefsFindInt32(const char *name)
  331. {
  332.     prefs_node *p = find_node(name, TYPE_INT32, 0);
  333.     if (p)
  334.         return *(int32 *)(p->data);
  335.     else
  336.         return 0;
  337. }
  338.  
  339.  
  340. /*
  341.  *  Remove prefs items
  342.  */
  343.  
  344. void PrefsRemoveItem(const char *name, int index)
  345. {
  346.     prefs_node *p = find_node(name, TYPE_ANY, index);
  347.     if (p) {
  348.         free((void *)p->name);
  349.         free(p->data);
  350.         prefs_node *q = the_prefs;
  351.         if (q == p) {
  352.             the_prefs = NULL;
  353.             delete p;
  354.             return;
  355.         }
  356.         while (q) {
  357.             if (q->next == p) {
  358.                 q->next = p->next;
  359.                 delete p;
  360.                 return;
  361.             }
  362.             q = q->next;
  363.         }
  364.     }
  365. }
  366.  
  367.  
  368. /*
  369.  *  Load prefs from stream (utility function for LoadPrefs() implementation)
  370.  */
  371.  
  372. void LoadPrefsFromStream(FILE *f)
  373. {
  374.     char line[256];
  375.     while(fgets(line, 255, f)) {
  376.         // Read line
  377.         int len = strlen(line);
  378.         if (len == 0)
  379.             continue;
  380.         line[len-1] = 0;
  381.  
  382.         // Comments begin with "#" or ";"
  383.         if (line[0] == '#' || line[0] == ';')
  384.             continue;
  385.  
  386.         // Terminate string after keyword
  387.         char *p = line;
  388.         while (!isspace(*p)) p++;
  389.         *p++ = 0;
  390.  
  391.         // Skip whitespace until value
  392.         while (isspace(*p)) p++;
  393.         char *keyword = line;
  394.         char *value = p;
  395.         int32 i = atol(value);
  396.  
  397.         // Look for keyword first in prefs item list
  398.         const prefs_desc *desc = find_prefs_desc(keyword);
  399.         if (desc == NULL) {
  400.             printf("WARNING: Unknown preferences keyword '%s'\n", keyword);
  401.             continue;
  402.         }
  403.  
  404.         // Add item to prefs
  405.         switch (desc->type) {
  406.             case TYPE_STRING:
  407.                 if (desc->multiple)
  408.                     PrefsAddString(keyword, value);
  409.                 else
  410.                     PrefsReplaceString(keyword, value);
  411.                 break;
  412.             case TYPE_BOOLEAN:
  413.                 PrefsReplaceBool(keyword, !strcmp(value, "true"));
  414.                 break;
  415.             case TYPE_INT32:
  416.                 PrefsReplaceInt32(keyword, i);
  417.                 break;
  418.             default:
  419.                 break;
  420.         }
  421.     }
  422. }
  423.  
  424.  
  425. /*
  426.  *  Save settings to stream (utility function for SavePrefs() implementation)
  427.  */
  428.  
  429. static void write_prefs(FILE *f, const prefs_desc *list)
  430. {
  431.     while (list->type != TYPE_ANY) {
  432.         switch (list->type) {
  433.             case TYPE_STRING: {
  434.                 int index = 0;
  435.                 const char *str;
  436.                 while ((str = PrefsFindString(list->name, index++)) != NULL)
  437.                     fprintf(f, "%s %s\n", list->name, str);
  438.                 break;
  439.             }
  440.             case TYPE_BOOLEAN:
  441.                 fprintf(f, "%s %s\n", list->name, PrefsFindBool(list->name) ? "true" : "false");
  442.                 break;
  443.             case TYPE_INT32:
  444.                 fprintf(f, "%s %d\n", list->name, PrefsFindInt32(list->name));
  445.                 break;
  446.             default:
  447.                 break;
  448.         }
  449.         list++;
  450.     }
  451. }
  452.  
  453. void SavePrefsToStream(FILE *f)
  454. {
  455.     write_prefs(f, common_prefs_items);
  456.     write_prefs(f, platform_prefs_items);
  457. }
  458.