home *** CD-ROM | disk | FTP | other *** search
/ Amiga Magazin: Amiga-CD 2000 April & May / AMIGA_2000_04.iso / patches / mesa3.1 / mesa-3_1.lha / src / config.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-01-07  |  10.6 KB  |  457 lines

  1. /* $Id: config.c,v 1.6.2.1 1999/12/13 22:03:30 brianp 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. #include "enums.h"
  42. #include "config.h"
  43. #include "types.h"
  44. #include "extensions.h"
  45. #include "simple_list.h"
  46. #include "glmisc.h"
  47.  
  48.  
  49. typedef enum { nil_t, list_t, word_t } node_type;
  50.  
  51. struct 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.  */
  62. static void pad(int n) { putchar('\n'); while(n--) putchar(' '); }
  63.  
  64. static 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.  */
  92. static 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.  
  103. static int is_nil( const struct cnode *x ) 
  104. {
  105.    return x->type == nil_t;
  106. }
  107.  
  108. static 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.  
  117. static 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.  */
  126. static void skip_comment( FILE *file )
  127. {
  128.    int c;
  129.    while ((c = getc(file)) != EOF && c != '\n') {};
  130.    ungetc( c, file );
  131. }
  132.  
  133.  
  134. static 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.  
  157. static 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.  */
  194. static void error( struct cnode *n, const char *err )
  195. {
  196.    printf("Error in init file, line %d: %s\n", n->line, err );
  197. }
  198.  
  199. static 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.  
  216. static 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.  */
  246. static 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.  
  274. struct var {
  275.    struct var *next, *prev;
  276.    const char *name;
  277.    void (*notify)(const char *value, int line);
  278. };
  279.  
  280. static struct var varlist = { &varlist, &varlist, 0, 0 };
  281.  
  282. static 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.  
  308. void 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.  
  318. static 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.  
  344. static 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.  
  370. static 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.  */
  402. void 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.  
  457.