source: trunk/src/opengl/mesa/config.c@ 3721

Last change on this file since 3721 was 3598, checked in by jeroen, 25 years ago

* empty log message *

File size: 10.9 KB
Line 
1/* $Id: config.c,v 1.2 2000-05-23 20:40:25 jeroen Exp $ */
2
3/*
4 * Mesa 3-D graphics library
5 * Version: 3.3
6 *
7 * Copyright (C) 1999 Brian Paul All Rights Reserved.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27/* Mesa config file parse and execute code.
28 * Copyright (C) 1999 Keith Whitwell.
29 *
30 * I hate parsers, so I've choosen a lisp-like syntax - extremely easy
31 * to parse and potentially very expressive.
32 */
33
34#include "glheader.h"
35#include "enums.h"
36#include "config.h"
37#include "types.h"
38#include "extensions.h"
39#include "simple_list.h"
40#include "mem.h"
41#include "hint.h"
42
43typedef enum { nil_t, list_t, word_t } node_type;
44
45struct cnode {
46 node_type type;
47 int line;
48 union {
49 struct { struct cnode *head, *tail; } l;
50 struct { char *text; } w;
51 } data;
52};
53
54/* Pretty printer for debugging.
55 */
56static void pad(int n) { putchar('\n'); while(n--) putchar(' '); }
57
58static void print_list( struct cnode *n, int indent )
59{
60 int i = 0;
61 printf("( ");
62 while (n->type == list_t) {
63 if (i++ > 0) pad(indent + 2);
64 switch (n->data.l.head->type) {
65 case list_t:
66 print_list( n->data.l.head, indent + 2 );
67 break;
68 case word_t:
69 printf( n->data.l.head->data.w.text );
70 break;
71 case nil_t:
72 printf("()");
73 break;
74 default:
75 puts("***");
76 }
77 n = n->data.l.tail;
78 }
79 printf(" )");
80}
81
82
83
84/* Accessors to query the contents of a cnode.
85 */
86static int is_list( struct cnode *x, struct cnode **h, struct cnode **t)
87{
88 if (x->type == list_t) {
89 struct cnode *tmp = x;
90 *h = tmp->data.l.head;
91 *t = tmp->data.l.tail;
92 return 1;
93 }
94 return 0;
95}
96
97static int is_nil( const struct cnode *x )
98{
99 return x->type == nil_t;
100}
101
102static int is_word( struct cnode *x, const char **s )
103{
104 if (x->type == word_t) {
105 *s = x->data.w.text;
106 return 1;
107 }
108 return 0;
109}
110
111static int match_word( struct cnode *x, const char *s )
112{
113 if (x->type == word_t)
114 return strcmp(s, x->data.w.text) == 0;
115 return 0;
116}
117
118/* Build the parsed expression.
119 */
120static void skip_comment( FILE *file )
121{
122 int c;
123 while ((c = getc(file)) != EOF && c != '\n') {};
124 ungetc( c, file );
125}
126
127
128static struct cnode *get_word( int line, FILE *file )
129{
130 int sz = 16, len = 0;
131 char *text = (char *) MALLOC( sz * sizeof(char) );
132
133 while (1) {
134 int c = getc(file);
135 if (len == sz)
136 text = (char *) realloc( text, sizeof(char) * (sz *= 2) );
137 if (c == EOF || isspace(c) || c == ')') {
138 struct cnode *n = MALLOC_STRUCT(cnode);
139 ungetc(c, file);
140 text[len] = 0;
141 n->type = word_t;
142 n->line = line;
143 n->data.w.text = text;
144 return n;
145 }
146 else
147 text[len++] = c;
148 }
149}
150
151static struct cnode *get_list( int *line, FILE *file )
152{
153 struct cnode *head, **current = &head;
154 head = MALLOC_STRUCT(cnode);
155 head->line = *line;
156 head->type = nil_t;
157
158 while (1) {
159 struct cnode *n = 0;
160 int c = getc(file);
161
162 switch (c) {
163 case EOF: return head;
164 case ')': return head;
165 case ';': skip_comment( file ); continue;
166 case '\n': (*line)++; continue;
167 case '(':
168 n = get_list( line, file );
169 break;
170 default:
171 if (isspace(c)) continue;
172 ungetc(c, file);
173 n = get_word( *line, file );
174 break;
175 }
176
177 (*current)->type = list_t;
178 (*current)->data.l.head = n;
179 current = &(*current)->data.l.tail;
180 (*current) = MALLOC_STRUCT(cnode);
181 (*current)->line = *line;
182 (*current)->type = nil_t;
183 }
184}
185
186/* Execute it.
187 */
188static void error( struct cnode *n, const char *err )
189{
190 printf("Error in init file, line %d: %s\n", n->line, err );
191}
192
193static void disable_extension( GLcontext *ctx, struct cnode *args )
194{
195 struct cnode *head, *tail;
196 const char *c;
197
198 if (is_list(args, &head, &tail) &&
199 is_nil(tail) &&
200 is_word(head, &c))
201 {
202 if (gl_extensions_disable( ctx, c ) != 0)
203 error( head, "unknown extension" );
204 }
205 else
206 error( args, "bad args for disable-extension" );
207}
208
209
210static void default_hint( GLcontext *ctx, struct cnode *args )
211{
212 struct cnode *hint, *tail, *value;
213 const char *hname, *vname;
214
215 if (is_list(args, &hint, &tail) &&
216 is_list(tail, &value, &tail) &&
217 is_nil(tail) &&
218 is_word(hint, &hname) &&
219 is_word(value, &vname))
220 {
221 GLint h = gl_lookup_enum_by_name(hname);
222 GLint v = gl_lookup_enum_by_name(vname);
223 if (h != -1 && v != -1)
224 {
225 printf("calling glHint(%s=%d, %s=%d)\n", hname, h, vname, v);
226 if (!_mesa_try_Hint( ctx, (GLenum) h, (GLenum) v ))
227 error( hint, "glHint failed");
228 printf("allow draw mem: %d\n", ctx->Hint.AllowDrawMem);
229 return;
230 }
231 else
232 error( hint, "unknown or illegal value for default-hint" );
233 }
234 else
235 error( args, "bad args for default-hint" );
236}
237
238/* Use the general-purpose set-variable
239 */
240static void fx_catch_signals( GLcontext *ctx, struct cnode *args )
241{
242 struct cnode *head, *tail;
243 const char *value;
244
245/* error( args, */
246/* "fx-catch-signals deprecated, use " */
247/* "(set-variable fx-catch-signals ...) instead"); */
248
249 if (is_list(args, &head, &tail) &&
250 is_nil(tail) &&
251 is_word(head, &value)) {
252 if (strcmp(value, "false") == 0)
253 ctx->CatchSignals = GL_FALSE;
254 else if (strcmp(value, "true") == 0)
255 ctx->CatchSignals = GL_TRUE;
256 else
257 error( args, "expected 'true' or 'false'" );
258 }
259 else {
260 error( args, "bad args for fx-catch-signal" );
261 }
262}
263
264/* Well, should these also check the environment?
265 * Should environment vars override config vars?
266 */
267
268struct var {
269 struct var *next, *prev;
270 const char *name;
271 void (*notify)(const char *value, int line);
272};
273
274static struct var varlist = { &varlist, &varlist, 0, 0 };
275
276static void set_var( GLcontext *ctx, struct cnode *args )
277{
278 struct var *v;
279 struct cnode *head, *tail;
280 const char *variable, *value;
281
282 if (is_list(args, &head, &tail) &&
283 is_word(head, &variable) &&
284 is_list(tail, &head, &tail) &&
285 is_word(head, &value) &&
286 is_nil(tail))
287 {
288 foreach(v, &varlist) {
289 if (strcmp(v->name, variable) == 0) {
290 v->notify(value, head->line);
291 return;
292 }
293 }
294
295 error( head, "unknown variable" );
296 }
297 else {
298 error( args, "bad format for (set VARIABLE VALUE)" );
299 }
300}
301
302void gl_register_config_var(const char *name,
303 void (*notify)( const char *, int ))
304{
305 struct var *v = MALLOC_STRUCT(var);
306 v->name = name;
307 v->notify = notify;
308 insert_at_tail( &varlist, v );
309}
310
311
312static void do_init( GLcontext *ctx, struct cnode *list )
313{
314 struct cnode *head, *tail, *func, *args;
315
316 if (is_list(list, &head, &tail) && is_nil(tail)) {
317 list = head;
318 while (is_list(list, &head, &list)) {
319 if (is_list(head, &func, &args)) {
320 if (match_word(func, "disable-extension"))
321 disable_extension( ctx, args );
322 else if (match_word(func, "default-hint"))
323 default_hint( ctx, args );
324 else if (match_word(func, "fx-catch-signals"))
325 fx_catch_signals( ctx, args );
326 else if (match_word(func, "set-variable"))
327 set_var( ctx, args );
328 else
329 error( func, "unknown configuration method" );
330 }
331 }
332 }
333 else if (!is_nil(list)) {
334 error( list, "configurations must form a list" );
335 }
336}
337
338static int run_init( GLcontext *ctx, const char *version, struct cnode *list )
339{
340 struct cnode *head, *arg1, *arg2;
341 const char *v;
342
343 /* Uses the first matching init list.
344 */
345 while (is_list(list, &head, &list))
346 if (is_list(head, &arg1, &head) &&
347 is_list(head, &arg2, &head) &&
348 match_word(arg1, "config-mesa") &&
349 is_word(arg2, &v))
350 {
351 if (strcmp(v, version) == 0) {
352 do_init( ctx, head );
353 return 1;
354 }
355 }
356 else
357 error( head, "malformed toplevel configuration" );
358
359 return 0;
360}
361
362
363
364static void free_list( struct cnode *n )
365{
366 while (n->type == list_t) {
367 struct cnode *tmp = n;
368 switch (n->data.l.head->type) {
369 case list_t:
370 free_list( n->data.l.head );
371 break;
372 case word_t:
373 FREE( n->data.l.head->data.w.text );
374 FREE( n->data.l.head );
375 break;
376 case nil_t:
377 FREE( n->data.l.head );
378 break;
379 default:
380 return;
381 }
382 n = n->data.l.tail;
383 FREE( tmp );
384 }
385 FREE( n );
386}
387
388
389
390
391/* How paranoid do you have to be when reading a config file? I don't
392 * know half the ways to exploit this stuff, and given that this may
393 * be run with root access, I think we're better off hardcoding the
394 * pathname. Some clever joe can fix this later if they care.
395 */
396void gl_read_config_file( GLcontext *ctx )
397{
398 const char *default_config = "mesa3.3";
399
400#if defined(__WIN32__) || defined(__MSDOS__)
401 const char *filename = "mesa.cnf";
402#else
403 const char *filename = "/etc/mesa.conf";
404#endif
405 FILE *file;
406 struct cnode *list;
407 int line = 1;
408 char *v;
409
410#if 0
411 int f;
412 struct stat statbuf;
413
414 if ((f = open(filename, O_RDONLY)) == -1)
415 return;
416
417 if (fstat( f, &statbuf ) == -1 ||
418 !S_ISREG( statbuf.st_mode ) ||
419 (file = fdopen(f, "r")) == 0)
420 {
421 close( f );
422 return;
423 }
424#endif
425
426 if ((file = fopen(filename, "r")) == 0)
427 return;
428
429 list = get_list( &line, file );
430 fclose( file );
431
432 if ((v = getenv("MESA_CONFIG")) != 0 && *v != 0) {
433 if (run_init( ctx, v, list )) {
434 free_list( list );
435 return;
436 }
437 else
438 fprintf(stderr, "No configuration '%s' in init file\n", v);
439 }
440
441
442 if (!run_init( ctx, default_config, list )) {
443 fprintf(stderr, "No default configuration '%s' in init file\n",
444 default_config);
445 }
446
447 free_list( list );
448}
449
450
Note: See TracBrowser for help on using the repository browser.