Home | History | Annotate | Line # | Download | only in config
      1 /*
      2  * Copyright 2002-2003 Red Hat Inc., Durham, North Carolina.
      3  *
      4  * All Rights Reserved.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining
      7  * a copy of this software and associated documentation files (the
      8  * "Software"), to deal in the Software without restriction, including
      9  * without limitation on the rights to use, copy, modify, merge,
     10  * publish, distribute, sublicense, and/or sell copies of the Software,
     11  * and to permit persons to whom the Software is furnished to do so,
     12  * subject to the following conditions:
     13  *
     14  * The above copyright notice and this permission notice (including the
     15  * next paragraph) shall be included in all copies or substantial
     16  * portions of the Software.
     17  *
     18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     19  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     21  * NON-INFRINGEMENT.  IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
     22  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
     23  * 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
     25  * SOFTWARE.
     26  */
     27 
     28 /*
     29  * Authors:
     30  *   Rickard E. (Rik) Faith <faith (at) redhat.com>
     31  *
     32  */
     33 
     34 /** \file
     35  * Provides interface for reading DMX configuration files and for
     36  * combining that information with command-line configuration parameters. */
     37 
     38 
     39 #ifdef HAVE_DMX_CONFIG_H
     40 #include <dmx-config.h>
     41 #endif
     42 
     43 #include "dmx.h"
     44 #include "dmxinput.h"
     45 #include "dmxconfig.h"
     46 #include "dmxparse.h"
     47 #include "dmxlog.h"
     48 #include "dmxcb.h"
     49 #include "dmxstat.h"
     50 #include "parser.h"
     51 
     52 extern int  yyparse(void);
     53 extern FILE *yyin;
     54 
     55 static char *dmxXkbRules;
     56 static char *dmxXkbModel;
     57 static char *dmxXkbLayout;
     58 static char *dmxXkbVariant;
     59 static char *dmxXkbOptions;
     60 
     61 /** Stores lists of configuration information. */
     62 typedef struct DMXConfigListStruct {
     63     const char                 *name;
     64     struct DMXConfigListStruct *next;
     65 } DMXConfigList, *DMXConfigListPtr;
     66 
     67 /** This stucture stores the parsed configuration information. */
     68 typedef struct DMXConfigCmdStruct {
     69     const char    *filename;
     70     const char    *config;
     71     DMXConfigList *displays;
     72     DMXConfigList *inputs;
     73     DMXConfigList *xinputs;
     74 } DMXConfigCmd, *DMXConfigCmdPtr;
     75 
     76 DMXConfigEntryPtr    dmxConfigEntry;
     77 static DMXConfigCmd  dmxConfigCmd;
     78 
     79 static int dmxDisplaysFromCommandLine;
     80 
     81 /** Make a note that \a display is the name of an X11 display that
     82  * should be initialized as a backend (output) display.  Called from
     83  * #ddxProcessArgument. */
     84 void dmxConfigStoreDisplay(const char *display)
     85 {
     86     DMXConfigListPtr entry = malloc(sizeof(*entry));
     87     entry->name = strdup(display);
     88     entry->next = NULL;
     89     if (!dmxConfigCmd.displays) dmxConfigCmd.displays = entry;
     90     else {
     91         DMXConfigList *pt;
     92         for (pt = dmxConfigCmd.displays; pt->next; pt = pt->next);
     93         if (!pt)
     94             dmxLog(dmxFatal, "dmxConfigStoreDisplay: end of list non-NULL\n");
     95         pt->next = entry;
     96     }
     97     ++dmxDisplaysFromCommandLine;
     98 }
     99 
    100 /** Make a note that \a input is the name of an X11 display that should
    101  * be used for input (either a backend or a console input device). */
    102 void dmxConfigStoreInput(const char *input)
    103 {
    104     DMXConfigListPtr entry = malloc(sizeof(*entry));
    105     entry->name = strdup(input);
    106     entry->next = NULL;
    107     if (!dmxConfigCmd.inputs) dmxConfigCmd.inputs = entry;
    108     else {
    109         DMXConfigList *pt;
    110         for (pt = dmxConfigCmd.inputs; pt->next; pt = pt->next);
    111         if (!pt)
    112             dmxLog(dmxFatal, "dmxConfigStoreInput: end of list non-NULL\n");
    113         pt->next = entry;
    114     }
    115 }
    116 
    117 /** Make a note that \a input is the name of an X11 display that should
    118  * be used for input from XInput extension devices. */
    119 void dmxConfigStoreXInput(const char *input)
    120 {
    121     DMXConfigListPtr entry = malloc(sizeof(*entry));
    122     entry->name = strdup(input);
    123     entry->next = NULL;
    124     if (!dmxConfigCmd.xinputs) dmxConfigCmd.xinputs = entry;
    125     else {
    126         DMXConfigList *pt;
    127         for (pt = dmxConfigCmd.xinputs; pt->next; pt = pt->next);
    128         if (!pt)
    129             dmxLog(dmxFatal, "dmxConfigStoreXInput: end of list non-NULL\n");
    130         pt->next = entry;
    131     }
    132 }
    133 
    134 /** Make a note that \a file is the configuration file. */
    135 void dmxConfigStoreFile(const char *file)
    136 {
    137     if (dmxConfigCmd.filename)
    138         dmxLog(dmxFatal, "Only one -configfile allowed\n");
    139     dmxConfigCmd.filename = strdup(file);
    140 }
    141 
    142 /** Make a note that \a config should be used as the configuration for
    143  * current instantiation of the DMX server. */
    144 void dmxConfigStoreConfig(const char *config)
    145 {
    146     if (dmxConfigCmd.config) dmxLog(dmxFatal, "Only one -config allowed\n");
    147     dmxConfigCmd.config = strdup(config);
    148 }
    149 
    150 static int dmxConfigReadFile(const char *filename, int debug)
    151 {
    152     FILE *str;
    153 
    154     if (!(str = fopen(filename, "r"))) return -1;
    155     dmxLog(dmxInfo, "Reading configuration file \"%s\"\n", filename);
    156     yyin    = str;
    157     yydebug = debug;
    158     yyparse();
    159     fclose(str);
    160     return 0;
    161 }
    162 
    163 static const char *dmxConfigMatch(const char *target, DMXConfigEntryPtr entry)
    164 {
    165     DMXConfigVirtualPtr v     = entry->virtual;
    166     const char          *name = NULL;
    167 
    168     if (v && v->name) name = v->name;
    169 
    170     if (v && !dmxConfigCmd.config) return v->name ? v->name : "<noname>";
    171     if (!name)                     return NULL;
    172     if (!strcmp(name, target))     return name;
    173     return NULL;
    174 }
    175 
    176 static DMXScreenInfo *dmxConfigAddDisplay(const char *name,
    177                                           int scrnWidth,   int scrnHeight,
    178                                           int scrnX,       int scrnY,
    179                                           int scrnXSign,   int scrnYSign,
    180                                           int rootWidth,   int rootHeight,
    181                                           int rootX,       int rootY,
    182                                           int rootXSign,   int rootYSign)
    183 {
    184     DMXScreenInfo *dmxScreen;
    185 
    186     if (!(dmxScreens = realloc(dmxScreens,
    187                                (dmxNumScreens+1) * sizeof(*dmxScreens))))
    188         dmxLog(dmxFatal,
    189                "dmxConfigAddDisplay: realloc failed for screen %d (%s)\n",
    190                dmxNumScreens, name);
    191 
    192     dmxScreen = &dmxScreens[dmxNumScreens];
    193     memset(dmxScreen, 0, sizeof(*dmxScreen));
    194     dmxScreen->name       = name;
    195     dmxScreen->index      = dmxNumScreens;
    196     dmxScreen->scrnWidth  = scrnWidth;
    197     dmxScreen->scrnHeight = scrnHeight;
    198     dmxScreen->scrnX      = scrnX;
    199     dmxScreen->scrnY      = scrnY;
    200     dmxScreen->scrnXSign  = scrnXSign;
    201     dmxScreen->scrnYSign  = scrnYSign;
    202     dmxScreen->rootWidth  = rootWidth;
    203     dmxScreen->rootHeight = rootHeight;
    204     dmxScreen->rootX      = rootX;
    205     dmxScreen->rootY      = rootY;
    206     dmxScreen->stat       = dmxStatAlloc();
    207     ++dmxNumScreens;
    208     return dmxScreen;
    209 }
    210 
    211 DMXInputInfo *dmxConfigAddInput(const char *name, int core)
    212 {
    213     DMXInputInfo *dmxInput;
    214 
    215     if (!(dmxInputs = realloc(dmxInputs,
    216                               (dmxNumInputs+1) * sizeof(*dmxInputs))))
    217         dmxLog(dmxFatal,
    218                "dmxConfigAddInput: realloc failed for input %d (%s)\n",
    219                dmxNumInputs, name);
    220 
    221     dmxInput = &dmxInputs[dmxNumInputs];
    222 
    223     memset(dmxInput, 0, sizeof(*dmxInput));
    224     dmxInput->name     = name;
    225     dmxInput->inputIdx = dmxNumInputs;
    226     dmxInput->scrnIdx  = -1;
    227     dmxInput->core     = core;
    228     ++dmxNumInputs;
    229     return dmxInput;
    230 }
    231 
    232 static void dmxConfigCopyFromDisplay(DMXConfigDisplayPtr d)
    233 {
    234     DMXScreenInfo *dmxScreen;
    235 
    236     dmxScreen         = dmxConfigAddDisplay(d->name,
    237                                             d->scrnWidth, d->scrnHeight,
    238                                             d->scrnX,     d->scrnY,
    239                                             d->scrnXSign, d->scrnYSign,
    240                                             d->rootWidth, d->rootHeight,
    241                                             d->rootX,     d->rootY,
    242                                             d->rootXSign, d->rootXSign);
    243     dmxScreen->where  = PosAbsolute;
    244     dmxScreen->whereX = d->rootXOrigin;
    245     dmxScreen->whereY = d->rootYOrigin;
    246 }
    247 
    248 static void dmxConfigCopyFromWall(DMXConfigWallPtr w)
    249 {
    250     DMXConfigStringPtr pt;
    251     DMXScreenInfo      *dmxScreen;
    252     int                edge = dmxNumScreens;
    253     int                last = dmxNumScreens;
    254 
    255     if (!w->xwall && !w->ywall) { /* Try to make it square */
    256         int count;
    257         for (pt = w->nameList, count = 0; pt; pt = pt->next) ++count;
    258         w->xwall = sqrt(count) + .5;
    259     }
    260 
    261     for (pt = w->nameList; pt; pt = pt->next) {
    262         dmxScreen = dmxConfigAddDisplay(pt->string, w->width, w->height,
    263                                         0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
    264         if (pt == w->nameList) { /* Upper left */
    265             dmxScreen->where  = PosAbsolute;
    266             dmxScreen->whereX = 0;
    267             dmxScreen->whereY = 0;
    268         } else if (w->xwall) {  /* Tile left to right, then top to bottom */
    269             if (!((dmxNumScreens-1) % w->xwall)) {
    270                 dmxScreen->where          = PosBelow;
    271                 dmxScreen->whereRefScreen = edge;
    272                 edge                      = dmxNumScreens-1;
    273             } else {
    274                 dmxScreen->where          = PosRightOf;
    275                 dmxScreen->whereRefScreen = last;
    276             }
    277         } else {                /* Tile top to bottom, then left to right */
    278             if (!((dmxNumScreens-1) % w->ywall)) {
    279                 dmxScreen->where          = PosRightOf;
    280                 dmxScreen->whereRefScreen = edge;
    281                 edge                      = dmxNumScreens-1;
    282             } else {
    283                 dmxScreen->where          = PosBelow;
    284                 dmxScreen->whereRefScreen = last;
    285             }
    286 
    287         }
    288         last = dmxNumScreens-1;
    289         if (dmxScreen->where == PosAbsolute)
    290             dmxLog(dmxInfo, "Added %s at %d %d\n",
    291                    pt->string, dmxScreen->whereX, dmxScreen->whereY);
    292         else
    293             dmxLog(dmxInfo, "Added %s %s %s\n",
    294                    pt->string,
    295                    dmxScreen->where == PosBelow ? "below" : "right of",
    296                    dmxScreens[dmxScreen->whereRefScreen].name);
    297     }
    298 }
    299 
    300 static void dmxConfigCopyFromOption(DMXConfigOptionPtr o)
    301 {
    302     DMXConfigStringPtr pt;
    303     int                argc   = 0;
    304     char               **argv = NULL;
    305 
    306     if (serverGeneration != 1) return; /* FIXME: only do once, for now */
    307     if (!o || !o->string) return;
    308     for (pt = o->option; pt; pt = pt->next) {
    309         if (pt->string) {
    310             ++argc;
    311             argv = realloc(argv, (argc+1) * sizeof(*argv));
    312             argv[argc] = (char *)pt->string;
    313         }
    314     }
    315     argv[0] = NULL;
    316     ProcessCommandLine(argc+1, argv);
    317     free(argv);
    318 }
    319 
    320 static void dmxConfigCopyFromParam(DMXConfigParamPtr p)
    321 {
    322     const char **argv;
    323     int        argc;
    324 
    325     if ((argv = dmxConfigLookupParam(p, "xkbrules", &argc)) && argc == 2) {
    326         dmxConfigSetXkbRules(argv[1]);
    327     } else if ((argv = dmxConfigLookupParam(p, "xkbmodel", &argc))
    328                && argc == 2) {
    329         dmxConfigSetXkbModel(argv[1]);
    330     } else if ((argv = dmxConfigLookupParam(p, "xkblayout", &argc))
    331                && argc == 2) {
    332         dmxConfigSetXkbLayout(argv[1]);
    333     } else if ((argv = dmxConfigLookupParam(p, "xkbvariant", &argc))
    334                && argc == 2) {
    335         dmxConfigSetXkbVariant(argv[1]);
    336     } else if ((argv = dmxConfigLookupParam(p, "xkboptions", &argc))
    337                && argc == 2) {
    338         dmxConfigSetXkbOptions(argv[1]);
    339     }
    340 }
    341 
    342 static void dmxConfigCopyData(DMXConfigVirtualPtr v)
    343 {
    344     DMXConfigSubPtr sub;
    345 
    346     if (v->dim) dmxSetWidthHeight(v->dim->x, v->dim->y);
    347     else        dmxSetWidthHeight(0, 0);
    348     for (sub = v->subentry; sub; sub = sub->next) {
    349         switch (sub->type) {
    350         case dmxConfigDisplay: dmxConfigCopyFromDisplay(sub->display); break;
    351         case dmxConfigWall:    dmxConfigCopyFromWall(sub->wall);       break;
    352         case dmxConfigOption:  dmxConfigCopyFromOption(sub->option);   break;
    353         case dmxConfigParam:   dmxConfigCopyFromParam(sub->param);     break;
    354         default:
    355             dmxLog(dmxFatal,
    356                    "dmxConfigCopyData: not a display, wall, or value\n");
    357         }
    358     }
    359 }
    360 
    361 static void dmxConfigFromCommandLine(void)
    362 {
    363     DMXConfigListPtr pt;
    364 
    365     dmxLog(dmxInfo, "Using configuration from command line\n");
    366     for (pt = dmxConfigCmd.displays; pt; pt = pt->next) {
    367         DMXScreenInfo *dmxScreen = dmxConfigAddDisplay(pt->name,
    368                                                        0, 0, 0, 0, 0, 0,
    369                                                        0, 0, 0, 0, 0, 0);
    370         if (dmxNumScreens == 1) {
    371             dmxScreen->where  = PosAbsolute;
    372             dmxScreen->whereX = 0;
    373             dmxScreen->whereY = 0;
    374             dmxLog(dmxInfo, "Added %s at %d %d\n",
    375                    dmxScreen->name, dmxScreen->whereX, dmxScreen->whereY);
    376         } else {
    377             dmxScreen->where          = PosRightOf;
    378             dmxScreen->whereRefScreen = dmxNumScreens - 2;
    379             if (dmxScreen->whereRefScreen < 0) dmxScreen->whereRefScreen = 0;
    380             dmxLog(dmxInfo, "Added %s %s %s\n",
    381                    dmxScreen->name,
    382                    dmxScreen->where == PosBelow ? "below" : "right of",
    383                    dmxScreens[dmxScreen->whereRefScreen].name);
    384         }
    385     }
    386 }
    387 
    388 static void dmxConfigFromConfigFile(void)
    389 {
    390     DMXConfigEntryPtr pt;
    391     const char        *name;
    392 
    393     for (pt = dmxConfigEntry; pt; pt = pt->next) {
    394                                 /* FIXME -- if an input is specified, use it */
    395         if (pt->type != dmxConfigVirtual) continue;
    396         if ((name = dmxConfigMatch(dmxConfigCmd.config, pt))) {
    397             dmxLog(dmxInfo, "Using configuration \"%s\"\n", name);
    398             dmxConfigCopyData(pt->virtual);
    399             return;
    400         }
    401     }
    402     dmxLog(dmxFatal, "Could not find configuration \"%s\" in \"%s\"\n",
    403            dmxConfigCmd.config, dmxConfigCmd.filename);
    404 }
    405 
    406 static void dmxConfigConfigInputs(void)
    407 {
    408     DMXConfigListPtr pt;
    409 
    410     if (dmxNumInputs) return;
    411 
    412     if (dmxConfigCmd.inputs) {   /* Use command line */
    413         for (pt = dmxConfigCmd.inputs; pt; pt = pt->next)
    414             dmxConfigAddInput(pt->name, TRUE);
    415     } else if (dmxNumScreens) { /* Use first display */
    416         dmxConfigAddInput(dmxScreens[0].name, TRUE);
    417     } else {                     /* Use dummy */
    418         dmxConfigAddInput("dummy", TRUE);
    419     }
    420 
    421     if (dmxConfigCmd.xinputs) {  /* Non-core devices from command line */
    422         for (pt = dmxConfigCmd.xinputs; pt; pt = pt->next)
    423             dmxConfigAddInput(pt->name, FALSE);
    424     }
    425 }
    426 
    427 /** Set up the appropriate global variables so that the DMX server will
    428  * be initialized using the configuration specified in the config file
    429  * and on the command line. */
    430 void dmxConfigConfigure(void)
    431 {
    432     if (dmxConfigEntry) {
    433         dmxConfigFreeEntry(dmxConfigEntry);
    434         dmxConfigEntry = NULL;
    435     }
    436     if (dmxConfigCmd.filename) {
    437         if (dmxConfigCmd.displays)
    438             dmxLog(dmxWarning,
    439                    "Using configuration file \"%s\" instead of command line\n",
    440                    dmxConfigCmd.filename);
    441         dmxConfigReadFile(dmxConfigCmd.filename, 0);
    442         dmxConfigFromConfigFile();
    443     } else {
    444         if (dmxConfigCmd.config)
    445             dmxLog(dmxWarning,
    446                    "Configuration name (%s) without configuration file\n",
    447                    dmxConfigCmd.config);
    448         dmxConfigFromCommandLine();
    449     }
    450     dmxConfigConfigInputs();
    451 }
    452 
    453 /** This function determines the number of displays we WILL have and
    454  * sets MAXSCREENS to that value.  This is difficult since the number
    455  * depends on the command line (which is easy to count) or on the config
    456  * file, which has to be parsed. */
    457 void dmxConfigSetMaxScreens(void)
    458 {
    459     static int processing = 0;
    460 
    461     if (processing) return;     /* Prevent reentry via ProcessCommandLine */
    462     processing = 1;
    463     if (dmxConfigCmd.filename) {
    464         if (!dmxNumScreens)
    465             dmxConfigConfigure();
    466 #ifndef MAXSCREENS
    467         SetMaxScreens(dmxNumScreens);
    468 #endif
    469     } else
    470 #ifndef MAXSCREENS
    471         SetMaxScreens(dmxDisplaysFromCommandLine);
    472 #endif
    473     processing = 0;
    474 }
    475 
    476 /** This macro is used to generate the following access methods:
    477  * - dmxConfig{Set,Get}rules
    478  * - dmxConfig{Set,Get}model
    479  * - dmxConfig{Set,Get}layout
    480  * - dmxConfig{Set,Get}variant
    481  * - dmxConfig{Set,Get}options
    482  * These methods are used to read and write information about the keyboard. */
    483 
    484 #define GEN(param,glob,def)                                                   \
    485  void dmxConfigSet##glob(const char *param) {                                 \
    486      if (dmx##glob) free((void *)dmx##glob);                                  \
    487      dmx##glob = strdup(param);                                               \
    488  }                                                                            \
    489  char *dmxConfigGet##glob(void) {                                             \
    490      return (char *)(dmx##glob ? dmx##glob : def);                            \
    491  }
    492 
    493 GEN(rules,   XkbRules,   XKB_DFLT_RULES)
    494 GEN(model,   XkbModel,   XKB_DFLT_MODEL)
    495 GEN(layout,  XkbLayout,  XKB_DFLT_LAYOUT)
    496 GEN(variant, XkbVariant, XKB_DFLT_VARIANT)
    497 GEN(options, XkbOptions, XKB_DFLT_OPTIONS)
    498