Settings.cpp 6.69 KB
Newer Older
1
2
3
4
5
6
7
8
////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// zmoelnig@iem.at
//
// Implementation file
//
zmoelnig's avatar
zmoelnig committed
9
//    Copyright (c) 2009-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at
10
11
12
13
14
15
16
//    For information on usage and redistribution, and for a DISCLAIMER OF ALL
//    WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
// load settings from a file (or get them via env-variables)
//
/////////////////////////////////////////////////////////

17
#include "Gem/GemConfig.h"
18

19
#include "Gem/RTE.h"
20

zmoelnig's avatar
zmoelnig committed
21
22
#include "Settings.h"
#include "Files.h"
23
24

#include <map>
25
#include <string.h>
26
27
28
#include <stdlib.h>
#include <errno.h>

29
#define GEM_SETTINGS_FILE "gem.conf"
30
static const char*s_configdir[] = {
31
32
#ifdef __linux__
  "/etc/pd",
33
  "~/.config/pure-data",
34
35
36
37
38
39
40
#elif defined __APPLE__
  "/Library/Pd",
  "~/Library/Pd",
#elif defined  _WIN32
  "%CommonProgramFiles%\\Pd",
  "%AppData%\\Pd",
#endif
41
42
  0 /* $(pwd)/gem.conf */
};
43

zmoelnig's avatar
zmoelnig committed
44
45
46
47
48
49
50
51
52
53
54
55
56
57



/* this is ripped from m_imp.h */
struct _gemclass
{
  t_symbol *c_name;                   /* name (mostly for error reporting) */
  t_symbol *c_helpname;               /* name of help file */
  t_symbol *c_externdir;              /* directory extern was loaded from */
  /* ... */ /* the real t_class continues here... */
};
# define t_gemclass struct _gemclass


zmoelnig's avatar
zmoelnig committed
58
59
namespace {
struct PIMPL {
60
  // dictionary for setting values
61
  std::map <std::string, t_atom> data;
62

63
  virtual t_atom*get(const std::string&name) {
64
65
66
67
    std::map<std::string, t_atom>::iterator it=data.find(name);
    if(it==data.end())
      return NULL;
    return &it->second;
68
  }
69
  virtual void set(const std::string&name, t_atom*value) {
70
    // LATER: we should expand envvariables
71
    if(value) {
72
      data[name]= *value;
73
74
75
    } else {
      data.erase(name);
    }
76
77
  }

78
  void set(const std::string&name, int i) {
zmoelnig's avatar
zmoelnig committed
79
80
81
82
    t_atom a;
    SETFLOAT(&a, i);
    set(name, &a);
  }
83
  void set(const std::string&name, float f) {
84
85
86
87
    t_atom a;
    SETFLOAT(&a, f);
    set(name, &a);
  }
88
  void set(const std::string&name, double f) {
zmoelnig's avatar
zmoelnig committed
89
90
91
92
    t_atom a;
    SETFLOAT(&a, f);
    set(name, &a);
  }
93
  void set(const std::string&name, const std::string&s) {
zmoelnig's avatar
zmoelnig committed
94
    t_atom a;
95
    SETSYMBOL(&a, gensym(s.c_str()));
zmoelnig's avatar
zmoelnig committed
96
97
98
    set(name, &a);
  }

99
  //  std::string expandEnv(std::string , bool bashfilename=false);
zmoelnig's avatar
zmoelnig committed
100

101

102
103
104
105
106
  bool open(const char*filename, const char*dirname=NULL) {
    t_binbuf*bb=binbuf_new();
    int r=0;
    if(NULL==filename)
      return false;
107
108


109
    if(dirname) {
zmoelnig's avatar
zmoelnig committed
110
      r=binbuf_read(bb, (char*)filename, const_cast<char*>(gem::files::expandEnv(dirname, true).c_str()), 1);
111
      if(0==r)verbose(1, "found Gem-settings '%s' in '%s'", filename, dirname);
112
    } else {
113
      r=binbuf_read_via_path(bb, (char*)filename, (char*)".", 1);
114
      if(0==r)verbose(1, "found Gem-settings '%s'", filename);
115
116
117
118
119
120
121
122
123
124
    }

    if(r){
      binbuf_free(bb);
      return false;
    }

    int ac=binbuf_getnatom(bb);
    t_atom*av=binbuf_getvec(bb);

125
    std::string s;
zmoelnig's avatar
zmoelnig committed
126
    t_atom*a=NULL;
127
128
129
130
131
    int state=0; /* 0=(next is ID); 1=(next is value); 2=(next is ignored) */

    while(ac--) {
      if (av->a_type == A_SEMI) {
        // done
132
        if(!s.empty()) {
133
134
135
          set(s, a);
        }
        state=0;
136
        s.clear();
137
138
139
      } else {
        switch (state) {
        case 0:
140
          s=atom_getsymbol(av)->s_name;
141
142
143
144
145
146
147
148
149
          state=1;
          break;
        case 1:
          a=av;
          state=2;
          break;
        default:
          break;
        }
150
      }
151
      av++;
152
    }
153
154
155
156
157
158

    binbuf_free(bb);
    return true;
  }

  void print(void) {
159
    std::map <std::string , t_atom>::iterator it;
160
    for(it = data.begin();
161
162
163
        it != data.end();
        it++)
      {
164
165
166
        if(!it->first.empty()) {
          startpost("key ['%s']: '", it->first.c_str());
          postatom(1, &it->second);
167

168
          post("'");
169
        }
170
      }
171
  }
zmoelnig's avatar
zmoelnig committed
172

173
174


175
176
  PIMPL(void)
  {
zmoelnig's avatar
zmoelnig committed
177
#ifdef GEM_DEFAULT_FONT
178
    set("font.face", GEM_DEFAULT_FONT);
zmoelnig's avatar
zmoelnig committed
179
180
#endif

181
    setEnv("settings.file", "GEM_SETTINGS");
182
    t_atom*a=get("settings.file");
183
184
185
186
    if(a) {
      std::string s=atom_getsymbol(a)->s_name;
      open(gem::files::expandEnv(s.c_str(), true).c_str(), ".");
    } else {
IOhannes m zmölnig's avatar
IOhannes m zmölnig committed
187
      int i=0;
188
189
190
191
192
      while(s_configdir[i]) {
	open(GEM_SETTINGS_FILE, s_configdir[i]);
	i++;
      }
      open(GEM_SETTINGS_FILE, ".");
193
    }
194

195
196
197
198
    /* legacy settings via environmental variables */
    setEnv("texture.rectangle", "GEM_RECTANGLE_TEXTURE");
    setEnv("singlecontext", "GEM_SINGLE_CONTEXT"); // hmm, what's a better new name for this?
    setEnv("font.face", "GEM_DEFAULT_FONT");
199

zmoelnig's avatar
zmoelnig committed
200

201
202
    t_gemclass *c = (t_gemclass*)class_new(gensym("Gem"), 0, 0, 0, 0, A_NULL);
    set("gem.path", c->c_externdir->s_name);
zmoelnig's avatar
zmoelnig committed
203

204
    //    print();
205
  }
zmoelnig's avatar
zmoelnig committed
206

207
  ~PIMPL(void) {
208

209
  }
210

211
  void setEnv(std::string key, const std::string&env) {
212
213
    if(env.empty())return;
    if(key.empty())return;
214

215
216
217
218
    char*result=getenv(env.c_str());
    if(NULL==result) {
      return;
    }
219

220
221
    t_atom a;
    errno=0;
222

223
224
225
226
227
228
    /* try integer */
    long l=strtol(result, NULL, 0);
    if(0==errno) {
      SETFLOAT(&a, l);
      set(key, &a);
    }
229

230
231
232
233
234
235
    /* try float */
    double d=strtod(result, NULL);
    if(0==errno) {
      SETFLOAT(&a, d);
      set(key, &a);
    }
236

237
238
    /* try symbol */
    SETSYMBOL(&a, gensym(result));
239
    set(key, &a);
240

241
    // we ignore lists and other complex things for now
242
  }
243
};
zmoelnig's avatar
zmoelnig committed
244
245
static PIMPL*settings=NULL;
};
246
247


248

249
/* gem::Settings: the public API */
250
251
252


/* public static functions */
253
void gem::Settings::init() {
254
  if(settings)return;
255
  settings=new PIMPL();
256
}
257
void gem::Settings::print() {
258
259
260
  if(!settings)return;
  settings->print();
}
261
void gem::Settings::save() {
262
  if(!settings)return;
263
  post("gem::Settings: save not yet implemented!");
264
265
266
}


267

268
t_atom*gem::Settings::get(const std::string&s) {
269
  if(NULL==settings) init();
270
  return settings->get(s.c_str());
271
}
272
273
void gem::Settings::set(const std::string&key, t_atom*v) {
  settings->set(key.c_str(), v);
274
}
zmoelnig's avatar
zmoelnig committed
275
276


277
void gem::Settings::get(const std::string&key, int&value) {
zmoelnig's avatar
zmoelnig committed
278
279
280
281
282
  t_atom*a=get(key);
  if(a && A_FLOAT==a->a_type) {
    value=atom_getint(a);
  }
}
283
void gem::Settings::get(const std::string&key, float&value) {
284
285
286
287
288
  t_atom*a=get(key);
  if(a && A_FLOAT==a->a_type) {
    value=atom_getfloat(a);
  }
}
289
void gem::Settings::get(const std::string&key, double&value) {
zmoelnig's avatar
zmoelnig committed
290
291
292
293
294
295
  t_atom*a=get(key);
  if(a && A_FLOAT==a->a_type) {
    value=atom_getfloat(a);
  }
}

296
void gem::Settings::get(const std::string&key, std::string&value) {
zmoelnig's avatar
zmoelnig committed
297
298
299
300
301
  t_atom*a=get(key);
  if(a) {
    value=atom_getsymbol(a)->s_name;
  }
}
zmoelnig's avatar
zmoelnig committed
302
303


304
std::vector<std::string>gem::Settings::keys(void) {
zmoelnig's avatar
zmoelnig committed
305
306
307
308
309
310
311
312
313
314
  std::vector<std::string>result;
  if(NULL==settings) init();
  if(NULL!=settings) {
    std::map<std::string, t_atom>::iterator it=settings->data.begin();
    while(settings->data.end() != it) {
      result.push_back(it->first);
    }
  }
  return result;
}