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

Last change on this file since 2962 was 2938, checked in by sandervl, 25 years ago

created

File size: 10.7 KB
Line 
1/* $Id: config.c,v 1.1 2000-02-29 00:50:00 sandervl Exp $ */
2
3/*
4 * Mesa 3-D graphics library
5 * Version: 3.1
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#ifndef XFree86Server
35#include <stdio.h>
36#include <stdlib.h>
37#include <ctype.h>
38#else
39#include "GL/xf86glx.h"
40#endif
41
42#include "enums.h"
43#include "config.h"
44#include "types.h"
45#include "extensions.h"
46#include "simple_list.h"
47#include "glmisc.h"
48
49typedef enum { nil_t, list_t, word_t } node_type;
50
51struct cnode {
52 node_type type;
53 int line;
54 union {
55 struct { struct cnode *head, *tail; } l;
56 struct { char *text; } w;
57 } data;
58};
59
60/* Pretty printer for debugging.
61 */
62static void pad(int n) { putchar('\n'); while(n--) putchar(' '); }
63
64static void print_list( struct cnode *n, int indent )
65{
66 int i = 0;
67 printf("( ");
68 while (n->type == list_t) {
69 if (i++ > 0) pad(indent + 2);
70 switch (n->data.l.head->type) {
71 case list_t:
72 print_list( n->data.l.head, indent + 2 );
73 break;
74 case word_t:
75 printf( n->data.l.head->data.w.text );
76 break;
77 case nil_t:
78 printf("()");
79 break;
80 default:
81 puts("***");
82 }
83 n = n->data.l.tail;
84 }
85 printf(" )");
86}
87
88
89
90/* Accessors to query the contents of a cnode.
91 */
92static int is_list( struct cnode *x, struct cnode **h, struct cnode **t)
93{
94 if (x->type == list_t) {
95 struct cnode *tmp = x;
96 *h = tmp->data.l.head;
97 *t = tmp->data.l.tail;
98 return 1;
99 }
100 return 0;
101}
102
103static int is_nil( const struct cnode *x )
104{
105 return x->type == nil_t;
106}
107
108static int is_word( struct cnode *x, const char **s )
109{
110 if (x->type == word_t) {
111 *s = x->data.w.text;
112 return 1;
113 }
114 return 0;
115}
116
117static int match_word( struct cnode *x, const char *s )
118{
119 if (x->type == word_t)
120 return strcmp(s, x->data.w.text) == 0;
121 return 0;
122}
123
124/* Build the parsed expression.
125 */
126static void skip_comment( FILE *file )
127{
128 int c;
129 while ((c = getc(file)) != EOF && c != '\n') {};
130 ungetc( c, file );
131}
132
133
134static struct cnode *get_word( int line, FILE *file )
135{
136 int sz = 16, len = 0;
137 char *text = (char *) MALLOC( sz * sizeof(char) );
138
139 while (1) {
140 int c = getc(file);
141 if (len == sz)
142 text = (char *) realloc( text, sizeof(char) * (sz *= 2) );
143 if (c == EOF || isspace(c) || c == ')') {
144 struct cnode *n = MALLOC_STRUCT(cnode);
145 ungetc(c, file);
146 text[len] = 0;
147 n->type = word_t;
148 n->line = line;
149 n->data.w.text = text;
150 return n;
151 }
152 else
153 text[len++] = c;
154 }
155}
156
157static struct cnode *get_list( int *line, FILE *file )
158{
159 struct cnode *head, **current = &head;
160 head = MALLOC_STRUCT(cnode);
161 head->line = *line;
162 head->type = nil_t;
163
164 while (1) {
165 struct cnode *n = 0;
166 int c = getc(file);
167
168 switch (c) {
169 case EOF: return head;
170 case ')': return head;
171 case ';': skip_comment( file ); continue;
172 case '\n': (*line)++; continue;
173 case '(':
174 n = get_list( line, file );
175 break;
176 default:
177 if (isspace(c)) continue;
178 ungetc(c, file);
179 n = get_word( *line, file );
180 break;
181 }
182
183 (*current)->type = list_t;
184 (*current)->data.l.head = n;
185 current = &(*current)->data.l.tail;
186 (*current) = MALLOC_STRUCT(cnode);
187 (*current)->line = *line;
188 (*current)->type = nil_t;
189 }
190}
191
192/* Execute it.
193 */
194static void error( struct cnode *n, const char *err )
195{
196 printf("Error in init file, line %d: %s\n", n->line, err );
197}
198
199static void disable_extension( GLcontext *ctx, struct cnode *args )
200{
201 struct cnode *head, *tail;
202 const char *c;
203
204 if (is_list(args, &head, &tail) &&
205 is_nil(tail) &&
206 is_word(head, &c))
207 {
208 if (gl_extensions_disable( ctx, c ) != 0)
209 error( head, "unknown extension" );
210 }
211 else
212 error( args, "bad args for disable-extension" );
213}
214
215
216static void default_hint( GLcontext *ctx, struct cnode *args )
217{
218 struct cnode *hint, *tail, *value;
219 const char *hname, *vname;
220 GLenum h, v;
221
222 if (is_list(args, &hint, &tail) &&
223 is_list(tail, &value, &tail) &&
224 is_nil(tail) &&
225 is_word(hint, &hname) &&
226 is_word(value, &vname))
227 {
228 if ((h = (GLenum) gl_lookup_enum_by_name(hname)) != -1 &&
229 (v = (GLenum) gl_lookup_enum_by_name(vname)) != -1)
230 {
231 printf("calling glHint(%s=%d, %s=%d)\n", hname, h, vname, v);
232 if (!gl_Hint( ctx, h, v ))
233 error( hint, "glHint failed");
234 printf("allow draw mem: %d\n", ctx->Hint.AllowDrawMem);
235 return;
236 }
237 else
238 error( hint, "unknown or illegal value for default-hint" );
239 }
240 else
241 error( args, "bad args for default-hint" );
242}
243
244/* Use the general-purpose set-variable
245 */
246static void fx_catch_signals( GLcontext *ctx, struct cnode *args )
247{
248 struct cnode *head, *tail;
249 const char *value;
250
251/* error( args, */
252/* "fx-catch-signals deprecated, use " */
253/* "(set-variable fx-catch-signals ...) instead"); */
254
255 if (is_list(args, &head, &tail) &&
256 is_nil(tail) &&
257 is_word(head, &value)) {
258 if (strcmp(value, "false") == 0)
259 ctx->CatchSignals = GL_FALSE;
260 else if (strcmp(value, "true") == 0)
261 ctx->CatchSignals = GL_TRUE;
262 else
263 error( args, "expected 'true' or 'false'" );
264 }
265 else {
266 error( args, "bad args for fx-catch-signal" );
267 }
268}
269
270/* Well, should these also check the environment?
271 * Should environment vars override config vars?
272 */
273
274struct var {
275 struct var *next, *prev;
276 const char *name;
277 void (*notify)(const char *value, int line);
278};
279
280static struct var varlist = { &varlist, &varlist, 0, 0 };
281
282static void set_var( GLcontext *ctx, struct cnode *args )
283{
284 struct var *v;
285 struct cnode *head, *tail;
286 const char *variable, *value;
287
288 if (is_list(args, &head, &tail) &&
289 is_word(head, &variable) &&
290 is_list(tail, &head, &tail) &&
291 is_word(head, &value) &&
292 is_nil(tail))
293 {
294 foreach(v, &varlist) {
295 if (strcmp(v->name, variable) == 0) {
296 v->notify(value, head->line);
297 return;
298 }
299 }
300
301 error( head, "unknown variable" );
302 }
303 else {
304 error( args, "bad format for (set VARIABLE VALUE)" );
305 }
306}
307
308void gl_register_config_var(const char *name,
309 void (*notify)( const char *, int ))
310{
311 struct var *v = MALLOC_STRUCT(var);
312 v->name = name;
313 v->notify = notify;
314 insert_at_tail( &varlist, v );
315}
316
317
318static void do_init( GLcontext *ctx, struct cnode *list )
319{
320 struct cnode *head, *tail, *func, *args;
321
322 if (is_list(list, &head, &tail) && is_nil(tail)) {
323 list = head;
324 while (is_list(list, &head, &list)) {
325 if (is_list(head, &func, &args)) {
326 if (match_word(func, "disable-extension"))
327 disable_extension( ctx, args );
328 else if (match_word(func, "default-hint"))
329 default_hint( ctx, args );
330 else if (match_word(func, "fx-catch-signals"))
331 fx_catch_signals( ctx, args );
332 else if (match_word(func, "set-variable"))
333 set_var( ctx, args );
334 else
335 error( func, "unknown configuration method" );
336 }
337 }
338 }
339 else if (!is_nil(list)) {
340 error( list, "configurations must form a list" );
341 }
342}
343
344static int run_init( GLcontext *ctx, const char *version, struct cnode *list )
345{
346 struct cnode *head, *arg1, *arg2;
347 const char *v;
348
349 /* Uses the first matching init list.
350 */
351 while (is_list(list, &head, &list))
352 if (is_list(head, &arg1, &head) &&
353 is_list(head, &arg2, &head) &&
354 match_word(arg1, "config-mesa") &&
355 is_word(arg2, &v))
356 {
357 if (strcmp(v, version) == 0) {
358 do_init( ctx, head );
359 return 1;
360 }
361 }
362 else
363 error( head, "malformed toplevel configuration" );
364
365 return 0;
366}
367
368
369
370static void free_list( struct cnode *n )
371{
372 while (n->type == list_t) {
373 struct cnode *tmp = n;
374 switch (n->data.l.head->type) {
375 case list_t:
376 free_list( n->data.l.head );
377 break;
378 case word_t:
379 FREE( n->data.l.head->data.w.text );
380 FREE( n->data.l.head );
381 break;
382 case nil_t:
383 FREE( n->data.l.head );
384 break;
385 default:
386 return;
387 }
388 n = n->data.l.tail;
389 FREE( tmp );
390 }
391 FREE( n );
392}
393
394
395
396
397/* How paranoid do you have to be when reading a config file? I don't
398 * know half the ways to exploit this stuff, and given that this may
399 * be run with root access, I think we're better off hardcoding the
400 * pathname. Some clever joe can fix this later if they care.
401 */
402void gl_read_config_file( GLcontext *ctx )
403{
404 const char *default_config = "mesa3.1";
405
406#if defined(__WIN32__) || defined(__MSDOS__)
407 const char *filename = "mesa.cnf";
408#else
409 const char *filename = "/etc/mesa.conf";
410#endif
411 FILE *file;
412 struct cnode *list;
413 int line = 1;
414 char *v;
415
416#if 0
417 int f;
418 struct stat statbuf;
419
420 if ((f = open(filename, O_RDONLY)) == -1)
421 return;
422
423 if (fstat( f, &statbuf ) == -1 ||
424 !S_ISREG( statbuf.st_mode ) ||
425 (file = fdopen(f, "r")) == 0)
426 {
427 close( f );
428 return;
429 }
430#endif
431
432 if ((file = fopen(filename, "r")) == 0)
433 return;
434
435 list = get_list( &line, file );
436 fclose( file );
437
438 if ((v = getenv("MESA_CONFIG")) != 0 && *v != 0) {
439 if (run_init( ctx, v, list )) {
440 free_list( list );
441 return;
442 }
443 else
444 fprintf(stderr, "No configuration '%s' in init file\n", v);
445 }
446
447
448 if (!run_init( ctx, default_config, list )) {
449 fprintf(stderr, "No default configuration '%s' in init file\n",
450 default_config);
451 }
452
453 free_list( list );
454}
455
456
Note: See TracBrowser for help on using the repository browser.