/* $XFree86: xc/programs/Xserver/hw/xfree86/common/xf86Config.c,v 3.292 2006/03/16 16:49:55 dawes Exp $ */


/*
 * Loosely based on code bearing the following copyright:
 *
 *   Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
 */

/*
 * Copyright (c) 1992-2006 by The XFree86 Project, Inc.
 * All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject
 * to the following conditions:
 *
 *   1.  Redistributions of source code must retain the above copyright
 *       notice, this list of conditions, and the following disclaimer.
 *
 *   2.  Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer
 *       in the documentation and/or other materials provided with the
 *       distribution, and in the same place and form as other copyright,
 *       license and disclaimer information.
 *
 *   3.  The end-user documentation included with the redistribution,
 *       if any, must include the following acknowledgment: "This product
 *       includes software developed by The XFree86 Project, Inc
 *       (http://www.xfree86.org/) and its contributors", in the same
 *       place and form as other third-party acknowledgments.  Alternately,
 *       this acknowledgment may appear in the software itself, in the
 *       same form and location as other such third-party acknowledgments.
 *
 *   4.  Except as contained in this notice, the name of The XFree86
 *       Project, Inc shall not be used in advertising or otherwise to
 *       promote the sale, use or other dealings in this Software without
 *       prior written authorization from The XFree86 Project, Inc.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE XFREE86 PROJECT, INC OR ITS CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
/*
 * Copyright 1997 by Metro Link, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 * Except as contained in this notice, the name of the copyright holder(s)
 * and author(s) shall not be used in advertising or otherwise to promote
 * the sale, use or other dealings in this Software without prior written
 * authorization from the copyright holder(s) and author(s).
 */
/*
 * Copyright © 2003, 2004, 2005 David H. Dawes.
 * Copyright © 2003, 2004, 2005 X-Oz Technologies.
 * All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 * 
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions, and the following disclaimer.
 *
 *  2. Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 * 
 *  3. The end-user documentation included with the redistribution,
 *     if any, must include the following acknowledgment: "This product
 *     includes software developed by X-Oz Technologies
 *     (http://www.x-oz.com/)."  Alternately, this acknowledgment may
 *     appear in the software itself, if and wherever such third-party
 *     acknowledgments normally appear.
 *
 *  4. Except as contained in this notice, the name of X-Oz
 *     Technologies shall not be used in advertising or otherwise to
 *     promote the sale, use or other dealings in this Software without
 *     prior written authorization from X-Oz Technologies.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL X-OZ TECHNOLOGIES OR ITS CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 */

/*
 *
 * Authors:
 *	Dirk Hohndel <hohndel@XFree86.Org>
 *	David Dawes <dawes@XFree86.Org>
 *      Marc La France <tsi@XFree86.Org>
 *      Egbert Eich <eich@XFree86.Org>
 *      ... and others
 */

#include <sys/types.h>
#include <grp.h>

#ifdef __UNIXOS2__
#define I_NEED_OS2_H
#endif

#include "xf86.h"
#include "xf86Parser.h"
#include "xf86tokens.h"
#include "xf86Config.h"
#include "xf86Priv.h"
#include "xf86_OSlib.h"

#include "globals.h"

#ifdef XKB
#define XKB_IN_SERVER
#include <X11/extensions/XKBsrv.h>
#endif

#ifdef RENDER
#include "picture.h"
#endif

#if (defined(i386) || defined(__i386__)) && \
    (defined(__FreeBSD__) || defined(__NetBSD__) || defined(linux) || \
     (defined(SVR4) && !defined(sun)) || defined(__GNU__))
#define SUPPORT_PC98
#endif

/*
 * These paths define the way the config file search is done.  The escape
 * sequences are documented in parser/scan.c.
 */
#ifndef ROOT_CONFIGPATH
#define ROOT_CONFIGPATH	"%A," "%R," \
			"/etc/X11/%R," "%P/etc/X11/%R," \
			"%E," "%F," \
			"/etc/X11/%F," "%P/etc/X11/%F," \
			"%D/%X," \
			"/etc/X11/%X-%M," "/etc/X11/%X," "/etc/%X," \
			"%P/etc/X11/%X.%H," "%P/etc/X11/%X-%M," \
			"%P/etc/X11/%X," \
			"%P/lib/X11/%X.%H," "%P/lib/X11/%X-%M," \
			"%P/lib/X11/%X"
#endif
#ifndef USER_CONFIGPATH
#define USER_CONFIGPATH	"/etc/X11/%S," "%P/etc/X11/%S," \
			"/etc/X11/%G," "%P/etc/X11/%G," \
			"/etc/X11/%X-%M," "/etc/X11/%X," "/etc/%X," \
			"%P/etc/X11/%X.%H," "%P/etc/X11/%X-%M," \
			"%P/etc/X11/%X," \
			"%P/lib/X11/%X.%H," "%P/lib/X11/%X-%M," \
			"%P/lib/X11/%X"
#endif
#ifndef PROJECTROOT
#define PROJECTROOT	"/usr/X11R6"
#endif

/* Forward declarations */
static MonPtr convertMonitor(MonPtr pMonitor,
			     const XF86ConfMonitorRec *confMonitor);
static IDevPtr convertInputDevice(IDevPtr input,
				  const XF86ConfInputRec *confInput);
static DispPtr convertDisplay(DispPtr pDisplay,
			      const XF86ConfDisplayRec *confDisplay);
static confModulesPtr convertModules(confModulesPtr modules,
					 const XF86ConfModuleRec* confModules);
static Bool addDefaultModes(MonPtr pMonitor);
static confDRIPtr configDRI(ConfigHandle handle, const XF86ConfDRIRec *driConf,
			    MessageType from);
static const confXvAdaptorRec *getNextActiveXvAdaptor(ConfigDataHandle prev);
static const confScreenRec *getNextActiveScreen(ConfigDataHandle prev);

static void
xf86ConfigError(const char *msg, ...)
{
    va_list ap;

    ErrorF("\nConfig Error:\n");
    va_start(ap, msg);
    VErrorF(msg, ap);
    va_end(ap);
    ErrorF("\n");
    return;
}

static const XF86ConfigRec *
ConfigHandleToConfigRead(ConfigHandle handle)
{
    /* For now, effectively ignore the pseudo handles. */
    if (handle == DEFAULT_CONFIG ||
	handle == CMDLINE_CONFIG || handle == BUILDTIME_CONFIG ||
	handle == ACTIVE_CONFIG)
	return xf86Info.config;
    else
	return handle;
}

#ifdef NOTYET
static XF86ConfigPtr
ConfigHandleToConfigWrite(ConfigHandle handle)
{
    if (handle == DEFAULT_CONFIG)
	return (XF86ConfigPtr)xf86Info.config;
    else
	return (XF86ConfigPtr)handle;
}
#endif

static void
xf86FreeStringArray(char **s, int n)
{
    int i;

    if (!s)
	return;

    for (i = 0; i < n; i++) {
	xfree(s[i]);
	s[i] = NULL;
    }
    xfree(s);
}

static char **
xf86DupStringArray(char **src, int n)
{
    int i;

    char **dst;

    if (n < 1)
	return NULL;

    dst = xcalloc(n, sizeof(*dst));
    if (!dst)
	return NULL;

    for (i = 0; i < n; i++) {
	dst[i] = xstrdup(src[i]);
	if (src[i] && !dst[i]) {
	    xf86FreeStringArray(dst, n);
	    return NULL;
	}
    }
    return dst;
}

confLoadModulePtr
xf86ConfAllocLoadModule()
{
    confLoadModulePtr pLoad;

    pLoad = xcalloc(1, sizeof(*pLoad));
    return pLoad;
}

void
xf86ConfFreeLoadModuleData(confLoadModulePtr pLoad)
{
    if (!pLoad)
	return;

    if (pLoad->name) {
	xfree(pLoad->name);
	pLoad->name = NULL;
    }
    if (pLoad->options) {
	xf86OptionListFree(pLoad->options);
	pLoad->options = NULL;
    }
}

confLoadModulePtr
xf86ConfDupLoadModule(const confLoadModuleRec *pLoad)
{
    confLoadModulePtr l;

    if (!pLoad)
	return NULL;

    l = xf86ConfAllocLoadModule();
    if (!l)
	return NULL;

    l->name = xstrdup(pLoad->name);
    if (pLoad->name && !l->name) {
	xf86ConfFreeLoadModuleData(l);
	xfree(l);
	return NULL;
    }
    l->options = xf86OptionListDup(pLoad->options);
    if (pLoad->options && !l->options) {
	xf86ConfFreeLoadModuleData(l);
	xfree(l);
	return NULL;
    }
    return l;
}

static confLoadModulePtr
convertLoadModule(confLoadModulePtr pLoad, const XF86LoadRec *loadConf)
{
    if (!pLoad || !loadConf)
	return NULL;

    pLoad->name = xstrdup(loadConf->load_name);
    if (loadConf->load_name && !pLoad->name) {
	xf86ConfFreeLoadModuleData(pLoad);
	return NULL;
    }
    pLoad->options = xf86OptionListDup(loadConf->load_opt);
    if (loadConf->load_opt && !pLoad->options) {
	xf86ConfFreeLoadModuleData(pLoad);
	return NULL;
    }
    return pLoad;
}

confModulesPtr
xf86ConfAllocModules()
{
    confModulesPtr pModules;

    pModules = xcalloc(1, sizeof(*pModules));
    pModules->handle = pModules;
    return pModules;
}

void
xf86ConfFreeModulesData(confModulesPtr pModules)
{
    int i;

    if (!pModules)
	return;

    if (pModules->identifier) {
	xfree(pModules->identifier);
	pModules->identifier = NULL;
    }
    if (pModules->options) {
	xf86OptionListFree(pModules->options);
	pModules->options = NULL;
    }
    if (pModules->modules) {
	for (i = 0; i < pModules->numModules; i++) {
	    xf86ConfFreeLoadModuleData(pModules->modules[i]);
	    xfree(pModules->modules[i]);
	    pModules->modules[i] = NULL;
	}
	xfree(pModules->modules);
	pModules->modules = NULL;
    }
    pModules->numModules = 0;
}

confModulesPtr
xf86ConfDupModules(const confModulesRec *pModules)
{
    confModulesPtr m;
    int i;

    if (!pModules)
	return NULL;

    m = xf86ConfAllocModules();
    if (!m)
	return NULL;

    m->handle = pModules->handle;
    m->identifier = xstrdup(pModules->identifier);
    if (pModules->identifier && !m->identifier) {
	xf86ConfFreeModulesData(m);
	xfree(m);
	return NULL;
    }
    m->options = xf86OptionListDup(pModules->options);
    if (pModules->options && !m->options) {
	xf86ConfFreeModulesData(m);
	xfree(m);
	return NULL;
    }
    m->numModules = pModules->numModules;
    if (m->numModules > 0 && pModules->modules) {
	m->modules = xcalloc(m->numModules, sizeof(confLoadModulePtr));
	if (!m->modules) {
	    xf86ConfFreeModulesData(m);
	    xfree(m);
	    return NULL;
	}
	for (i = 0; i < m->numModules; i++) {
	    m->modules[i] = xf86ConfDupLoadModule(pModules->modules[i]);
	    if (pModules->modules[i] && !m->modules[i]) {
		xf86ConfFreeModulesData(m);
		xfree(m);
		return NULL;
	    }
	}
    }
    return m;
}

static confModulesPtr
convertModules(confModulesPtr pModules, const XF86ConfModuleRec* confModules)
{
    XF86LoadPtr lp;
    int count, i;

    if (!pModules || !confModules)
	return NULL;

    pModules->handle = confModules;
    pModules->identifier = xstrdup(confModules->mod_identifier);
    if (confModules->mod_identifier && !pModules->identifier) {
	xf86ConfFreeModulesData(pModules);
	return NULL;
    }
    pModules->options = xf86OptionListDup(confModules->mod_option_lst);
    if (confModules->mod_option_lst && !pModules->options) {
	xf86ConfFreeModulesData(pModules);
	return NULL;
    }

    /* Count how many module load references there are. */
    lp = confModules->mod_load_lst;
    count = 0;
    while (lp) {
	count++;
	lp = lp->list.next;
    }
    pModules->numModules = count;
    if (count > 0) {
	pModules->modules = xcalloc(count, sizeof(confLoadModulePtr));
	if (!pModules->modules) {
	    xf86ConfFreeModulesData(pModules);
	    return NULL;
	}
	lp = confModules->mod_load_lst;
	for (i = 0; i < count; i++) {
	    pModules->modules[i] = xf86ConfAllocLoadModule();
	    if (!pModules->modules[i]) {
		xf86ConfFreeModulesData(pModules);
		return NULL;
	    }
	    if (!convertLoadModule(pModules->modules[i], lp)) {
		xf86ConfFreeModulesData(pModules);
		return NULL;
	    }
	    lp = lp->list.next;
	}
    }
    return pModules;
}

confModulesPtr
xf86ConfGetModulesByName(ConfigHandle handle, const char *name)
{
    const XF86ConfigRec *pConfig;
    const XF86ConfModuleRec *m;
    confModulesPtr pModules = NULL;

    if (!name)
	return NULL;

    pConfig = ConfigHandleToConfigRead(handle);
    for (m = pConfig->conf_modules_lst; m; m = m->list.next) {
	if (xf86nameCompare(m->mod_identifier, name) == 0)
	    break;
    }
    if (m) {
	pModules = xf86ConfAllocModules();
	if (pModules) {
	    if (convertModules(pModules, m))
		return pModules;
	    else
		xfree(pModules);
	}
    }
    return NULL;
}

confModulesPtr
xf86ConfGetNextModules(ConfigHandle handle,
		       ConfigDataHandle prevModulesHandle)
{
    const XF86ConfigRec *pConfig;
    const XF86ConfModuleRec *m;
    confModulesPtr pModules = NULL;

    /* The active special case. */
    if (handle == ACTIVE_CONFIG) {
	if (!prevModulesHandle)
	    return xf86ConfDupModules(xf86Info.confModules);
	else
	    return NULL;
    }

    pConfig = ConfigHandleToConfigRead(handle);
    if (!prevModulesHandle) {
	m = pConfig->conf_modules_lst;
    } else {
	for (m = pConfig->conf_modules_lst; m; m = m->list.next) {
	    if (m == prevModulesHandle) {
		m = m->list.next;
		break;
	    }
	}
    }
    if (m) {
	pModules = xf86ConfAllocModules();
	if (pModules) {
	    if (convertModules(pModules, m))
		return pModules;
	    else
		xfree(pModules);
	}
    }
    return NULL;
}

confModulesPtr
xf86ConfCombineModulesData(const confModulesRec *src1,
			   const confModulesRec *src2)
{
    confModulesPtr dst = NULL;
    pointer opt1 = NULL, opt2 = NULL;
    int i, j;

    dst = xf86ConfAllocModules();
    if (!dst)
	return NULL;

    dst->numModules = 0;
    if (src1)
	dst->numModules = src1->numModules;
    if (src2)
	dst->numModules += src2->numModules;

    if (dst->numModules > 0) {
	dst->modules = xcalloc(dst->numModules, sizeof(confLoadModulePtr));
	if (!dst->modules) {
	    xf86ConfFreeModulesData(dst);
	    xfree(dst);
	    return NULL;
	}
	j = 0;
	if (src1) {
	    for (i = 0; i < src1->numModules; i++) {
		dst->modules[j] = xf86ConfAllocLoadModule();
		if (!dst->modules) {
		    xf86ConfFreeModulesData(dst);
		    xfree(dst);
		    return NULL;
		}
		dst->modules[j]->name = xstrdup(src1->modules[i]->name);
		dst->modules[j]->options =
			xf86OptionListDup(src1->modules[i]->options);
		j++;
	    }
	}
	if (src2) {
	    for (i = 0; i < src2->numModules; i++) {
		dst->modules[j] = xf86ConfAllocLoadModule();
		if (!dst->modules) {
		    xf86ConfFreeModulesData(dst);
		    xfree(dst);
		    return NULL;
		}
		dst->modules[j]->name = xstrdup(src2->modules[i]->name);
		dst->modules[j]->options =
			xf86OptionListDup(src2->modules[i]->options);
		j++;
	    }
	}
    }
    if (src1)
	opt1 = xf86OptionListDup(src1->options);
    if (src2)
	opt2 = xf86OptionListDup(src2->options);
    dst->options = xf86OptionListMerge(opt2, opt1);
    dst->handle = dst;
    return dst;
}

/*
 * Process the Modules sections, combining them into a single list of modules
 * to load explicitly.
 */
static confModulesPtr
configModules(ConfigHandle handle, const XF86ConfModuleRec *confModules,
	      MessageType from)
{
    confModulesPtr m = NULL, m1, m2;
    const void *mh;
    
    if (confModules) {
	m = xf86ConfAllocModules();
	if (!m)
	    return NULL;
	if (!convertModules(m, confModules)) {
	    xfree(m);
	    return NULL;
	}
    } else {
	m1 = xf86ConfGetNextModules(handle, NULL);
	if (m1) {
	    mh = m1->handle;
	    do {
		m2 = xf86ConfGetNextModules(handle, mh);
		if (m2) {
		    mh = m2->handle;
		    m = xf86ConfCombineModulesData(m1, m2);
		    xf86ConfFreeModulesData(m1);
		    xf86ConfFreeModulesData(m2);
		    xfree(m1);
		    xfree(m2);
		    if (!m)
			return NULL;
		    m1 = m;
		} else {
		    m = m1;
		    mh = NULL;
		}
	    } while (mh);
	}
    }
    if (!m)
	m = xf86ConfAllocModules();
    return m;
}

void
xf86ModulelistFree(const char **moduleList, pointer *optList)
{
    int i;

    if (moduleList) {
	for (i = 0; moduleList[i]; i++)
	    xfree(moduleList[i]);
	xfree(moduleList);
    }
    if (optList) {
	for (i = 0; optList[i]; i++)
	    xf86OptionListFree(optList[i]);
	xfree(optList);
    }
}

const char **
xf86ModulelistFromConfig(pointer **optList)
{
    const char **moduleArray = NULL;
    pointer *optArray = NULL;
    int i, n;
    
    if (!optList)
	return NULL;

    if (xf86Info.confModules && xf86Info.confModules->numModules > 0) {
	n = xf86Info.confModules->numModules;
	moduleArray = xcalloc(n + 1, sizeof(*moduleArray));
	optArray = xcalloc(n + 1, sizeof(*optArray));
	for (i = 0; i < n; i++) {
	    moduleArray[i] = xstrdup(xf86Info.confModules->modules[i]->name);
	    if (!moduleArray[i]) {
		xf86ModulelistFree(moduleArray, optArray);
		return NULL;
	    }
	    optArray[i] =
		xf86OptionListDup(xf86Info.confModules->modules[i]->options);
	    if (xf86Info.confModules->modules[i]->options && !optArray[i]) {
		xf86ModulelistFree(moduleArray, optArray);
		return NULL;
	    }
	}
	moduleArray[n] = NULL;
	optArray[n] = NULL;
    }
    *optList = optArray;
    return moduleArray;
}

const char **
xf86DriverlistFromConfig()
{
    int count = 0;
    int i, j;
    const char **modulearray;
    screenLayoutPtr pScreenLayout;

    if (!xf86Info.serverLayout)
	return NULL;

    count = xf86Info.serverLayout->numScreens +
	    xf86Info.serverLayout->numInactives;
    if (count == 0)
	return NULL;

    modulearray = xnfalloc((count + 1) * sizeof(char*));
    j = 0;
    for (i = 0; i < xf86Info.serverLayout->numScreens; i++) {
	pScreenLayout = xf86Info.serverLayout->screenLayouts[i];
	modulearray[j] = pScreenLayout->screen->device->driver;
	j++;
    }

    for (i = 0; i < xf86Info.serverLayout->numInactives; i++) {
	modulearray[j] = xf86Info.serverLayout->inactiveDevs[i]->driver;
	j++;
    }

    modulearray[j] = NULL;

    /* Remove duplicates */
    for (i = 0; i < count; i++) {
	for (j = 0; j < i; j++) {
	    if (xf86NameCmp(modulearray[j], modulearray[i]) == 0) {
		modulearray[i] = "";
		break;
	    }
	}
    }
    return modulearray;
}


Bool
xf86BuiltinInputDriver(const char *name)
{
    if (xf86NameCmp(name, "keyboard") == 0)
	return TRUE;
    else
	return FALSE;
}


const char **
xf86InputDriverlistFromConfig()
{
    int i;
    const char **modulearray;

    if (!xf86Info.serverLayout)
	return NULL;

    if (xf86Info.serverLayout->numInputs == 0)
	return NULL;

    modulearray = xnfalloc((xf86Info.serverLayout->numInputs + 1) *
			   sizeof(char*));
    for (i = 0; i < xf86Info.serverLayout->numInputs; i++) {
	if (!xf86BuiltinInputDriver(
		xf86Info.serverLayout->inputDevs[i]->driver))
	    modulearray[i] = xf86Info.serverLayout->inputDevs[i]->driver;
	else
	    modulearray[i] = "";
    }
    modulearray[i] = NULL;

    /* Remove duplicates. */
    for (i = 0; i < xf86Info.serverLayout->numInputs; i++) {
	int j;

	for (j = 0; j < i; j++) {
	    if (xf86NameCmp(modulearray[j], modulearray[i]) == 0) {
		modulearray[i] = "";
		break;
	    }
	}
    }
    return modulearray;
}


/*
 * Generate a compiled-in list of driver names.  This is used to produce a
 * consistent probe order.  For the loader server, we also look for vendor-
 * provided modules, pre-pending them to our own list.
 */
static const char **
GenerateDriverlist(char * dirname, char * drivernames)
{
    char *cp, **driverlist;
    int count;

    /* Count the number needed */
    count = 0;
    cp = drivernames;
    while (*cp) {
	while (*cp && isspace(*cp)) cp++;
	if (!*cp) break;
	count++;
	while (*cp && !isspace(*cp)) cp++;
    }

    if (!count)
	return NULL;

    /* Now allocate the array of pointers to 0-terminated driver names */
    driverlist = (char **)xnfalloc((count + 1) * sizeof(char *));
    count = 0;
    cp = drivernames;
    while (*cp) {
	while (*cp && isspace(*cp)) cp++;
	if (!*cp) break;
	driverlist[count++] = cp;
	while (*cp && !isspace(*cp)) cp++;
	if (!*cp) break;
	*cp++ = 0;
    }
    driverlist[count] = NULL;

#ifdef XFree86LOADER
    {
        const char *subdirs[] = {NULL, NULL};
        static const char *patlist[] = {"(.*)_drv\\.so", "(.*)_drv\\.o", NULL};
        char **dlist, **clist, **dcp, **ccp;
	int size;

        subdirs[0] = dirname;

        /* Get module list */
        dlist = LoaderListDirs(subdirs, patlist);
        if (!dlist) {
            xfree(driverlist);
            return NULL;        /* No modules, no list */
        }

        clist = driverlist;

        /* The resulting list cannot be longer than the module list */
        for (dcp = dlist, count = 0;  *dcp++;  count++);
        driverlist = (char **)xnfalloc((size = count + 1) * sizeof(char *));

        /* First, add modules not in compiled-in list */
        for (count = 0, dcp = dlist;  *dcp;  dcp++) {
            for (ccp = clist;  ;  ccp++) {
                if (!*ccp) {
                    driverlist[count++] = *dcp;
		    if (count >= size)
			driverlist = (char**)
			    xnfrealloc(driverlist, ++size * sizeof(char*));
                    break;
                }
                if (!strcmp(*ccp, *dcp))
                    break;
            }
        }

        /* Next, add compiled-in names that are also modules */
        for (ccp = clist;  *ccp;  ccp++) {
            for (dcp = dlist;  *dcp;  dcp++) {
                if (!strcmp(*ccp, *dcp)) {
                    driverlist[count++] = *ccp;
		    if (count >= size)
			driverlist = (char**)
			    xnfrealloc(driverlist, ++size * sizeof(char*));
                    break;
                }
            }
        }

        driverlist[count] = NULL;
        xfree(clist);
        xfree(dlist);
    }
#endif /* XFree86LOADER */
    return (const char **)driverlist;
}


const char **
xf86DriverlistFromCompile(void)
{
    static const char **driverlist = NULL;
    static Bool generated = FALSE;

    /* This string is modified in-place */
    static char drivernames[] = DRIVERS;

    if (!generated) {
        generated = TRUE;
        driverlist = GenerateDriverlist("drivers", drivernames);
    }
    return driverlist;
}


const char **
xf86InputDriverlistFromCompile(void)
{
    static const char **driverlist = NULL;
    static Bool generated = FALSE;

    /* This string is modified in-place */
    static char drivernames[] = IDRIVERS;

    if (!generated) {
        generated = TRUE;
	driverlist = GenerateDriverlist("input", drivernames);
    }
    return driverlist;
}

confFilesPtr
xf86ConfAllocFiles()
{
    confFilesPtr pFiles;

    pFiles = xcalloc(1, sizeof(*pFiles));
    pFiles->fontPathFrom = X_NONE;
    pFiles->rgbPathFrom = X_NONE;
    pFiles->modulePathFrom = X_NONE;
    pFiles->logFileFrom = X_NONE;
    pFiles->inputDeviceListFrom = X_NONE;
    pFiles->handle = pFiles;
    return pFiles;
}

void
xf86ConfFreeFilesData(confFilesPtr pFiles)
{
    if (!pFiles)
	return;

    if (pFiles->identifier) {
	xfree(pFiles->identifier);
	pFiles->identifier = NULL;
    }
    if (pFiles->logFile) {
	xfree(pFiles->logFile);
	pFiles->logFile = NULL;
    }
    if (pFiles->rgbPath) {
	xfree(pFiles->rgbPath);
	pFiles->rgbPath = NULL;
    }
    if (pFiles->modulePath) {
	xfree(pFiles->modulePath);
	pFiles->modulePath = NULL;
    }
    if (pFiles->inputDeviceList) {
	xfree(pFiles->inputDeviceList);
	pFiles->inputDeviceList = NULL;
    }
    if (pFiles->fontPath) {
	xfree(pFiles->fontPath);
	pFiles->fontPath = NULL;
    }
    if (pFiles->options) {
	xf86OptionListFree(pFiles->options);
	pFiles->options = NULL;
    }
}

confFilesPtr
xf86ConfDupFiles(const confFilesRec *pFiles)
{
    confFilesPtr f;

    if (!pFiles)
	return NULL;

    f = xf86ConfAllocFiles();
    if (!f)
	return NULL;

    f->handle = pFiles->handle;
    f->identifier = xstrdup(pFiles->identifier);
    if (pFiles->identifier && !f->identifier) {
	xf86ConfFreeFilesData(f);
	xfree(f);
	return NULL;
    }
    f->logFile = xstrdup(pFiles->logFile);
    if (pFiles->logFile && !f->logFile) {
	xf86ConfFreeFilesData(f);
	xfree(f);
	return NULL;
    }
    f->rgbPath = xstrdup(pFiles->rgbPath);
    if (pFiles->rgbPath && !f->rgbPath) {
	xf86ConfFreeFilesData(f);
	xfree(f);
	return NULL;
    }
    f->modulePath = xstrdup(pFiles->modulePath);
    if (pFiles->modulePath && !f->modulePath) {
	xf86ConfFreeFilesData(f);
	xfree(f);
	return NULL;
    }
    f->inputDeviceList = xstrdup(pFiles->inputDeviceList);
    if (pFiles->inputDeviceList && !f->inputDeviceList) {
	xf86ConfFreeFilesData(f);
	xfree(f);
	return NULL;
    }
    f->fontPath = xstrdup(pFiles->fontPath);
    if (pFiles->fontPath && !f->fontPath) {
	xf86ConfFreeFilesData(f);
	xfree(f);
	return NULL;
    }
    f->options = xf86OptionListDup(pFiles->options);
    if (pFiles->options && !f->options) {
	xf86ConfFreeFilesData(f);
	xfree(f);
	return NULL;
    }
    return f;
}

/*
 * Convert a Files section from the parser's format to the server's format.
 */
static confFilesPtr
convertFiles(confFilesPtr pFiles, const XF86ConfFilesRec *filesConf)
{
    if (!pFiles || !filesConf)
	return NULL;

    pFiles->handle = filesConf;
    pFiles->identifier = xstrdup(filesConf->file_identifier);
    if (filesConf->file_identifier && !pFiles->identifier) {
	xf86ConfFreeFilesData(pFiles);
	return NULL;
    }
    pFiles->logFile = xstrdup(filesConf->file_logfile);
    if (filesConf->file_logfile && !pFiles->logFile) {
	xf86ConfFreeFilesData(pFiles);
	return NULL;
    }
    pFiles->rgbPath = xstrdup(filesConf->file_rgbpath);
    if (filesConf->file_rgbpath && !pFiles->rgbPath) {
	xf86ConfFreeFilesData(pFiles);
	return NULL;
    }
    pFiles->modulePath = xstrdup(filesConf->file_modulepath);
    if (filesConf->file_modulepath && !pFiles->modulePath) {
	xf86ConfFreeFilesData(pFiles);
	return NULL;
    }
    pFiles->inputDeviceList = xstrdup(filesConf->file_inputdevs);
    if (filesConf->file_inputdevs && !pFiles->inputDeviceList) {
	xf86ConfFreeFilesData(pFiles);
	return NULL;
    }
    pFiles->fontPath = xstrdup(filesConf->file_fontpath);
    if (filesConf->file_fontpath && !pFiles->fontPath) {
	xf86ConfFreeFilesData(pFiles);
	return NULL;
    }
    pFiles->options = xf86OptionListDup(filesConf->file_option_lst);
    if (filesConf->file_option_lst && !pFiles->options) {
	xf86ConfFreeFilesData(pFiles);
	return NULL;
    }
    return pFiles;
}

confFilesPtr
xf86ConfGetFilesByName(ConfigHandle handle, const char *name)
{
    const XF86ConfigRec *pConfig;
    XF86ConfFilesPtr f;
    confFilesPtr pFiles = NULL;

    if (!name)
	return NULL;

    pConfig = ConfigHandleToConfigRead(handle);
    for (f = pConfig->conf_files_lst; f; f = f->list.next) {
	if (xf86nameCompare(f->file_identifier, name) == 0)
	    break;
    }
    if (f) {
	pFiles = xf86ConfAllocFiles();
	if (pFiles) {
	    if (convertFiles(pFiles, f))
		return pFiles;
	    else
		xfree(pFiles);
	}
    }
    return NULL;
}

confFilesPtr
xf86ConfGetNextFiles(ConfigHandle handle, ConfigDataHandle prevFilesHandle)
{
    const XF86ConfigRec *pConfig;
    XF86ConfFilesPtr f;
    confFilesPtr pFiles = NULL;

    /* Check for these special cases first. */
    if (handle == CMDLINE_CONFIG || handle == BUILDTIME_CONFIG ||
	handle == ACTIVE_CONFIG) {
	if (prevFilesHandle)
	    return NULL;
	else {
	    const confFilesRec *fd;

	    if (handle == ACTIVE_CONFIG)
		return xf86ConfDupFiles(xf86FilePaths);
	    else if (handle == CMDLINE_CONFIG)
		fd = &xf86FileCmdline;
	    else
		fd = &xf86FileDefaults;
	    pFiles = xf86ConfCombineFilesData(fd, X_NONE, NULL, X_NONE);
	    if (!pFiles)
		return NULL;
	    return pFiles;
	}
    }

    pConfig = ConfigHandleToConfigRead(handle);
    if (!prevFilesHandle) {
	f = pConfig->conf_files_lst;
    } else {
	for (f = pConfig->conf_files_lst; f; f = f->list.next) {
	    if (f == prevFilesHandle) {
		f = f->list.next;
		break;
	    }
	}
    }
    if (f) {
	pFiles = xf86ConfAllocFiles();
	if (pFiles) {
	    if (convertFiles(pFiles, f))
		return pFiles;
	    else
		xfree(pFiles);
	}
    }
    return NULL;
}

confFilesPtr
xf86ConfCombineFilesData(const confFilesRec *src1, MessageType m1,
			 const confFilesRec *src2, MessageType m2)
{
    pointer opt1 = NULL, opt2 = NULL;
    confFilesPtr dst = NULL;

    dst = xf86ConfAllocFiles();
    if (!dst)
	return NULL;

    if (src1 && src1->logFile) {
	dst->logFile = xstrdup(src1->logFile);
	dst->logFileFrom = (m1 != X_NONE ? m1 : src1->logFileFrom);
    } else if (src2 && src2->logFile) {
	dst->logFile = xstrdup(src2->logFile);
	dst->logFileFrom = (m2 != X_NONE ? m2 : src2->logFileFrom);
    }
    if (!dst->logFile && ((src1 && src1->logFile) ||
			  (src2 && src2->logFile))) {
	xf86ConfFreeFilesData(dst);
	xfree(dst);
	return NULL;
    }

    if (src1 && src1->rgbPath) {
	dst->rgbPath = xstrdup(src1->rgbPath);
	dst->rgbPathFrom = (m1 != X_NONE ? m1 : src1->rgbPathFrom);
    } else if (src2 && src2->rgbPath) {
	dst->rgbPath = xstrdup(src2->rgbPath);
	dst->rgbPathFrom = (m2 != X_NONE ? m2 : src2->rgbPathFrom);
    }
    if (!dst->rgbPath && ((src1 && src1->rgbPath) ||
			  (src2 && src2->rgbPath))) {
	xf86ConfFreeFilesData(dst);
	xfree(dst);
	return NULL;
    }

    if (src1 && src1->modulePath) {
	dst->modulePath = xstrdup(src1->modulePath);
	dst->modulePathFrom = (m1 != X_NONE ? m1 : src1->modulePathFrom);
    } else if (src2 && src2->modulePath) {
	dst->modulePath = xstrdup(src2->modulePath);
	dst->modulePathFrom = (m2 != X_NONE ? m2 : src2->modulePathFrom);
    }
    if (!dst->modulePath && ((src1 && src1->modulePath) ||
			     (src2 && src2->modulePath))) {
	xf86ConfFreeFilesData(dst);
	xfree(dst);
	return NULL;
    }

    if (src1 && src1->fontPath) {
	dst->fontPath = xstrdup(src1->fontPath);
	dst->fontPathFrom = (m1 != X_NONE ? m1 : src1->fontPathFrom);
    } else if (src2 && src2->fontPath) {
	dst->fontPath = xstrdup(src2->fontPath);
	dst->fontPathFrom = (m2 != X_NONE ? m2 : src2->fontPathFrom);
    }
    if (!dst->fontPath && ((src1 && src1->fontPath) ||
			   (src2 && src2->fontPath))) {
	xf86ConfFreeFilesData(dst);
	xfree(dst);
	return NULL;
    }

    if (src1 && src1->inputDeviceList) {
	dst->inputDeviceList = xstrdup(src1->inputDeviceList);
	dst->inputDeviceListFrom =
		(m1 != X_NONE ? m1 : src1->inputDeviceListFrom);
    } else if (src2 && src2->inputDeviceList) {
	dst->inputDeviceList = xstrdup(src2->inputDeviceList);
	dst->inputDeviceListFrom =
		(m2 != X_NONE ? m2 : src2->inputDeviceListFrom);
    }
    if (!dst->inputDeviceList && ((src1 && src1->inputDeviceList) ||
				  (src2 && src2->inputDeviceList))) {
	xf86ConfFreeFilesData(dst);
	xfree(dst);
	return NULL;
    }

    if (src1)
	opt1 = xf86OptionListDup(src1->options);
    if (src2)
	opt2 = xf86OptionListDup(src2->options);
    dst->options = xf86OptionListMerge(opt2, opt1);

    dst->handle = dst;
    return dst;
}

/*
 * xf86GetPathElem --
 *	Extract a single element from the font path string starting at
 *	pnt.  The font path element will be returned, and pnt will be
 *	updated to point to the start of the next element, or set to
 *	NULL if there are no more.
 */
static char *
xf86GetPathElem(char **pnt)
{
    char *p1;

    p1 = *pnt;
    *pnt = strchr(*pnt, ',');
    if (*pnt) {
	**pnt = '\0';
	(*pnt)++;
    }
    return p1;
}

/*
 * xf86ValidateFontPath --
 *	Validates the user-specified font path.  Each element that
 *	begins with a '/' is checked to make sure the directory exists.
 *	If the directory exists, the existence of a file named 'fonts.dir'
 *	is checked.  If either check fails, an error is printed and the
 *	element is removed from the font path.
 */

#define DIR_FILE "/fonts.dir"
static char *
xf86ValidateFontPath(const char *p)
{
    char *tmp_path, *out_pnt, *path_elem, *next, *p1, *dir_elem, *path;
    struct stat stat_buf;
    Bool ok;
    int dirlen;

    path = xstrdup(p);
    if (!path)
	return NULL;
    tmp_path = xcalloc(1, strlen(path) + 1);
    if (!tmp_path)
	return NULL;
    out_pnt = tmp_path;
    path_elem = NULL;
    next = path;
    while (next) {
	path_elem = xf86GetPathElem(&next);
	if (*path_elem == '/') {
#ifndef __UNIXOS2__
	    dir_elem = xcalloc(1, strlen(path_elem) + 1);
	    if (!dir_elem) {
		xfree(tmp_path);
		return NULL;
	    }
	    if ((p1 = strchr(path_elem, ':')))
#else
	/* OS/2 must prepend X11ROOT */
	    path_elem = (char*)__XOS2RedirRoot(path_elem);
	    dir_elem = xcalloc(1, strlen(path_elem) + 1);
	    if (!dir_elem) {
		xfree(tmp_path);
		return NULL;
	    }
	    if ((p1 = strchr(path_elem + 2, ':')))
#endif
		dirlen = p1 - path_elem;
	    else
		dirlen = strlen(path_elem);
	    strncpy(dir_elem, path_elem, dirlen);
	    dir_elem[dirlen] = '\0';
	    ok = (stat(dir_elem, &stat_buf) == 0 && S_ISDIR(stat_buf.st_mode));
	    if (!ok) {
		xf86Msg(X_WARNING,
			"The directory \"%s\" does not exist.\n", dir_elem);
		xf86ErrorF("\tEntry deleted from font path.\n");
		xfree(dir_elem);
		continue;
	    } else {
		p1 = xalloc(strlen(dir_elem) + strlen(DIR_FILE) + 1);
		if (!p1) {
		    xfree(dir_elem);
		    xfree(tmp_path);
		    return NULL;
		}
		strcpy(p1, dir_elem);
		strcat(p1, DIR_FILE);
		ok = (stat(p1, &stat_buf) == 0 && S_ISREG(stat_buf.st_mode));
		xfree(p1);
		if (!ok) {
		    xf86Msg(X_WARNING,
			    "\"fonts.dir\" not found (or not valid) in "
			    "\"%s\".\n", dir_elem);
		    xf86ErrorF("\tEntry deleted from font path.\n");
		    xf86ErrorF("\t(Run 'mkfontdir' on \"%s\").\n", dir_elem);
		    xfree(dir_elem);
		    continue;
		}
	    }
	    xfree(dir_elem);
	}

	/*
	 * Either an OK directory, or a font server name.  So add it to
	 * the path.
	 */
	if (out_pnt != tmp_path)
	    *out_pnt++ = ',';
	strcat(out_pnt, path_elem);
	out_pnt += strlen(path_elem);
    }
    return tmp_path;
}

static confFilesPtr
configFiles(ConfigHandle handle, const XF86ConfFilesRec *filesConf,
	    MessageType from)
{
    confFilesPtr f = NULL, f1, f2;
    const void *fh;

    /*
     * If filesConf is supplied explicitly, use it.  Otherwise combine all
     * of the Files data.
     */
    if (filesConf) {
	f = xf86ConfAllocFiles();
	if (!f)
	    return NULL;
	if (!(f = convertFiles(f, filesConf))) {
	    xfree(f);
	    return NULL;
	}
    } else {
	f1 = xf86ConfGetNextFiles(handle, NULL);
	if (f1) {
	    fh = f1->handle;
	    do {
		f2 = xf86ConfGetNextFiles(handle, fh);
		if (f2) {
		    fh = f2->handle;
		    f = xf86ConfCombineFilesData(f1, from, f2, from);
		    xf86ConfFreeFilesData(f1);
		    xf86ConfFreeFilesData(f2);
		    xfree(f1);
		    xfree(f2);
		    if (!f)
			return NULL;
		    f1 = f;
		} else {
		    f = f1;
		    fh = NULL;
		}
	    } while (fh);
	}
    }
    /*
     * Combine the config file data with the defaults and command line
     * options.
     */
    f1 = f;
    f = xf86ConfCombineFilesData(&xf86FileCmdline, X_CMDLINE, f1, from);
    xf86ConfFreeFilesData(f1);
    xfree(f1);
    if (!f)
	return NULL;
    f1 = f;
    f = xf86ConfCombineFilesData(f1, X_NONE, &xf86FileDefaults, X_DEFAULT);
    xf86ConfFreeFilesData(f1);
    xfree(f1);
    if (!f)
	return NULL;
    f->identifier = xstrdup("<combined>");
    xf86ConfFreeFilesData(xf86FilePaths);
    xf86FilePaths = f;

    /* Validate/print path info. */
    {
	char *fp;

	fp = xf86ValidateFontPath(xf86FilePaths->fontPath);
	xfree(xf86FilePaths->fontPath);
	if (fp && *fp) {
	    xf86FilePaths->fontPath = defaultFontPath = fp;
	} else {
	    xf86Msg(X_WARNING, "FontPath is completely invalid.  "
			       "Using compiled-in default.\n");
	    xf86FilePaths->fontPath = xstrdup(defaultFontPath);
	    if (!xf86FilePaths->fontPath)
		return NULL;
	    xf86FilePaths->fontPathFrom = X_DEFAULT;
	}
    }

    /* Fatal error if no valid font path is found. */
    if (!defaultFontPath || !*defaultFontPath)
	FatalError("No valid FontPath could be found.");

    xf86Msg(xf86FilePaths->fontPathFrom, "FontPath set to \"%s\"\n",
	    xf86FilePaths->fontPath);

    rgbPath = xnfstrdup(xf86FilePaths->rgbPath);
    xf86Msg(xf86FilePaths->rgbPathFrom, "RgbPath set to \"%s\"\n",
	    xf86FilePaths->rgbPath);

    if (xf86FilePaths->inputDeviceList) {
	xf86Msg(xf86FilePaths->inputDeviceListFrom,
		"Input device list set to \"%s\"\n",
		xf86FilePaths->inputDeviceList);
    }
  
    xf86Msg(xf86FilePaths->modulePathFrom, "ModulePath set to \"%s\"\n",
	    xf86FilePaths->modulePath);

#if 0
    /* LogFile */
    /*
     * XXX The problem with this is that the log file is already open.
     * One option might be to copy the exiting contents to the new location.
     * and re-open it.  The down side is that the default location would
     * already have been overwritten.  Another option would be to start with
     * unique temporary location, then copy it once the correct name is known.
     * A problem with this is what happens if the server exits before that
     * happens.
     */
    xf86Msg(xf86FilePaths->logFileFrom, "Log file set to \"%s\"\n",
	    xf86FilePaths->logFile);
#endif
    return xf86FilePaths;
}

confFlagsPtr
xf86ConfAllocServerFlags()
{
    confFlagsPtr pFlags;

    pFlags = xcalloc(1, sizeof(*pFlags));
    pFlags->handle = pFlags;
    return pFlags;
}

void
xf86ConfFreeServerFlagsData(confFlagsPtr pFlags)
{
    if (!pFlags)
	return;

    if (pFlags->identifier) {
	xfree(pFlags->identifier);
	pFlags->identifier = NULL;
    }
    if (pFlags->options) {
	xf86OptionListFree(pFlags->options);
	pFlags->options = NULL;
    }
}

confFlagsPtr
xf86ConfDupServerFlags(const confFlagsRec *pFlags)
{
    confFlagsPtr f;

    if (!pFlags)
	return NULL;

    f = xf86ConfAllocServerFlags();
    if (!f)
	return NULL;

    f->handle = pFlags->handle;
    f->identifier = xstrdup(pFlags->identifier);
    if (pFlags->identifier && !f->identifier) {
	xf86ConfFreeServerFlagsData(f);
	xfree(f);
	return NULL;
    }
    f->options = xf86OptionListDup(pFlags->options);
    if (pFlags->options && !f->options) {
	xf86ConfFreeServerFlagsData(f);
	xfree(f);
	return NULL;
    }
    return f;
}

/*
 * Convert a Files section from the parser's format to the server's format.
 */
static confFlagsPtr
convertServerFlags(confFlagsPtr pFlags, const XF86ConfFlagsRec *flagsConf)
{
    if (!pFlags || !flagsConf)
	return NULL;

    pFlags->handle = flagsConf;
    pFlags->identifier = xstrdup(flagsConf->flg_identifier);
    if (flagsConf->flg_identifier && !pFlags->identifier) {
	xf86ConfFreeServerFlagsData(pFlags);
	return NULL;
    }
    pFlags->options = xf86OptionListDup(flagsConf->flg_option_lst);
    if (flagsConf->flg_option_lst && !pFlags->options) {
	xf86ConfFreeServerFlagsData(pFlags);
	return NULL;
    }
    return pFlags;
}

confFlagsPtr
xf86ConfGetServerFlagsByName(ConfigHandle handle, const char *name)
{
    const XF86ConfigRec *pConfig;
    const XF86ConfFlagsRec *f;
    confFlagsPtr pFlags = NULL;

    if (!name)
	return NULL;

    pConfig = ConfigHandleToConfigRead(handle);
    for (f = pConfig->conf_flags_lst; f; f = f->list.next) {
	if (xf86nameCompare(f->flg_identifier, name) == 0)
	    break;
    }
    if (f) {
	pFlags = xf86ConfAllocServerFlags();
	if (pFlags) {
	    if (convertServerFlags(pFlags, f))
		return pFlags;
	    else
		xfree(pFlags);
	}
    }
    return NULL;
}

confFlagsPtr
xf86ConfGetNextServerFlags(ConfigHandle handle,
			   ConfigDataHandle prevFlagsHandle)
{
    const XF86ConfigRec *pConfig;
    const XF86ConfFlagsRec *f;
    confFlagsPtr pFlags = NULL;

    /* The active special case. */
    if (handle == ACTIVE_CONFIG) {
	if (!prevFlagsHandle)
	    return xf86ConfDupServerFlags(xf86Info.confFlags);
	else
	    return NULL;
    }

    pConfig = ConfigHandleToConfigRead(handle);
    if (!prevFlagsHandle) {
	f = pConfig->conf_flags_lst;
    } else {
	for (f = pConfig->conf_flags_lst; f; f = f->list.next) {
	    if (f == prevFlagsHandle) {
		f = f->list.next;
		break;
	    }
	}
    }
    if (f) {
	pFlags = xf86ConfAllocServerFlags();
	if (pFlags) {
	    if (convertServerFlags(pFlags, f))
		return pFlags;
	    else
		xfree(pFlags);
	}
    }
    return NULL;
}

confFlagsPtr
xf86ConfCombineServerFlagsData(const confFlagsRec *src1,
			       const confFlagsRec *src2)
{
    confFlagsPtr dst = NULL;
    pointer opt1 = NULL, opt2 = NULL;

    dst = xf86ConfAllocServerFlags();
    if (!dst)
	return NULL;

    if (src1)
	opt1 = xf86OptionListDup(src1->options);
    if (src2)
	opt2 = xf86OptionListDup(src2->options);
    dst->options = xf86OptionListMerge(opt2, opt1);
    return dst;
}

typedef enum {
    FLAG_NOTRAPSIGNALS,
    FLAG_DONTVTSWITCH,
    FLAG_DONTZAP,
    FLAG_DONTZOOM,
    FLAG_DISABLEVIDMODE,
    FLAG_ALLOWNONLOCAL,
    FLAG_DISABLEMODINDEV,
    FLAG_MODINDEVALLOWNONLOCAL,
    FLAG_ALLOWMOUSEOPENFAIL,
    FLAG_VTINIT,
    FLAG_VTSYSREQ,
    FLAG_XKBDISABLE,
    FLAG_PCIPROBE1,
    FLAG_PCIPROBE2,
    FLAG_PCIFORCECONFIG1,
    FLAG_PCIFORCECONFIG2,
    FLAG_PCIFORCENONE,
    FLAG_PCIOSCONFIG,
    FLAG_SAVER_BLANKTIME,
    FLAG_DPMS_STANDBYTIME,
    FLAG_DPMS_SUSPENDTIME,
    FLAG_DPMS_OFFTIME,
    FLAG_PIXMAP,
    FLAG_PC98,
    FLAG_ESTIMATE_SIZES_AGGRESSIVELY,
    FLAG_NOPM,
    FLAG_XINERAMA,
    FLAG_ALLOW_DEACTIVATE_GRABS,
    FLAG_ALLOW_CLOSEDOWN_GRABS,
    FLAG_LOG,
    FLAG_RENDER_COLORMAP_MODE,
    FLAG_HANDLE_SPECIAL_KEYS,
    FLAG_RANDR
} FlagValues;

static OptionInfoRec FlagOptions[] = {
  { FLAG_NOTRAPSIGNALS,		"NoTrapSignals",		OPTV_BOOLEAN,
	{0}, FALSE },
  { FLAG_DONTVTSWITCH,		"DontVTSwitch",			OPTV_BOOLEAN,
	{0}, FALSE },
  { FLAG_DONTZAP,		"DontZap",			OPTV_BOOLEAN,
	{0}, FALSE },
  { FLAG_DONTZOOM,		"DontZoom",			OPTV_BOOLEAN,
	{0}, FALSE },
  { FLAG_DISABLEVIDMODE,	"DisableVidModeExtension",	OPTV_BOOLEAN,
	{0}, FALSE },
  { FLAG_ALLOWNONLOCAL,		"AllowNonLocalXvidtune",	OPTV_BOOLEAN,
	{0}, FALSE },
  { FLAG_DISABLEMODINDEV,	"DisableModInDev",		OPTV_BOOLEAN,
	{0}, FALSE },
  { FLAG_MODINDEVALLOWNONLOCAL,	"AllowNonLocalModInDev",	OPTV_BOOLEAN,
	{0}, FALSE },
  { FLAG_ALLOWMOUSEOPENFAIL,	"AllowMouseOpenFail",		OPTV_BOOLEAN,
	{0}, FALSE },
  { FLAG_VTINIT,		"VTInit",			OPTV_STRING,
	{0}, FALSE },
  { FLAG_VTSYSREQ,		"VTSysReq",			OPTV_BOOLEAN,
	{0}, FALSE },
  { FLAG_XKBDISABLE,		"XkbDisable",			OPTV_BOOLEAN,
	{0}, FALSE },
  { FLAG_PCIPROBE1,		"PciProbe1"		,	OPTV_BOOLEAN,
	{0}, FALSE },
  { FLAG_PCIPROBE2,		"PciProbe2",			OPTV_BOOLEAN,
	{0}, FALSE },
  { FLAG_PCIFORCECONFIG1,	"PciForceConfig1",		OPTV_BOOLEAN,
	{0}, FALSE },
  { FLAG_PCIFORCECONFIG2,	"PciForceConfig2",		OPTV_BOOLEAN,
	{0}, FALSE },
  { FLAG_PCIFORCENONE,		"PciForceNone",			OPTV_BOOLEAN,
	{0}, FALSE },
  { FLAG_PCIOSCONFIG,	        "PciOsConfig",   		OPTV_BOOLEAN,
	{0}, FALSE },
  { FLAG_SAVER_BLANKTIME,	"BlankTime"		,	OPTV_INTEGER,
	{0}, FALSE },
  { FLAG_DPMS_STANDBYTIME,	"StandbyTime",			OPTV_INTEGER,
	{0}, FALSE },
  { FLAG_DPMS_SUSPENDTIME,	"SuspendTime",			OPTV_INTEGER,
	{0}, FALSE },
  { FLAG_DPMS_OFFTIME,		"OffTime",			OPTV_INTEGER,
	{0}, FALSE },
  { FLAG_PIXMAP,		"Pixmap",			OPTV_INTEGER,
	{0}, FALSE },
  { FLAG_PC98,			"PC98",				OPTV_BOOLEAN,
	{0}, FALSE },
  { FLAG_ESTIMATE_SIZES_AGGRESSIVELY,"EstimateSizesAggressively",OPTV_INTEGER,
	{0}, FALSE },
  { FLAG_NOPM,			"NoPM",				OPTV_BOOLEAN,
	{0}, FALSE },
  { FLAG_XINERAMA,		"Xinerama",			OPTV_BOOLEAN,
	{0}, FALSE },
  { FLAG_ALLOW_DEACTIVATE_GRABS,"AllowDeactivateGrabs",		OPTV_BOOLEAN,
	{0}, FALSE },
  { FLAG_ALLOW_CLOSEDOWN_GRABS, "AllowClosedownGrabs",		OPTV_BOOLEAN,
	{0}, FALSE },
  { FLAG_LOG,			"Log",				OPTV_STRING,
	{0}, FALSE },
  { FLAG_RENDER_COLORMAP_MODE,	"RenderColormapMode",		OPTV_STRING,
	{0}, FALSE },
  { FLAG_HANDLE_SPECIAL_KEYS,	"HandleSpecialKeys",		OPTV_STRING,
	{0}, FALSE },
  { FLAG_RANDR,			"RandR",			OPTV_BOOLEAN,
	{0}, FALSE },
  { -1,				NULL,				OPTV_NONE,
	{0}, FALSE },
};

#if defined(i386) || defined(__i386__)
static Bool
detectPC98(void)
{
#ifdef SUPPORT_PC98
    unsigned char buf[2];

    if (xf86ReadBIOS(0xf8000, 0xe80, buf, 2) != 2)
	return FALSE;
    if ((buf[0] == 0x98) && (buf[1] == 0x21))
	return TRUE;
    else
	return FALSE;
#else
    return FALSE;
#endif
}
#endif /* __i386__ */

static confFlagsPtr
configServerFlags(ConfigHandle handle, const XF86ConfFlagsPtr flagsConf,
		  XF86OptionPtr layoutOpts, MessageType from)
{
    confFlagsPtr f = NULL, f1, f2;
    const void *fh;
    pointer opt1, opt2;
    int i;
    Pix24Flags pix24 = Pix24DontCare;
    Bool value;

    /*
     * If flagsConf is supplied explicitly, use it.  Otherwise combine all of
     * the ServerFlags data.
     */
    if (flagsConf) {
	f = xf86ConfAllocServerFlags();
	if (!f)
	    return NULL;
	if (!(f = convertServerFlags(f, flagsConf))) {
	    xfree(f);
	    return NULL;
	}
    } else {
	f1 = xf86ConfGetNextServerFlags(handle, NULL);
	if (f1) {
	    fh = f1->handle;
	    do {
		f2 = xf86ConfGetNextServerFlags(handle, fh);
		if (f2) {
		    fh = f2->handle;
		    f = xf86ConfCombineServerFlagsData(f1, f2);
		    xf86ConfFreeServerFlagsData(f1);
		    xf86ConfFreeServerFlagsData(f2);
		    xfree(f1);
		    xfree(f2);
		    if (!f)
			return NULL;
		    f1 = f;
		} else {
		    f = f1;
		    fh = NULL;
		}
	    } while (fh);
	}
    }

    if (!f)
	f = xf86ConfAllocServerFlags();
    if (!f)
	return NULL;

    /*
     * Merge the ServerLayout and ServerFlags options.  The former have
     * precedence over the latter.
     */
    if (layoutOpts) {
	opt1 = xf86OptionListDup(layoutOpts);
	opt2 = xf86OptionListDup(f->options);
	f->options = xf86OptionListMerge(opt2, opt1);
    }

    xf86ProcessOptions(-1, f->options, FlagOptions);

    xf86GetOptValBool(FlagOptions, FLAG_NOTRAPSIGNALS, &xf86Info.notrapSignals);
    xf86GetOptValBool(FlagOptions, FLAG_DONTVTSWITCH, &xf86Info.dontVTSwitch);
    xf86GetOptValBool(FlagOptions, FLAG_DONTZAP, &xf86Info.dontZap);
    xf86GetOptValBool(FlagOptions, FLAG_DONTZOOM, &xf86Info.dontZoom);

    xf86GetOptValBool(FlagOptions, FLAG_ALLOW_DEACTIVATE_GRABS,
		      &(xf86Info.grabInfo.allowDeactivate));
    xf86GetOptValBool(FlagOptions, FLAG_ALLOW_CLOSEDOWN_GRABS,
		      &(xf86Info.grabInfo.allowClosedown));

    /*
     * Set things up based on the config file information.  Some of these
     * settings may be overridden later when the command line options are
     * checked.
     */
#ifdef XF86VIDMODE
    if (xf86GetOptValBool(FlagOptions, FLAG_DISABLEVIDMODE, &value))
	xf86Info.vidModeEnabled = !value;
    if (xf86GetOptValBool(FlagOptions, FLAG_ALLOWNONLOCAL, &value))
	xf86Info.vidModeAllowNonLocal = value;
#endif

#ifdef XF86MISC
    if (xf86GetOptValBool(FlagOptions, FLAG_DISABLEMODINDEV, &value))
	xf86Info.miscModInDevEnabled = !value;
    if (xf86GetOptValBool(FlagOptions, FLAG_MODINDEVALLOWNONLOCAL, &value))
	xf86Info.miscModInDevAllowNonLocal = value;
#endif

    if (xf86GetOptValBool(FlagOptions, FLAG_ALLOWMOUSEOPENFAIL, &value))
	xf86Info.allowMouseOpenFail = value;

    if (xf86GetOptValBool(FlagOptions, FLAG_VTSYSREQ, &value)) {
#ifdef USE_VT_SYSREQ
	xf86Info.vtSysreq = value;
	xf86Msg(X_CONFIG, "VTSysReq %s\n", value ? "enabled" : "disabled");
#else
	if (value)
	    xf86Msg(X_WARNING, "VTSysReq is not supported on this OS.\n");
#endif
    }

    if (xf86GetOptValBool(FlagOptions, FLAG_XKBDISABLE, &value)) {
#ifdef XKB
	noXkbExtension = value;
	xf86Msg(X_CONFIG, "Xkb %s\n", value ? "disabled" : "enabled");
#else
	if (!value)
	    xf86Msg(X_WARNING, "Xserver doesn't support XKB.\n");
#endif
    }

    xf86Info.vtinit = xf86GetOptValString(FlagOptions, FLAG_VTINIT);

    if (xf86IsOptionSet(FlagOptions, FLAG_PCIPROBE1))
	xf86Info.pciFlags = PCIProbe1;
    if (xf86IsOptionSet(FlagOptions, FLAG_PCIPROBE2))
	xf86Info.pciFlags = PCIProbe2;
    if (xf86IsOptionSet(FlagOptions, FLAG_PCIFORCECONFIG1))
	xf86Info.pciFlags = PCIForceConfig1;
    if (xf86IsOptionSet(FlagOptions, FLAG_PCIFORCECONFIG2))
	xf86Info.pciFlags = PCIForceConfig2;
    if (xf86IsOptionSet(FlagOptions, FLAG_PCIOSCONFIG))
	xf86Info.pciFlags = PCIOsConfig;
    if (xf86IsOptionSet(FlagOptions, FLAG_PCIFORCENONE))
	xf86Info.pciFlags = PCIForceNone;

    xf86Info.pmFlag = TRUE;
    if (xf86GetOptValBool(FlagOptions, FLAG_NOPM, &value)) 
	xf86Info.pmFlag = !value;
    {
	const char *s;
	if ((s = xf86GetOptValString(FlagOptions, FLAG_LOG))) {
	    if (!xf86NameCmp(s,"flush")) {
		xf86Msg(X_CONFIG, "Flushing logfile enabled\n");
		LogSetParameter(XLOG_FLUSH, TRUE);
	    } else if (!xf86NameCmp(s,"sync")) {
		xf86Msg(X_CONFIG, "Syncing logfile enabled\n");
		LogSetParameter(XLOG_SYNC, TRUE);
	    } else {
		xf86Msg(X_WARNING,"Unknown Log option.\n");
	    }
        }
    }
    
#ifdef RENDER
    {
	const char *s;

	if ((s = xf86GetOptValString(FlagOptions, FLAG_RENDER_COLORMAP_MODE))){
	    int policy = PictureParseCmapPolicy (s);
	    if (policy == PictureCmapPolicyInvalid)
		xf86Msg(X_WARNING, "Unknown colormap policy \"%s\".\n", s);
	    else
	    {
		xf86Msg(X_CONFIG, "Render colormap policy set to %s\n", s);
		PictureCmapPolicy = policy;
	    }
	}
    }
#endif
    {
	const char *s;
	if ((s = xf86GetOptValString(FlagOptions, FLAG_HANDLE_SPECIAL_KEYS))) {
	    if (!xf86NameCmp(s,"always")) {
		xf86Msg(X_CONFIG, "Always handling special keys in DDX\n");
		xf86Info.ddxSpecialKeys = SKAlways;
	    } else if (!xf86NameCmp(s,"whenneeded")) {
		xf86Msg(X_CONFIG, "Special keys handled in DDX only if needed\n");
		xf86Info.ddxSpecialKeys = SKWhenNeeded;
	    } else if (!xf86NameCmp(s,"never")) {
		xf86Msg(X_CONFIG, "Never handling special keys in DDX\n");
		xf86Info.ddxSpecialKeys = SKNever;
	    } else {
		xf86Msg(X_WARNING,"Unknown HandleSpecialKeys option.\n");
	    }
        }
    }
#ifdef RANDR
    xf86Info.disableRandR = FALSE;
    xf86Info.randRFrom = X_DEFAULT;
    if (xf86GetOptValBool(FlagOptions, FLAG_RANDR, &value)) {
	xf86Info.disableRandR = !value;
	xf86Info.randRFrom = X_CONFIG;
    }
#endif
    i = -1;
    xf86GetOptValInteger(FlagOptions, FLAG_ESTIMATE_SIZES_AGGRESSIVELY, &i);
    if (i >= 0)
	xf86Info.estimateSizesAggressively = i;
    else
	xf86Info.estimateSizesAggressively = 0;
	
    i = -1;
    xf86GetOptValInteger(FlagOptions, FLAG_SAVER_BLANKTIME, &i);
    if (i >= 0)
	ScreenSaverTime = defaultScreenSaverTime = i * MILLI_PER_MIN;

#ifdef DPMSExtension
    i = -1;
    xf86GetOptValInteger(FlagOptions, FLAG_DPMS_STANDBYTIME, &i);
    if (i >= 0)
	DPMSStandbyTime = defaultDPMSStandbyTime = i * MILLI_PER_MIN;
    i = -1;
    xf86GetOptValInteger(FlagOptions, FLAG_DPMS_SUSPENDTIME, &i);
    if (i >= 0)
	DPMSSuspendTime = defaultDPMSSuspendTime = i * MILLI_PER_MIN;
    i = -1;
    xf86GetOptValInteger(FlagOptions, FLAG_DPMS_OFFTIME, &i);
    if (i >= 0)
	DPMSOffTime = defaultDPMSOffTime = i * MILLI_PER_MIN;
#endif

    i = -1;
    xf86GetOptValInteger(FlagOptions, FLAG_PIXMAP, &i);
    switch (i) {
    case 24:
	pix24 = Pix24Use24;
	break;
    case 32:
	pix24 = Pix24Use32;
	break;
    case -1:
	break;
    default:
	xf86ConfigError("Pixmap option's value (%d) must be 24 or 32\n", i);
	return FALSE;
    }
    if (xf86Pix24 != Pix24DontCare) {
	xf86Info.pixmap24 = xf86Pix24;
	xf86Info.pix24From = X_CMDLINE;
    } else if (pix24 != Pix24DontCare) {
	xf86Info.pixmap24 = pix24;
	xf86Info.pix24From = X_CONFIG;
    } else {
	xf86Info.pixmap24 = Pix24DontCare;
	xf86Info.pix24From = X_DEFAULT;
    }
#if defined(i386) || defined(__i386__)
    if (xf86GetOptValBool(FlagOptions, FLAG_PC98, &value)) {
	xf86Info.pc98 = value;
	if (value) {
	    xf86Msg(X_CONFIG, "Japanese PC98 architecture\n");
	}
    } else
	if (detectPC98()) {
	    xf86Info.pc98 = TRUE;
	    xf86Msg(X_PROBED, "Japanese PC98 architecture\n");
	}
#endif

#ifdef PANORAMIX
    from = X_DEFAULT;
    if (!noPanoramiXExtension)
      from = X_CMDLINE;
    else if (xf86GetOptValBool(FlagOptions, FLAG_XINERAMA, &value)) {
      noPanoramiXExtension = !value;
      from = X_CONFIG;
    }
    if (!noPanoramiXExtension)
      xf86Msg(from, "Xinerama: enabled.\n");
#endif

    xf86MsgVerb(X_INFO, 3, "Checking for unused ServerFlags options:\n");
    xf86ShowUnusedOptionsVerb(-1, f->options, 3);
    return f;
}

/*
 * XXX This function is temporary, and will be removed when the keyboard
 * driver is converted into a regular input driver.
 */
static Bool
configInputKbd(IDevPtr pIDev)
{
    char *s;
    MessageType from = X_DEFAULT;
    Bool customKeycodesDefault = FALSE;
    int verb = 0;

    /* Initialize defaults */
    xf86Info.xleds = 0L;
    xf86Info.kbdDelay = 500;
    xf86Info.kbdRate = 30;
    xf86Info.kbdProc = NULL;
    xf86Info.vtinit = NULL;
    xf86Info.vtSysreq = VT_SYSREQ_DEFAULT;
#if defined(SVR4) && defined(i386)
    xf86Info.panix106 = FALSE;
#endif
    xf86Info.kbdCustomKeycodes = FALSE;
#ifdef WSCONS_SUPPORT
    xf86Info.kbdFd = -1;
#endif
#ifdef XKB
    if (!xf86IsPc98()) {
	xf86Info.xkbrules = "xfree86";
	xf86Info.xkbmodel = "pc105";
	xf86Info.xkblayout = "us";
	xf86Info.xkbvariant = NULL;
	xf86Info.xkboptions = NULL;
    } else {
	xf86Info.xkbrules = "xfree98";
	xf86Info.xkbmodel = "pc98";
	xf86Info.xkblayout = "nec/jp";
	xf86Info.xkbvariant = NULL;
	xf86Info.xkboptions = NULL;
    }
    xf86Info.xkbcomponents_specified = FALSE;
    /* Should discourage the use of these. */
    xf86Info.xkbkeymap = NULL;
    xf86Info.xkbtypes = NULL;
    xf86Info.xkbcompat = NULL;
    xf86Info.xkbkeycodes = NULL;
    xf86Info.xkbsymbols = NULL;
    xf86Info.xkbgeometry = NULL;
#endif

    s = xf86SetStrOption(pIDev->commonOptions, "Protocol", "standard");
    if (xf86NameCmp(s, "standard") == 0) {
	xf86Info.kbdProc = xf86KbdProc;
	xf86Info.kbdEvents = xf86KbdEvents;
	xfree(s);
    } else if (xf86NameCmp(s, "xqueue") == 0) {
#ifdef XQUEUE
	xf86Info.kbdProc = xf86XqueKbdProc;
	xf86Info.kbdEvents = xf86XqueEvents;
	xf86Msg(X_CONFIG, "Xqueue selected for keyboard input.\n");
#endif
	xfree(s);
#ifdef WSCONS_SUPPORT
    } else if (xf86NameCmp(s, "wskbd") == 0) {
	xf86Info.kbdProc = xf86KbdProc;
	xf86Info.kbdEvents = xf86WSKbdEvents;
	xfree(s);
	s = xf86SetStrOption(pIDev->commonOptions, "Device", NULL);
	xf86Msg(X_CONFIG, "Keyboard: Protocol: wskbd\n");
	if (!s) {
	   xf86ConfigError("A \"device\" option is required with"
			   " the \"wskbd\" keyboard protocol.");
	   return FALSE;
	}
	xf86Info.kbdFd = open(s, O_RDWR | O_NONBLOCK | O_EXCL);
	if (xf86Info.kbdFd == -1) {
	    xf86ConfigError("cannot open \"%s\"", s);
	    xfree(s);
	    return FALSE;
	}
	xfree(s);
	/* Find out keyboard type. */
	if (ioctl(xf86Info.kbdFd, WSKBDIO_GTYPE, &xf86Info.wsKbdType) == -1) {
	    xf86ConfigError("Cannot get keyboard type.");
	    close(xf86Info.kbdFd);
	    return FALSE;
	}
	switch (xf86Info.wsKbdType) {
	case WSKBD_TYPE_PC_XT:
	    xf86Msg(X_PROBED, "Keyboard type: XT\n");
	    break;
	case WSKBD_TYPE_PC_AT:
	    xf86Msg(X_PROBED, "Keyboard type: AT\n");
	    break;
	case WSKBD_TYPE_USB:
	    xf86Msg(X_PROBED, "Keyboard type: USB\n");
	    break;
#ifdef WSKBD_TYPE_ADB
	case WSKBD_TYPE_ADB:
	    xf86Msg(X_PROBED, "Keyboard type: ADB\n");
	    break;
#endif
#ifdef WSKBD_TYPE_SUN
	case WSKBD_TYPE_SUN:
	    xf86Msg(X_PROBED, "Keyboard type: Sun\n");
	    break;
#endif
#ifdef WSKBD_TYPE_SUN5
	case WSKBD_TYPE_SUN5:
	    xf86Msg(X_PROBED, "Keyboard type: Sun5\n");
	    break;
#endif
	default:
	    xf86ConfigError("Unsupported wskbd type \"%d\"", 
			    xf86Info.wsKbdType);
	    close(xf86Info.kbdFd);
	    return FALSE;
	}
#endif
    } else {
	xf86ConfigError("\"%s\" is not a valid keyboard protocol name.", s);
	xfree(s);
	return FALSE;
    }

    s = xf86SetStrOption(pIDev->commonOptions, "AutoRepeat", NULL);
    if (s) {
	if (sscanf(s, "%d %d", &xf86Info.kbdDelay, &xf86Info.kbdRate) != 2) {
	    xf86ConfigError("\"%s\" is not a valid AutoRepeat value", s);
	    xfree(s);
	    return FALSE;
	}
	xfree(s);
    }

    s = xf86SetStrOption(pIDev->commonOptions, "XLeds", NULL);
    if (s) {
	char *l, *end;
	unsigned int i;
	l = strtok(s, " \t\n");
	while (l) {
	    i = strtoul(l, &end, 0);
	    if (*end == '\0')
		xf86Info.xleds |= 1L << (i - 1);
	    else {
		xf86ConfigError("\"%s\" is not a valid XLeds value", l);
		xfree(s);
		return FALSE;
	    }
	    l = strtok(NULL, " \t\n");
	}
	xfree(s);
    }

#ifdef XKB
    from = X_DEFAULT;
    if (noXkbExtension)
	from = X_CMDLINE;
    else if (xf86FindOption(pIDev->commonOptions, "XkbDisable")) {
	xf86Msg(X_WARNING, "KEYBOARD: XKB should be disabled in the "
	    "ServerFlags section instead\n"
	    "\tof in the \"keyboard\" InputDevice section.\n");
	noXkbExtension =
	xf86SetBoolOption(pIDev->commonOptions, "XkbDisable", FALSE);
	from = X_CONFIG;
    }
    if (noXkbExtension)
	xf86Msg(from, "XKB: disabled.\n");

#define NULL_IF_EMPTY(s) (s[0] ? s : (xfree(s), (char *)NULL))

    if (!noXkbExtension && !XkbInitialMap) {
	if ((s = xf86SetStrOption(pIDev->commonOptions, "XkbKeymap", NULL))) {
	    xf86Info.xkbkeymap = NULL_IF_EMPTY(s);
	    xf86Msg(X_CONFIG, "XKB: keymap: \"%s\" "
		    "(overrides other XKB settings)\n", xf86Info.xkbkeymap);
	} else {
	    if ((s = xf86SetStrOption(pIDev->commonOptions, "XkbCompat",
				      NULL))) {
		xf86Info.xkbcompat = NULL_IF_EMPTY(s);
		xf86Info.xkbcomponents_specified = TRUE;
		xf86Msg(X_CONFIG, "XKB: compat: \"%s\"\n", s);
	    }

	    if ((s = xf86SetStrOption(pIDev->commonOptions, "XkbTypes",
				      NULL))) {
		xf86Info.xkbtypes = NULL_IF_EMPTY(s);
		xf86Info.xkbcomponents_specified = TRUE;
		xf86Msg(X_CONFIG, "XKB: types: \"%s\"\n", s);
	    }

	    if ((s = xf86SetStrOption(pIDev->commonOptions, "XkbKeycodes",
				      NULL))) {
		xf86Info.xkbkeycodes = NULL_IF_EMPTY(s);
		xf86Info.xkbcomponents_specified = TRUE;
		xf86Msg(X_CONFIG, "XKB: keycodes: \"%s\"\n", s);
	    }

	    if ((s = xf86SetStrOption(pIDev->commonOptions, "XkbGeometry",
				      NULL))) {
		xf86Info.xkbgeometry = NULL_IF_EMPTY(s);
		xf86Info.xkbcomponents_specified = TRUE;
		xf86Msg(X_CONFIG, "XKB: geometry: \"%s\"\n", s);
	    }

	    if ((s = xf86SetStrOption(pIDev->commonOptions, "XkbSymbols",
				      NULL))) {
		xf86Info.xkbsymbols = NULL_IF_EMPTY(s);
		xf86Info.xkbcomponents_specified = TRUE;
		xf86Msg(X_CONFIG, "XKB: symbols: \"%s\"\n", s);
	    }

	    if ((s = xf86SetStrOption(pIDev->commonOptions, "XkbRules",
				      NULL))) {
		xf86Info.xkbrules = NULL_IF_EMPTY(s);
		xf86Info.xkbcomponents_specified = TRUE;
		xf86Msg(X_CONFIG, "XKB: rules: \"%s\"\n", s);
	    }

	    if ((s = xf86SetStrOption(pIDev->commonOptions, "XkbModel",
				      NULL))) {
		xf86Info.xkbmodel = NULL_IF_EMPTY(s);
		xf86Info.xkbcomponents_specified = TRUE;
		xf86Msg(X_CONFIG, "XKB: model: \"%s\"\n", s);
	    }

	    if ((s = xf86SetStrOption(pIDev->commonOptions, "XkbLayout",
				      NULL))) {
		xf86Info.xkblayout = NULL_IF_EMPTY(s);
		xf86Info.xkbcomponents_specified = TRUE;
		xf86Msg(X_CONFIG, "XKB: layout: \"%s\"\n", s);
	    }

	    if ((s = xf86SetStrOption(pIDev->commonOptions, "XkbVariant",
				      NULL))) {
		xf86Info.xkbvariant = NULL_IF_EMPTY(s);
		xf86Info.xkbcomponents_specified = TRUE;
		xf86Msg(X_CONFIG, "XKB: variant: \"%s\"\n", s);
	    }

	    if ((s = xf86SetStrOption(pIDev->commonOptions, "XkbOptions",
				      NULL))) {
		xf86Info.xkboptions = NULL_IF_EMPTY(s);
		xf86Info.xkbcomponents_specified = TRUE;
		xf86Msg(X_CONFIG, "XKB: options: \"%s\"\n", s);
	    }
	}
    }
#undef NULL_IF_EMPTY
#endif
#if defined(SVR4) && defined(i386)
    if ((xf86Info.panix106 =
		xf86SetBoolOption(pIDev->commonOptions, "Panix106", FALSE))) {
	xf86Msg(X_CONFIG, "PANIX106: enabled\n");
    }
#endif

    /*
     * This was once a compile time option (ASSUME_CUSTOM_KEYCODES)
     * defaulting to 1 on Linux/PPC. It is no longer necessary, but for
     * backwards compatibility we provide 'Option "CustomKeycodes"'
     * and try to autoprobe on Linux/PPC.
     */
    from = X_DEFAULT;
    verb = 2;
#if defined(__linux__) && defined(__powerpc__)
    {
	FILE *f;

	f = fopen("/proc/sys/dev/mac_hid/keyboard_sends_linux_keycodes","r");
	if (f) {
	    if (fgetc(f) == '0') {
		customKeycodesDefault = TRUE;
		from = X_PROBED;
		verb = 1;
	    }
	    fclose(f);
	}
    }
#endif
    if (xf86FindOption(pIDev->commonOptions, "CustomKeycodes")) {
	from = X_CONFIG;
	verb = 1;
    }
    xf86Info.kbdCustomKeycodes =
	xf86SetBoolOption(pIDev->commonOptions, "CustomKeycodes",
			  customKeycodesDefault);
    xf86MsgVerb(from, verb, "Keyboard: CustomKeycode %s.\n",
		xf86Info.kbdCustomKeycodes ? "enabled" : "disabled");
    return TRUE;
}

/*
 * Locate the core input devices.  These can be specified/located in
 * the following ways, in order of priority:
 *
 *  1. The InputDevices named by the -pointer and -keyboard command line
 *     options.
 *  2. The "CorePointer" and "CoreKeyboard" InputDevices referred to by
 *     the active ServerLayout.
 *  3. The first InputDevices marked as "CorePointer" and "CoreKeyboard".
 *  4. The first InputDevices that use the 'mouse' and 'keyboard' or 'kbd'
 *     drivers.
 *  5. Default devices with an empty (default) configuration.  These defaults
 *     will reference the 'mouse' and 'keyboard' drivers.
 */

static Bool
checkCoreInputDevices(ConfigHandle handle, serverLayoutPtr pServerLayout,
		      Bool implicitLayout)
{
    int i, j, n;
    IDevPtr corePointer = NULL, coreKeyboard = NULL;
    Bool foundPointer = FALSE, foundKeyboard = FALSE;
    const char *pointerMsg = NULL, *keyboardMsg = NULL;
    IDevPtr indp, pIDev = NULL;
    XF86ConfInputRec defPtr, defKbd;
    pointer opt1 = NULL, opt2 = NULL;

    /*
     * First check if a core pointer or core keyboard have been specified
     * in the active ServerLayout.  If more than one is specified for either,
     * remove the core attribute from the later ones.
     */
    for (i = 0; i < pServerLayout->numInputs; i++) {
	indp = pServerLayout->inputDevs[i];
	if (!indp)
	    continue;
	opt1 = opt2 = NULL;
	if (indp->commonOptions &&
	    xf86CheckBoolOption(indp->commonOptions, "CorePointer", FALSE)) {
	    opt1 = indp->commonOptions;
	}
	if (indp->extraOptions &&
	    xf86CheckBoolOption(indp->extraOptions, "CorePointer", FALSE)) {
	    opt2 = indp->extraOptions;
	}
	if (opt1 || opt2) {
	    if (!corePointer) {
		corePointer = indp;
		corePointer->from = X_CONFIG;
	    } else {
		if (opt1)
		    xf86ReplaceBoolOption(opt1, "CorePointer", FALSE);
		if (opt2)
		    xf86ReplaceBoolOption(opt2, "CorePointer", FALSE);
		xf86Msg(X_WARNING, "Duplicate core pointer devices.  "
			"Removing core pointer attribute from \"%s\".\n",
			indp->identifier);
	    }
	}
	opt1 = opt2 = NULL;
	if (indp->commonOptions &&
	    xf86CheckBoolOption(indp->commonOptions, "CoreKeyboard", FALSE)) {
	    opt1 = indp->commonOptions;
	}
	if (indp->extraOptions &&
	    xf86CheckBoolOption(indp->extraOptions, "CoreKeyboard", FALSE)) {
	    opt2 = indp->extraOptions;
	}
	if (opt1 || opt2) {
	    if (!coreKeyboard) {
		coreKeyboard = indp;
		coreKeyboard->from = X_CONFIG;
	    } else {
		if (opt1)
		    xf86ReplaceBoolOption(opt1, "CoreKeyboard", FALSE);
		if (opt2)
		    xf86ReplaceBoolOption(opt2, "CoreKeyboard", FALSE);
		xf86Msg(X_WARNING, "Duplicate core keyboard devices.  "
			"Removing core keyboard attribute from \"%s\".\n",
			indp->identifier);
	    }
	}
    }

    /* 1. Check for the -pointer command line option. */
    if (xf86PointerName) {
	pIDev = xf86ConfGetInputDeviceByName(handle, xf86PointerName);
	if (!pIDev) {
	    xf86Msg(X_ERROR, "No InputDevice section called \"%s\".\n",
		    xf86PointerName);
	    return FALSE;
	}
	pIDev->from = X_CMDLINE;
	/*
	 * If one was already specified in the ServerLayout, it needs to be
	 * removed.
	 */
	if (corePointer) {
	    for (i = 0; i < pServerLayout->numInputs; i++) {
		indp = pServerLayout->inputDevs[i];
		if (indp == corePointer) {
		    xf86ConfFreeInputDeviceData(indp);
		    pServerLayout->numInputs--;
		    for (j = i; j < pServerLayout->numInputs; j++) {
			pServerLayout->inputDevs[j] =
				pServerLayout->inputDevs[j + 1];
		    }
		    pServerLayout->inputDevs[j] = NULL;
		    break;
		}
	    }
	}
	corePointer = NULL;
	foundPointer = TRUE;
    }

    /* 2. ServerLayout-specified core pointer. */
    if (corePointer) {
	foundPointer = TRUE;
	corePointer->from = X_CONFIG;
    }

    /* 3. First core pointer device. */
    if (!foundPointer) {
	pIDev = xf86ConfGetInputDeviceByOption(handle, "CorePointer");
	if (pIDev) {
	    foundPointer = TRUE;
	    pIDev->from = X_DEFAULT;
	    pointerMsg = "first core pointer device";
	}
    }

    /*
     * 4. First pointer named CONF_IMPLICIT_POINTER or with 'mouse' as
     *    the driver.
     */
    if (!foundPointer) {
	pIDev = xf86ConfGetInputDeviceByName(handle, CONF_IMPLICIT_POINTER);
	if (!pIDev)
	    pIDev = xf86ConfGetInputDeviceByDriver(handle, "mouse");
	if (pIDev) {
	    foundPointer = TRUE;
	    pIDev->from = X_DEFAULT;
	    pointerMsg = "first mouse device";
	}
    }

    /* 5. Built-in default. */
    if (!foundPointer) {
	bzero(&defPtr, sizeof(defPtr));
	defPtr.inp_identifier = xstrdup("<default pointer>");
	defPtr.inp_driver = xstrdup("mouse");
	pIDev = xf86ConfAllocInputDevice();
	if (pIDev) {
	    if (!convertInputDevice(pIDev, &defPtr)) {
		xfree(pIDev);
		pIDev = NULL;
	    } else {
		foundPointer = TRUE;
		pIDev->from = X_DEFAULT;
		pointerMsg = "default mouse configuration";
	    }
	}
    }

    /* Add the core pointer device to the layout, and set it to Core. */
    if (foundPointer && pIDev) {
	IDevPtr *newDevs;
	char **newNames;
	pointer *newOpts;

	n = pServerLayout->numInputs++;
	newDevs = xrealloc(pServerLayout->inputDevs,
			   pServerLayout->numInputs * sizeof(*newDevs));
	if (!newDevs) {
	    xf86Msg(X_ERROR, "Allocation of new input device list failed.\n");
	    return FALSE;
	}
	pServerLayout->inputDevs = newDevs;
	newNames = xrealloc(pServerLayout->inputNames,
			    pServerLayout->numInputs * sizeof(newDevs));
	if (!newNames) {
	    xf86Msg(X_ERROR, "Allocation of new input device list failed.\n");
	    return FALSE;
	}
	pServerLayout->inputNames = newNames;
	newOpts = xrealloc(pServerLayout->inputExtraOptions,
			   pServerLayout->numInputs * sizeof(*newOpts));
	if (!newOpts) {
	    xf86Msg(X_ERROR, "Allocation of new input device list failed.\n");
	    return FALSE;
	}
	pServerLayout->inputExtraOptions = newOpts;
	pIDev->extraOptions = xf86addNewOption(NULL, "CorePointer", NULL);
	pServerLayout->inputDevs[n] = pIDev;
	pServerLayout->inputNames[n] = xstrdup(pIDev->identifier);
	pServerLayout->inputExtraOptions[n] =
		xf86OptionListDup(pIDev->extraOptions);
	pIDev = NULL;
    }

    if (!foundPointer) {
	/* This shouldn't happen. */
	xf86Msg(X_ERROR, "Cannot locate a core pointer device.\n");
	return FALSE;
    }

    /* 1. Check for the -keyboard command line option. */
    if (xf86KeyboardName) {
	pIDev = xf86ConfGetInputDeviceByName(handle, xf86KeyboardName);
	if (!pIDev) {
	    xf86Msg(X_ERROR, "No InputDevice section called \"%s\".\n",
		    xf86KeyboardName);
	    return FALSE;
	}
	pIDev->from = X_CMDLINE;
	/*
	 * If one was already specified in the ServerLayout, it needs to be
	 * removed.
	 */
	if (coreKeyboard) {
	    for (i = 0; i < pServerLayout->numInputs; i++) {
		indp = pServerLayout->inputDevs[i];
		if (indp == coreKeyboard) {
		    xf86ConfFreeInputDeviceData(indp);
		    pServerLayout->numInputs--;
		    for (j = i; j < pServerLayout->numInputs; j++) {
			pServerLayout->inputDevs[j] =
				pServerLayout->inputDevs[j + 1];
		    }
		    pServerLayout->inputDevs[j] = NULL;
		    break;
		}
	    }
	}
	coreKeyboard = NULL;
	foundKeyboard = TRUE;
    }

    /* 2. ServerLayout-specified core keyboard. */
    if (coreKeyboard) {
	foundKeyboard = TRUE;
	coreKeyboard->from = X_CONFIG;
    }

    /* 3. First core keyboard device. */
    if (!foundKeyboard) {
	pIDev = xf86ConfGetInputDeviceByOption(handle, "CoreKeyboard");
	if (pIDev) {
	    foundKeyboard = TRUE;
	    pIDev->from = X_DEFAULT;
	    keyboardMsg = "first core keyboard device";
	}
    }

    /*
     * 4. First keyboard named CONF_IMPLICIT_KEYBOARD, or with 'keyboard'
     *    or 'kbd' as the driver.
     */
    if (!foundKeyboard) {
	pIDev = xf86ConfGetInputDeviceByName(handle, CONF_IMPLICIT_KEYBOARD);
	if (!pIDev)
	    pIDev = xf86ConfGetInputDeviceByDriver(handle, "keyboard");
	if (!pIDev)
	    pIDev = xf86ConfGetInputDeviceByDriver(handle, "kbd");
	if (pIDev) {
	    foundKeyboard = TRUE;
	    pIDev->from = X_DEFAULT;
	    keyboardMsg = "first keyboard device";
	}
    }

    /* 5. Built-in default. */
    if (!foundKeyboard) {
	bzero(&defKbd, sizeof(defKbd));
	defKbd.inp_identifier = xstrdup("<default keyboard>");
	defKbd.inp_driver = xstrdup("keyboard");
	pIDev = xf86ConfAllocInputDevice();
	if (pIDev) {
	    if (!convertInputDevice(pIDev, &defKbd)) {
		xfree(pIDev);
		pIDev = NULL;
	    } else {
		foundKeyboard = TRUE;
		pIDev->from = X_DEFAULT;
		keyboardMsg = "default keyboard configuration";
	    }
	}
    }

    /* Add the core keyboard device to the layout, and set it to Core. */
    if (foundKeyboard && pIDev) {
	if (!xf86NameCmp(pIDev->driver, "keyboard"))
	    foundKeyboard = configInputKbd(pIDev);
	if (foundKeyboard) {
	    IDevPtr *newDevs;
	    char **newNames;
	    pointer *newOpts;

	    n = pServerLayout->numInputs++;
	    newDevs = xrealloc(pServerLayout->inputDevs,
			       pServerLayout->numInputs * sizeof(*newDevs));
	    if (!newDevs) {
		xf86Msg(X_ERROR,
			"Allocation of new input device list failed.\n");
		return FALSE;
	    }
	    pServerLayout->inputDevs = newDevs;
	    newNames = xrealloc(pServerLayout->inputNames,
				pServerLayout->numInputs * sizeof(newDevs));
	    if (!newNames) {
		xf86Msg(X_ERROR,
			"Allocation of new input device list failed.\n");
		return FALSE;
	    }
	    pServerLayout->inputNames = newNames;
	    newOpts = xrealloc(pServerLayout->inputExtraOptions,
			       pServerLayout->numInputs * sizeof(*newOpts));
	    if (!newOpts) {
		xf86Msg(X_ERROR,
			"Allocation of new input device list failed.\n");
		return FALSE;
	    }
	    pServerLayout->inputExtraOptions = newOpts;
	    pIDev->extraOptions = xf86addNewOption(NULL, "CoreKeyboard", NULL);
	    pServerLayout->inputDevs[n] = pIDev;
	    pServerLayout->inputNames[n] = xstrdup(pIDev->identifier);
	    pServerLayout->inputExtraOptions[n] =
		    xf86OptionListDup(pIDev->extraOptions);
	    pIDev = NULL;
	}
    }

    if (!foundKeyboard) {
	/* This shouldn't happen. */
	xf86Msg(X_ERROR, "Cannot locate a core keyboard device.\n");
	return FALSE;
    }

    if (pointerMsg) {
	xf86Msg(X_WARNING, "The core pointer device wasn't specified "
		"explicitly in the layout.\n"
		"\tUsing the %s.\n", pointerMsg);
    }

    if (keyboardMsg) {
	xf86Msg(X_WARNING, "The core keyboard device wasn't specified "
		"explicitly in the layout.\n"
		"\tUsing the %s.\n", keyboardMsg);
    }
    return TRUE;
}

screenLayoutPtr
xf86ConfAllocScreenLayout()
{
    screenLayoutPtr pScreenLayout;

    pScreenLayout = xcalloc(1, sizeof(*pScreenLayout));
    pScreenLayout->where = PosAbsolute;
    pScreenLayout->x = -1;
    pScreenLayout->y = -1;
    return pScreenLayout;
}

void
xf86ConfFreeScreenLayoutData(screenLayoutPtr pScreenLayout)
{
    if (!pScreenLayout)
	return;

    if (pScreenLayout->screen) {
	xf86ConfFreeScreenData(pScreenLayout->screen);
	pScreenLayout->screen = NULL;
    }
    if (pScreenLayout->refname) {
	xfree(pScreenLayout->refname);
	pScreenLayout->refname = NULL;
    }
    if (pScreenLayout->screenName) {
	xfree(pScreenLayout->screenName);
	pScreenLayout->screenName = NULL;
    }
    pScreenLayout->refscreen = NULL;
}

screenLayoutPtr
xf86ConfDupScreenLayout(const screenLayoutRec *pScreenLayout, int depth)
{
    screenLayoutPtr s;

    if (!pScreenLayout)
	return NULL;

    s = xf86ConfAllocScreenLayout();
    if (!s)
	return NULL;

    s->screenName = xstrdup(pScreenLayout->screenName);
    if (pScreenLayout->screenName && !s->screenName) {
	xf86ConfFreeScreenLayoutData(s);
	xfree(s);
	return NULL;
    }
    s->screenNum = pScreenLayout->screenNum;
    s->x = pScreenLayout->x;
    s->y = pScreenLayout->y;
    s->refname = xstrdup(pScreenLayout->refname);
    if (pScreenLayout->refname && !s->refname) {
	xf86ConfFreeScreenLayoutData(s);
	xfree(s);
	return NULL;
    }
    s->where = pScreenLayout->where;
    if (depth > 0) {
	s->screen = xf86ConfDupScreen(pScreenLayout->screen, depth - 1);
	s->refscreen = pScreenLayout->refscreen;
    }
    return s;
}

static screenLayoutPtr
convertScreenLayout(screenLayoutPtr pScreenLayout,
		    const XF86ConfAdjacencyRec *adjacency)
{
    if (!pScreenLayout)
	return NULL;

    pScreenLayout->screenName = xstrdup(adjacency->adj_screen_str);
    if (adjacency->adj_screen_str && !pScreenLayout->screenName) {
	xf86ConfFreeScreenLayoutData(pScreenLayout);
	return NULL;
    }
    pScreenLayout->screenNum = adjacency->adj_scrnum;
    pScreenLayout->x = adjacency->adj_x;
    pScreenLayout->y = adjacency->adj_y;
    pScreenLayout->refname = xstrdup(adjacency->adj_refscreen);
    if (adjacency->adj_refscreen && !pScreenLayout->refname) {
	xf86ConfFreeScreenLayoutData(pScreenLayout);
	return NULL;
    }
    switch (adjacency->adj_where) {
    case CONF_ADJ_ABSOLUTE:
	pScreenLayout->where = PosAbsolute;
	break;
    case CONF_ADJ_RIGHTOF:
	pScreenLayout->where = PosRightOf;
	break;
    case CONF_ADJ_LEFTOF:
	pScreenLayout->where = PosLeftOf;
	break;
    case CONF_ADJ_ABOVE:
	pScreenLayout->where = PosAbove;
	break;
    case CONF_ADJ_BELOW:
	pScreenLayout->where = PosBelow;
	break;
    case CONF_ADJ_RELATIVE:
	pScreenLayout->where = PosRelative;
	break;
    case CONF_ADJ_OBSOLETE:
	xf86Msg(X_ERROR,
		"Obsolete screen layout encountered for screen \"%s\".\n"
		"\tThis is no longer supported.  "
		"Default positioning will be used.\n",
		pScreenLayout->screenName);
	pScreenLayout->where = PosAbsolute;
	pScreenLayout->x = -1;
	pScreenLayout->y = -1;
	break;
    }
    return pScreenLayout;
}

serverLayoutPtr
xf86ConfAllocServerLayout()
{
    serverLayoutPtr pServerLayout;

    pServerLayout = xcalloc(1, sizeof(*pServerLayout));
    pServerLayout->handle = pServerLayout;
    pServerLayout->from = X_NONE;
    return pServerLayout;
}

void
xf86ConfFreeServerLayoutData(serverLayoutPtr pServerLayout)
{
    int i;

    if (!pServerLayout)
	return;

    if (pServerLayout->screenLayouts) {
	for (i = 0; i < pServerLayout->numScreens; i++)  {
	    xf86ConfFreeScreenLayoutData(pServerLayout->screenLayouts[i]);
	    xfree(pServerLayout->screenLayouts[i]);
	    pServerLayout->screenLayouts[i] = NULL;
	}
	xfree(pServerLayout->screenLayouts);
	pServerLayout->screenLayouts = NULL;
    }
    pServerLayout->numScreens = 0;
    if (pServerLayout->inactiveNames) {
	for (i = 0; i < pServerLayout->numInactives; i++) {
	    xfree(pServerLayout->inactiveNames[i]);
	    pServerLayout->inactiveNames[i] = NULL;
	}
	xfree(pServerLayout->inactiveNames);
	pServerLayout->inactiveNames = NULL;
    }
    if (pServerLayout->inactiveDevs) {
	for (i = 0; i < pServerLayout->numInactives; i++) {
	    xf86ConfFreeGraphicsDeviceData(pServerLayout->inactiveDevs[i]);
	    xfree(pServerLayout->inactiveDevs[i]);
	    pServerLayout->inactiveDevs[i] = NULL;
	}
	xfree(pServerLayout->inactiveDevs);
	pServerLayout->inactiveDevs = NULL;
    }
    pServerLayout->numInactives = 0;
    if (pServerLayout->inputNames) {
	for (i = 0; i < pServerLayout->numInputs; i++) {
	    xfree(pServerLayout->inputNames[i]);
	    pServerLayout->inputNames[i] = NULL;
	}
	xfree(pServerLayout->inputNames);
	pServerLayout->inputNames = NULL;
    }
    if (pServerLayout->inputExtraOptions) {
	for (i = 0; i < pServerLayout->numInputs; i++) {
	    xf86OptionListFree(pServerLayout->inputExtraOptions[i]);
	    pServerLayout->inputExtraOptions[i] = NULL;
	}
	xfree(pServerLayout->inputExtraOptions);
	pServerLayout->inputExtraOptions = NULL;
    }
    if (pServerLayout->inputDevs) {
	for (i = 0; i < pServerLayout->numInputs; i++) {
	    xf86ConfFreeInputDeviceData(pServerLayout->inputDevs[i]);
	    xfree(pServerLayout->inputDevs[i]);
	    pServerLayout->inputDevs[i] = NULL;
	}
	xfree(pServerLayout->inputDevs);
	pServerLayout->inputDevs = NULL;
    }
    pServerLayout->numInputs = 0;
    if (pServerLayout->id) {
	xfree(pServerLayout->id);
	pServerLayout->id = NULL;
    }
    if (pServerLayout->options) {
	xf86OptionListFree(pServerLayout->options);
	pServerLayout->options = NULL;
    }
}

serverLayoutPtr
xf86ConfDupServerLayout(const serverLayoutRec *pServerLayout, int depth)
{
    serverLayoutPtr s;
    int i;

    if (!pServerLayout)
	return NULL;

    s = xf86ConfAllocServerLayout();
    if (!s)
	return NULL;

    s->handle = pServerLayout->handle;
    s->from = pServerLayout->from;
    s->numScreens = pServerLayout->numScreens;
    if (s->numScreens > 0) {
	s->screenLayouts = xcalloc(s->numScreens, sizeof(screenLayoutPtr));
	if (!s->screenLayouts) {
	    xfree(s);
	    return NULL;
	}
	for (i = 0; i < s->numScreens; i++) {
	    s->screenLayouts[i] =
		xf86ConfDupScreenLayout(pServerLayout->screenLayouts[i], depth);
	    if (!s->screenLayouts[i]) {
		xf86ConfFreeServerLayoutData(s);
		xfree(s);
		return NULL;
	    }
	}
    }
    s->numInactives = pServerLayout->numInactives;
    if (s->numInactives > 0) {
	s->inactiveNames = xf86DupStringArray(pServerLayout->inactiveNames,
					      pServerLayout->numInactives);
	if (pServerLayout->inactiveNames && !s->inactiveNames) {
	    xf86ConfFreeServerLayoutData(s);
	    xfree(s);
	    return NULL;
	}
	if (depth > 0) {
	    s->inactiveDevs = xcalloc(s->numInactives, sizeof(GDevPtr));
	    if (!s->inactiveDevs) {
		xf86ConfFreeServerLayoutData(s);
		xfree(s);
		return NULL;
	    }
	    for (i = 0; i < s->numInactives; i++) {
		s->inactiveDevs[i] =
		    xf86ConfDupGraphicsDevice(pServerLayout->inactiveDevs[i]);
		if (pServerLayout->inactiveDevs[i] && !s->inactiveDevs[i]) {
		    xf86ConfFreeServerLayoutData(s);
		    xfree(s);
		    return NULL;
		}
	    }
	}
    }

    s->numInputs = pServerLayout->numInputs;
    if (s->numInputs > 0) {
	s->inputNames = xf86DupStringArray(pServerLayout->inputNames,
					   pServerLayout->numInputs);
	if (pServerLayout->inputNames && !s->inputNames) {
	    xf86ConfFreeServerLayoutData(s);
	    xfree(s);
	    return NULL;
	}
	if (pServerLayout->inputExtraOptions) {
	    s->inputExtraOptions = xcalloc(s->numInputs, sizeof(pointer));
	    if (!s->inputExtraOptions) {
		xf86ConfFreeServerLayoutData(s);
		xfree(s);
		return NULL;
	    }
	    for (i = 0; i < s->numInputs; i++) {
		s->inputExtraOptions[i] =
		    xf86OptionListDup(pServerLayout->inputExtraOptions[i]);
		if (pServerLayout->inputExtraOptions[i] &&
		    !s->inputExtraOptions[i]) {
		    xf86ConfFreeServerLayoutData(s);
		    xfree(s);
		    return NULL;
		}
	    }
	}
	if (depth > 0) {
	    s->inputDevs = xcalloc(s->numInputs, sizeof(IDevPtr));
	    if (!s->inputDevs) {
		xf86ConfFreeServerLayoutData(s);
		xfree(s);
		return NULL;
	    }
	    for (i = 0; i < s->numInputs; i++) {
		s->inputDevs[i] =
		    xf86ConfDupInputDevice(pServerLayout->inputDevs[i], depth);
		if (pServerLayout->inputDevs[i] && !s->inputDevs[i]) {
		    xf86ConfFreeServerLayoutData(s);
		    xfree(s);
		    return NULL;
		}
	    }
	}
    }
    s->id = xstrdup(pServerLayout->id);
    if (pServerLayout->id && !s->id) {
	xf86ConfFreeServerLayoutData(s);
	xfree(s);
	return NULL;
    }
    s->options = xf86OptionListDup(pServerLayout->options);
    if (pServerLayout->options && !s->options) {
	xf86ConfFreeServerLayoutData(s);
	xfree(s);
	return NULL;
    }
    return s;
}

/*
 * Convert a ServerLayout section from the parser's format to the server's
 * format.
 */
static serverLayoutPtr
convertServerLayout(serverLayoutPtr pServerLayout,
		    const XF86ConfLayoutRec *confLayout)
{
    XF86ConfAdjacencyPtr adjp;
    XF86ConfInactivePtr idp;
    XF86ConfInputrefPtr irp;
    int count = 0;

    if (!pServerLayout || !confLayout)
	return NULL;

    pServerLayout->handle = confLayout;

    adjp = confLayout->lay_adjacency_lst;

    /*
     * We know that each screen is referenced exactly once on the left side
     * of a Screen statement in the ServerLayout section.  So to allocate
     * the right size for the array we do a quick walk of the list to figure
     * out how many screens we have.
     */
    while (adjp) {
	count++;
	adjp = adjp->list.next;
    }
    pServerLayout->numScreens = count;
    xf86MsgVerb(X_INFO, 5, "Found %d screen%s in the layout section \"%s\".\n",
		count, PLURAL(count), confLayout->lay_identifier);
    if (count) {
	pServerLayout->screenLayouts = xcalloc(count, sizeof(screenLayoutPtr));
	if (!pServerLayout->screenLayouts)
	    return NULL;
	adjp = confLayout->lay_adjacency_lst;
	count = 0;
	while (adjp) {
	    pServerLayout->screenLayouts[count] = xf86ConfAllocScreenLayout();
	    if (!pServerLayout->screenLayouts[count]) {
		xf86ConfFreeServerLayoutData(pServerLayout);
		return NULL;
	    }
	    if (!convertScreenLayout(pServerLayout->screenLayouts[count],
				     adjp)) {
		xf86ConfFreeServerLayoutData(pServerLayout);
		return NULL;
	    }
	    if (pServerLayout->screenLayouts[count]->screenNum < 0)
		pServerLayout->screenLayouts[count]->screenNum = count;
	    count++;
	    adjp = adjp->list.next;
	}
    }

    /*
     * Count the number of inactive devices.
     * XXX Do we still need these?
     */
    count = 0;
    idp = confLayout->lay_inactive_lst;
    while (idp) {
	count++;
	idp = idp->list.next;
    }
    pServerLayout->numInactives = count;
    xf86MsgVerb(X_INFO, 5,
		"Found %d inactive device%s in the layout section \"%s\".\n",
		count, PLURAL(count), confLayout->lay_identifier);
    if (count > 0) {
	pServerLayout->inactiveNames = xcalloc(count, sizeof(char *));
	if (!pServerLayout->inactiveNames) {
	    xf86ConfFreeServerLayoutData(pServerLayout);
	    return NULL;
	}
	count = 0;
	while (idp) {
	    pServerLayout->inactiveNames[count] =
		xstrdup(idp->inactive_device_str);
	    if (idp->inactive_device_str &&
		!pServerLayout->inactiveNames[count]) {
		xf86ConfFreeServerLayoutData(pServerLayout);
		return NULL;
	    }
	    count++;
	    idp = idp->list.next;
	}
    }

    /*
     * Count the number of input devices.
     */
    count = 0;
    irp = confLayout->lay_input_lst;
    while (irp) {
	count++;
	irp = irp->list.next;
    }
    pServerLayout->numInputs = count;
    xf86MsgVerb(X_INFO, 5,
		"Found %d input device%s in the layout section \"%s\".\n",
		count, PLURAL(count), confLayout->lay_identifier);
    if (count > 0) {
	pServerLayout->inputNames = xcalloc(count, sizeof(char *));
	if (!pServerLayout->inputNames) {
	    xf86ConfFreeServerLayoutData(pServerLayout);
	    return NULL;
	}
	pServerLayout->inputExtraOptions = xcalloc(count, sizeof(pointer));
	if (!pServerLayout->inputExtraOptions) {
	    xf86ConfFreeServerLayoutData(pServerLayout);
	    return NULL;
	}
	count = 0;
	irp = confLayout->lay_input_lst;
	while (irp) {
	    pServerLayout->inputNames[count] = xstrdup(irp->iref_inputdev_str);
	    if (irp->iref_inputdev_str && !pServerLayout->inputNames[count]) {
		xf86ConfFreeServerLayoutData(pServerLayout);
		return NULL;
	    }
	    pServerLayout->inputExtraOptions[count] =
		xf86OptionListDup(irp->iref_option_lst);
	    if (irp->iref_option_lst &&
		!pServerLayout->inputExtraOptions[count]) {
		xf86ConfFreeServerLayoutData(pServerLayout);
		return NULL;
	    }
	    count++;
	    irp = irp->list.next;
	}
    }
    pServerLayout->id = xstrdup(confLayout->lay_identifier);
    if (confLayout->lay_identifier && !pServerLayout->id) {
	xf86ConfFreeServerLayoutData(pServerLayout);
	return NULL;
    }
    pServerLayout->options = xf86OptionListDup(confLayout->lay_option_lst);
    if (confLayout->lay_option_lst && !pServerLayout->options) {
	xf86ConfFreeServerLayoutData(pServerLayout);
	return NULL;
    }
    return pServerLayout;
}

serverLayoutPtr
xf86ConfGetServerLayoutByName(ConfigHandle handle, const char *name, int depth)
{
    const XF86ConfigRec *pConfig;
    XF86ConfLayoutPtr l;
    serverLayoutPtr pServerLayout = NULL;

    if (!name)
	return NULL;

    pConfig = ConfigHandleToConfigRead(handle);
    for (l = pConfig->conf_layout_lst; l; l = l->list.next) {
	if (xf86nameCompare(l->lay_identifier, name) == 0) {
	    break;
	}
    }
    if (l) {
	pServerLayout = xf86ConfAllocServerLayout();
	if (pServerLayout) {
	    if (!convertServerLayout(pServerLayout, l)) {
		xfree(pServerLayout);
		return NULL;
	    }
	    if (depth > 0) {
		if (!xf86ConfResolveServerLayout(handle,
						 pServerLayout, depth)) {
		    xf86ConfFreeServerLayoutData(pServerLayout);
		    xfree(pServerLayout);
		    return NULL;
		}
	    }
	    return pServerLayout;
	}
    }
    return NULL;
}

serverLayoutPtr
xf86ConfGetNextServerLayout(ConfigHandle handle,
			    ConfigDataHandle prevLayoutHandle, int depth)
{
    const XF86ConfigRec *pConfig;
    XF86ConfLayoutPtr l;
    serverLayoutPtr pServerLayout = NULL;

    /* The special active case. */
    if (handle == ACTIVE_CONFIG) {
	if (!prevLayoutHandle)
	    return xf86ConfDupServerLayout(xf86Info.serverLayout, depth);
	else
	    return NULL;
    }

    pConfig = ConfigHandleToConfigRead(handle);
    if (!prevLayoutHandle) {
	l = pConfig->conf_layout_lst;
    } else {
	for (l = pConfig->conf_layout_lst; l; l = l->list.next) {
	    if (l == prevLayoutHandle) {
		l = l->list.next;
		break;
	    }
	}
    }
    if (l) {
	pServerLayout = xf86ConfAllocServerLayout();
	if (pServerLayout) {
	    if (!convertServerLayout(pServerLayout, l)) {
		xfree(pServerLayout);
		return NULL;
	    }
	    if (depth > 0) {
		if (!xf86ConfResolveServerLayout(handle,
						 pServerLayout, depth)) {
		    xf86ConfFreeServerLayoutData(pServerLayout);
		    xfree(pServerLayout);
		    return NULL;
		}
	    }
	    return pServerLayout;
	}
    }
    return NULL;
}

static void
resolveServerLayoutCleanup(serverLayoutPtr pServerLayout)
{
    int i;

    if (pServerLayout->screenLayouts) {
	for (i = 0; i < pServerLayout->numScreens; i++) {
	    if (pServerLayout->screenLayouts[i]) {
		xf86ConfFreeScreenData(pServerLayout->screenLayouts[i]->screen);
		pServerLayout->screenLayouts[i]->screen = NULL;
	    }
	}
    }
    if (pServerLayout->inactiveDevs) {
	for (i = 0; i < pServerLayout->numInactives; i++) {
	    xf86ConfFreeGraphicsDeviceData(pServerLayout->inactiveDevs[i]);
	    pServerLayout->inactiveDevs[i] = NULL;
	}
	xfree(pServerLayout->inactiveDevs);
    }
    if (pServerLayout->inputDevs) {
	for (i = 0; i < pServerLayout->numInputs; i++) {
	    xf86ConfFreeInputDeviceData(pServerLayout->inputDevs[i]);
	    pServerLayout->inputDevs[i] = NULL;
	}
	xfree(pServerLayout->inputDevs);
    }
}

serverLayoutPtr
xf86ConfResolveServerLayout(ConfigHandle handle, serverLayoutPtr pServerLayout,
			    int depth)
{
    screenLayoutPtr *ppScreenLayout;
    int i = 0, j;

    if (!pServerLayout || depth < 1)
	return pServerLayout;

    resolveServerLayoutCleanup(pServerLayout);

    if (!pServerLayout->screenLayouts)
	return pServerLayout;

    ppScreenLayout = pServerLayout->screenLayouts;
    for (i = 0; i < pServerLayout->numScreens; i++) {
	if (!ppScreenLayout[i]->screenName)
	    continue;
	ppScreenLayout[i]->screen =
	    xf86ConfGetScreenByName(handle, ppScreenLayout[i]->screenName,
				    depth - 1);
	if (!ppScreenLayout[i]->screen)
	    continue;
	ppScreenLayout[i]->screen->screennum = ppScreenLayout[i]->screenNum;
    }

    /* Fill in the refscreen value. */
    for (i = 0; i < pServerLayout->numScreens; i++) {
	for (j = 0; j < pServerLayout->numScreens; j++) {
	    if (ppScreenLayout[i]->refname &&
		strcmp(ppScreenLayout[i]->refname,
		       ppScreenLayout[j]->screenName) == 0) {
		ppScreenLayout[i]->refscreen = ppScreenLayout[j]->screen;
	    }
	}
	if (ppScreenLayout[i]->where != PosAbsolute &&
	    !ppScreenLayout[i]->refscreen) {
	    xf86Msg(X_WARNING,
		    "Screen \"%s\" doesn't exist: deleting placement.\n",
		    ppScreenLayout[i]->refname);
	    ppScreenLayout[i]->where = PosAbsolute;
	    ppScreenLayout[i]->x = -1;
	    ppScreenLayout[i]->y = -1;
	}
    }

    /* Inactive devices. */
    if (pServerLayout->numInactives > 0 && pServerLayout->inactiveNames) {
	pServerLayout->inactiveDevs =
	    xcalloc(pServerLayout->numInactives, sizeof(GDevPtr));
	if (!pServerLayout->inactiveDevs) {
	    resolveServerLayoutCleanup(pServerLayout);
	    return NULL;
	}
	for (i = 0; i < pServerLayout->numInactives; i++) {
	    if (!pServerLayout->inactiveNames[i])
		continue;
	    pServerLayout->inactiveDevs[i] =
		xf86ConfGetGraphicsDeviceByName(handle,
					    pServerLayout->inactiveNames[i]);
	}
    }

    /* Input devices. */
    if (pServerLayout->numInputs > 0 && pServerLayout->inputNames) {
	pServerLayout->inputDevs =
	    xcalloc(pServerLayout->numInputs, sizeof(IDevPtr));
	if (!pServerLayout->inputDevs) {
	    resolveServerLayoutCleanup(pServerLayout);
	    return NULL;
	}
	for (i = 0; i < pServerLayout->numInputs; i++) {
	    if (!pServerLayout->inputNames[i])
		continue;
	    pServerLayout->inputDevs[i] =
		xf86ConfGetInputDeviceByName(handle,
					     pServerLayout->inputNames[i]);
	    if (!pServerLayout->inputDevs[i])
		continue;
	    if (pServerLayout->inputExtraOptions) {
		pServerLayout->inputDevs[i]->extraOptions =
			xf86OptionListDup(pServerLayout->inputExtraOptions[i]);
		if (pServerLayout->inputExtraOptions[i] &&
		    !pServerLayout->inputDevs[i]->extraOptions) {
		    resolveServerLayoutCleanup(pServerLayout);
		    return NULL;
		}
	    }
	}
    }
    return pServerLayout;
}

int
xf86ConfCheckResolvedServerLayout(const serverLayoutRec *pServerLayout,
				  int depth, Bool strict)
{
    int i;
    Bool failures = 0;
    screenLayoutPtr *ppScreenLayout;

    if (!pServerLayout || depth < 1)
	return 0;

    ppScreenLayout = pServerLayout->screenLayouts;
    for (i = 0; i < pServerLayout->numScreens; i++) {
	if (!ppScreenLayout[i]->screenName)
	    continue;
	if (ppScreenLayout[i]->screen) {
	    failures +=
		xf86ConfCheckResolvedScreen(ppScreenLayout[i]->screen,
					    depth - 1, strict);
	} else {
	    xf86Msg(X_ERROR, "No Screen \"%s\" "
			     "(referenced by ServerLayout \"%s\").\n",
		    ppScreenLayout[i]->screenName, pServerLayout->id);
	    failures++;
	}
    }
    if (strict && pServerLayout->numScreens == 0) {
	xf86Msg(X_ERROR, "No Screen references in ServerLayout \"%s\".\n",
		pServerLayout->id);
	failures++;
    }

    if (pServerLayout->numInactives > 0 && pServerLayout->inactiveNames) {
	for (i = 0; i < pServerLayout->numInactives; i++) {
	    if (!pServerLayout->inactiveNames[i])
		continue;
	    if (!pServerLayout->inactiveDevs[i]) {
		xf86Msg(X_ERROR, "No Device \"%s\" "
				 "(referenced by ServerLayout \"%s\").\n",
			pServerLayout->inactiveNames[i], pServerLayout->id);
		failures++;
	    }
	}
    }
    if (pServerLayout->numInputs > 0 && pServerLayout->inputNames) {
	for (i = 0; i < pServerLayout->numInputs; i++) {
	    if (!pServerLayout->inputNames[i])
		continue;
	    if (!pServerLayout->inputDevs[i]) {
		xf86Msg(X_ERROR, "No Input Device \"%s\" "
				 "(referenced by ServerLayout \"%s\").\n",
			pServerLayout->inputNames[i], pServerLayout->id);
		failures++;
	    }
	}
    } else if (strict) {
	xf86Msg(X_ERROR, "No Input Device references in ServerLayout \"%s\".\n",
		pServerLayout->id);
	failures++;
    }
    return failures;
}

/*
 * Figure out which layout is active, and fill in the config data for
 * everything that it references.
 */
static serverLayoutPtr
configServerLayout(ConfigHandle handle, char *defaultLayout)
{
    int i;
    const char *name = NULL;
    serverLayoutPtr pServerLayout;

    /*
     * Find the active ServerLayout section.  The order of priority is:
     *
     *   1. Name specified by the -layout command line option.
     *   2. Name specified by the DefaultServerLayout config option.
     *   3. The first ServerLayout section.
     */
    if (xf86LayoutName)
	name = xf86LayoutName;
    else if (defaultLayout)
	name = defaultLayout;
    if (name) {
	pServerLayout = xf86ConfGetServerLayoutByName(handle, name,
						      CONFIG_RESOLVE_ALL);
	if (!pServerLayout) {
	    xf86Msg(X_ERROR, "No ServerLayout section called \"%s\".\n", name);
	    return NULL;
	}
	pServerLayout->from = xf86LayoutName ? X_CMDLINE : X_CONFIG;
    } else {
	pServerLayout = xf86ConfGetNextServerLayout(handle, NULL,
						    CONFIG_RESOLVE_ALL);
	if (!pServerLayout) {
	    xf86Msg(X_ERROR, "No ServerLayout sections found.\n");
	    return NULL;
	}
	pServerLayout->from = X_DEFAULT;
    }

    if (pServerLayout->numScreens <= 0) {
	xf86Msg(X_ERROR, "No Screens in ServerLayout \"%s\".\n",
		pServerLayout->id);
	xf86ConfFreeServerLayoutData(pServerLayout);
	xfree(pServerLayout);
	return NULL;
    }

    /* Special case handling for the built-in keyboard device. */
    if (pServerLayout->inputDevs) {
	for (i = 0; i < pServerLayout->numInputs; i++) {
	    IDevPtr pIDev = pServerLayout->inputDevs[i];
	    if (pIDev && !xf86NameCmp(pIDev->driver, "keyboard")) {
		if (!configInputKbd(pIDev)) {
		    xf86ConfFreeServerLayoutData(pServerLayout);
		    xfree(pServerLayout);
		    return NULL;
		}
	    }
	}
    }

    if (!checkCoreInputDevices(handle, pServerLayout, FALSE)) {
	xf86ConfFreeServerLayoutData(pServerLayout);
	xfree(pServerLayout);
	return NULL;
    }
    return pServerLayout;
}

/*
 * No ServerLayout section, so find the first Screen section and set that up as
 * the only active screen.
 */
static serverLayoutPtr
configImpliedServerLayout(ConfigHandle handle, const char *screenName)
{
    confScreenPtr s;
    screenLayoutPtr pScreenLayout;
    serverLayoutPtr pServerLayout;

    /*
     * Find the active Screen section in the absence of a ServerLayout
     * section, or when a Screen section is specified explicitly with
     * the '-screen' option.  The order of priority is:
     *
     *   1. Name specified by the -screen command line option.
     *   2. The first Screen section.
     */

    if (screenName) {
	s = xf86ConfGetScreenByName(handle, screenName, CONFIG_RESOLVE_ALL);
	if (!s) {
	    xf86Msg(X_ERROR, "No Screen section called \"%s\".\n", screenName);
	    return NULL;
	}
    } else {
	s = xf86ConfGetNextScreen(handle, NULL, CONFIG_RESOLVE_ALL);
	if (!s) {
	    xf86Msg(X_ERROR, "No Screen sections found.\n");
	    return NULL;
	}
    }

    pServerLayout = xf86ConfAllocServerLayout();
    if (!pServerLayout) {
	xf86ConfFreeScreenData(s);
	xfree(s);
	return NULL;
    }

    /* With an implied ServerLayout, there is exactly one screen. */
    pServerLayout->screenLayouts = xcalloc(1, sizeof(serverLayoutPtr));
    if (!pServerLayout->screenLayouts) {
	xf86ConfFreeScreenData(s);
	xfree(s);
	xfree(pServerLayout);
	return NULL;
    }
    pServerLayout->numScreens = 1;
    pScreenLayout = xf86ConfAllocScreenLayout();
    if (!pScreenLayout) {
	xf86ConfFreeScreenData(s);
	xfree(s);
	xf86ConfFreeServerLayoutData(pServerLayout);
	xfree(pServerLayout);
	return NULL;
    }
    pServerLayout->screenLayouts[0] = pScreenLayout;
    pScreenLayout->screen = s;
    pScreenLayout->screenName = xstrdup(s->id);
    if (s->id && !pScreenLayout->screenName) {
	xf86ConfFreeServerLayoutData(pServerLayout);
	xfree(pServerLayout);
	return NULL;
    }
    pServerLayout->id = xstrdup("(implicit)");
    if (!pServerLayout->id) {
	xf86ConfFreeServerLayoutData(pServerLayout);
	xfree(pServerLayout);
	return NULL;
    }
    pServerLayout->from = X_DEFAULT;
    /* Find implied core devices. */
    if (!checkCoreInputDevices(handle, pServerLayout, TRUE)) {
	xf86ConfFreeServerLayoutData(pServerLayout);
	xfree(pServerLayout);
	return NULL;
    }
    return pServerLayout;
}

confXvPortPtr
xf86ConfAllocXvPort()
{
    confXvPortPtr pPort;

    pPort = xcalloc(1, sizeof(*pPort));
    pPort->handle = pPort;
    return pPort;
}

void
xf86ConfFreeXvPortData(confXvPortPtr pPort)
{
    if (!pPort)
	return;

    if (pPort->identifier) {
	xfree(pPort->identifier);
	pPort->identifier = NULL;
    }
    if (pPort->options) {
	xf86OptionListFree(pPort->options);
	pPort->options = NULL;
    }
}

confXvPortPtr
xf86ConfDupXvPort(const confXvPortRec *pPort)
{
    confXvPortPtr p;

    if (!pPort)
	return NULL;

    p = xf86ConfAllocXvPort();
    if (!p)
	return NULL;

    p->handle = pPort->handle;
    p->identifier = xstrdup(pPort->identifier);
    if (pPort->identifier && !p->identifier) {
	xf86ConfFreeXvPortData(p);
	xfree(p);
	return NULL;
    }
    p->options = xf86OptionListDup(pPort->options);
    if (pPort->options && !p->options) {
	xf86ConfFreeXvPortData(p);
	xfree(p);
	return NULL;
    }
    return p;
}

static confXvPortPtr
convertXvPort(confXvPortPtr pPort, const XF86ConfVideoPortRec *confPort)
{
    if (!pPort || ! confPort)
	return NULL;

    pPort->handle = confPort;
    pPort->identifier = xstrdup(confPort->vp_identifier);
    if (confPort->vp_identifier && !pPort->identifier) {
	xf86ConfFreeXvPortData(pPort);
	return NULL;
    }
    pPort->options = xf86OptionListDup(confPort->vp_option_lst);
    if (confPort->vp_option_lst && !pPort->options) {
	xf86ConfFreeXvPortData(pPort);
	return NULL;
    }
    return pPort;
}

confXvAdaptorPtr
xf86ConfAllocXvAdaptor()
{
    confXvAdaptorPtr pAdaptor;

    pAdaptor = xcalloc(1, sizeof(*pAdaptor));
    pAdaptor->handle = pAdaptor;
    return pAdaptor;
}

void
xf86ConfFreeXvAdaptorData(confXvAdaptorPtr pAdaptor)
{
    int i;

    if (!pAdaptor)
	return;

    if (pAdaptor->identifier) {
	xfree(pAdaptor->identifier);
	pAdaptor->identifier = NULL;
    }
    if (pAdaptor->xvPorts) {
	for (i = 0; i < pAdaptor->numports; i++) {
	    xf86ConfFreeXvPortData(pAdaptor->xvPorts[i]);
	    xfree(pAdaptor->xvPorts[i]);
	    pAdaptor->xvPorts[i] = NULL;
	}
	xfree(pAdaptor->xvPorts);
	pAdaptor->xvPorts = NULL;
    }
    pAdaptor->numports = 0;
    if (pAdaptor->options) {
	xf86OptionListFree(pAdaptor->options);
	pAdaptor->options = NULL;
    }
}

confXvAdaptorPtr
xf86ConfDupXvAdaptor(const confXvAdaptorRec *pAdaptor)
{
    int i;
    confXvAdaptorPtr a;

    if (!pAdaptor)
	return NULL;

    a = xf86ConfAllocXvAdaptor();
    if (!a)
	return NULL;

    a->handle = pAdaptor->handle;
    a->identifier = xstrdup(pAdaptor->identifier);
    if (pAdaptor->identifier && !a->identifier) {
	xf86ConfFreeXvAdaptorData(a);
	xfree(a);
	return NULL;
    }
    a->options = xf86OptionListDup(pAdaptor->options);
    if (pAdaptor->options && !a->options) {
	xf86ConfFreeXvAdaptorData(a);
	xfree(a);
	return NULL;
    }
    a->numports = pAdaptor->numports;
    if (a->numports > 0) {
	a->xvPorts = xcalloc(a->numports, sizeof(confXvPortPtr));
	if (!a->xvPorts) {
	    xf86ConfFreeXvAdaptorData(a);
	    xfree(a);
	    return NULL;
	}
	for (i = 0; i < a->numports; i++) {
	    a->xvPorts[i] = xf86ConfDupXvPort(pAdaptor->xvPorts[i]);
	    if (pAdaptor->xvPorts[i] && !a->xvPorts[i]) {
		xf86ConfFreeXvAdaptorData(a);
		xfree(a);
		return NULL;
	    }
	}
    }
    return a;
}

static confXvAdaptorPtr
convertXvAdaptor(confXvAdaptorPtr pAdaptor,
		 const XF86ConfVideoAdaptorRec *confAdaptor)
{
    int count = 0;
    XF86ConfVideoPortPtr confPort;

    if (!pAdaptor || ! confAdaptor)
	return NULL;

    pAdaptor->handle = confAdaptor;
    pAdaptor->identifier = xstrdup(confAdaptor->va_identifier);
    if (confAdaptor->va_identifier && !pAdaptor->identifier) {
	xf86ConfFreeXvAdaptorData(pAdaptor);
	return NULL;
    }
    pAdaptor->options = xf86OptionListDup(confAdaptor->va_option_lst);
    if (confAdaptor->va_option_lst && !pAdaptor->options) {
	xf86ConfFreeXvAdaptorData(pAdaptor);
	return NULL;
    }

#if 0
    if (conf_adaptor->va_busid || conf_adaptor->va_driver) {
	xf86Msg(X_CONFIG, "|   | Unsupported device type, skipping entry\n");
	return FALSE;
    }
#endif

    /*
     * Figure out how many videoport subsections there are and fill them in.
     */
    confPort = confAdaptor->va_port_lst;
    while (confPort) {
	count++;
	confPort = confPort->list.next;
    }
    if (count > 0) {
	pAdaptor->xvPorts = xcalloc(count, sizeof(confXvAdaptorPtr));
	if (!pAdaptor->xvPorts) {
	    xf86ConfFreeXvAdaptorData(pAdaptor);
	    return NULL;
	}
	pAdaptor->numports = count;
	count = 0;
	confPort = confAdaptor->va_port_lst;
	while (confPort) {
	    pAdaptor->xvPorts[count] = xf86ConfAllocXvPort();
	    if (!pAdaptor->xvPorts[count]) {
		xf86ConfFreeXvAdaptorData(pAdaptor);
		return NULL;
	    }
	    if (!convertXvPort(pAdaptor->xvPorts[count], confPort)) {
		xf86ConfFreeXvAdaptorData(pAdaptor);
		return NULL;
	    }
	    count++;
	    confPort = confPort->list.next;
	}
    }
    return pAdaptor;
}

confXvAdaptorPtr
xf86ConfGetXvAdaptorByName(ConfigHandle handle, const char *name)
{
    const XF86ConfigRec *pConfig;
    XF86ConfVideoAdaptorPtr a;
    confXvAdaptorPtr pAdaptor = NULL;

    if (!name)
	return NULL;

    pConfig = ConfigHandleToConfigRead(handle);
    for (a = pConfig->conf_videoadaptor_lst; a; a = a->list.next) {
	if (xf86nameCompare(a->va_identifier, name) == 0) {
	    break;
	}
    }
    if (a) {
	pAdaptor = xf86ConfAllocXvAdaptor();
	if (pAdaptor) {
	    if (convertXvAdaptor(pAdaptor, a))
		return pAdaptor;
	    else
		xfree(pAdaptor);
	}
    }
    return NULL;
}

static const confXvAdaptorRec *
getNextActiveXvAdaptor(ConfigDataHandle prev)
{
    const confScreenRec *pConfScreen = NULL;
    int i = 0;
    Bool found = FALSE;

    while ((pConfScreen = getNextActiveScreen(pConfScreen))) {
	for (i = 0; i < pConfScreen->numXvAdaptors; i++) {
	    if (!prev) {
		found = TRUE;
		break;
	    } else if (pConfScreen->xvAdaptorList &&
		       pConfScreen->xvAdaptorList[i]->handle == prev) {
		i++;
		found = TRUE;
		break;
	    }
	}
	if (found) {
	    if (i < pConfScreen->numXvAdaptors)
		break;
	    else {
		prev = NULL;
		found = FALSE;
	    }
	}
    }
    if (found)
	return pConfScreen->xvAdaptorList[i];
    else
	return NULL;
}

confXvAdaptorPtr
xf86ConfGetNextXvAdaptor(ConfigHandle handle,
			 ConfigDataHandle prevAdaptorHandle)
{
    const XF86ConfigRec *pConfig;
    XF86ConfVideoAdaptorPtr a;
    confXvAdaptorPtr pAdaptor = NULL;

    if (handle == ACTIVE_CONFIG)
	return xf86ConfDupXvAdaptor(getNextActiveXvAdaptor(prevAdaptorHandle));

    pConfig = ConfigHandleToConfigRead(handle);
    if (!prevAdaptorHandle) {
	a = pConfig->conf_videoadaptor_lst;
    } else {
	for (a = pConfig->conf_videoadaptor_lst; a; a = a->list.next) {
	    if (a == prevAdaptorHandle) {
		a = a->list.next;
		break;
	    }
	}
    }
    if (a) {
	pAdaptor = xf86ConfAllocXvAdaptor();
	if (pAdaptor) {
	    if (convertXvAdaptor(pAdaptor, a))
		return pAdaptor;
	    else
		xfree(pAdaptor);
	}
    }
    return NULL;
}

confScreenPtr
xf86ConfAllocScreen()
{
    confScreenPtr pConfScreen;

    pConfScreen = xcalloc(1, sizeof(*pConfScreen));
    pConfScreen->screennum = -1;
    pConfScreen->handle = pConfScreen;
    return pConfScreen;
}

void
xf86ConfFreeScreenData(confScreenPtr pConfScreen)
{
    int i;

    if (!pConfScreen)
	return;

    if (pConfScreen->id) {
	xfree(pConfScreen->id);
	pConfScreen->id = NULL;
    }
    if (pConfScreen->monitorNames) {
	for (i = 0; i < pConfScreen->numMonitors; i++) {
	    xfree(pConfScreen->monitorNames[i]);
	    pConfScreen->monitorNames[i] = NULL;
	}
	xfree(pConfScreen->monitorNames);
	pConfScreen->monitorNames = NULL;
    }
    if (pConfScreen->monitorNums) {
	xfree(pConfScreen->monitorNums);
	pConfScreen->monitorNums = NULL;
    }
    if (pConfScreen->monitors) {
	for (i = 0; i < pConfScreen->numMonitors; i++) {
	    xf86ConfFreeMonitorData(pConfScreen->monitors[i]);
	    if (pConfScreen->monitor == pConfScreen->monitors[i])
		pConfScreen->monitor = NULL;
	    xfree(pConfScreen->monitors[i]);
	    pConfScreen->monitors[i] = NULL;
	}
	xfree(pConfScreen->monitors);
	pConfScreen->monitors = NULL;
    }
    pConfScreen->numMonitors = 0;
    if (pConfScreen->monitor) {
	xf86ConfFreeMonitorData(pConfScreen->monitor);
	xfree(pConfScreen->monitor);
	pConfScreen->monitor = NULL;
    }
    if (pConfScreen->deviceName) {
	xfree(pConfScreen->deviceName);
	pConfScreen->deviceName = NULL;
    }
    if (pConfScreen->device) {
	xf86ConfFreeGraphicsDeviceData(pConfScreen->device);
	xfree(pConfScreen->device);
	pConfScreen->device = NULL;
    }
    if (pConfScreen->displayList) {
	for (i = 0; i < pConfScreen->numdisplays; i++) {
	    xf86ConfFreeDisplayData(pConfScreen->displayList[i]);
	    xfree(pConfScreen->displayList[i]);
	    pConfScreen->displayList[i] = NULL;
	}
	xfree(pConfScreen->displayList);
	pConfScreen->displayList = NULL;
    }
    pConfScreen->numdisplays = 0;
    if (pConfScreen->xvAdaptorNames) {
	for (i = 0; i < pConfScreen->numXvAdaptors; i++) {
	    xfree(pConfScreen->xvAdaptorNames[i]);
	    pConfScreen->xvAdaptorNames[i] = NULL;
	}
	xfree(pConfScreen->xvAdaptorNames);
	pConfScreen->xvAdaptorNames = NULL;
    }
    if (pConfScreen->xvAdaptorList) {
	for (i = 0; i < pConfScreen->numXvAdaptors; i++) {
	    xf86ConfFreeXvAdaptorData(pConfScreen->xvAdaptorList[i]);
	    xfree(pConfScreen->xvAdaptorList[i]);
	    pConfScreen->xvAdaptorList[i] = NULL;
	}
	xfree(pConfScreen->xvAdaptorList);
	pConfScreen->xvAdaptorList = NULL;
    }
    pConfScreen->numXvAdaptors = 0;
    if (pConfScreen->options) {
	xf86OptionListFree(pConfScreen->options);
	pConfScreen->options = NULL;
    }
}

confScreenPtr
xf86ConfDupScreen(const confScreenRec *pConfScreen, int depth)
{
    int i;
    confScreenPtr s;

    if (!pConfScreen)
	return NULL;

    s = xf86ConfAllocScreen();
    if (!s)
	return NULL;

    s->handle = pConfScreen->handle;
    s->id = xstrdup(pConfScreen->id);
    if (pConfScreen->id && !s->id) {
	xf86ConfFreeScreenData(s);
	xfree(s);
	return NULL;
    }
    s->deviceName = xstrdup(pConfScreen->deviceName);
    if (pConfScreen->deviceName && !s->deviceName) {
	xf86ConfFreeScreenData(s);
	xfree(s);
	return NULL;
    }
    s->defaultdepth = pConfScreen->defaultdepth;
    s->defaultbpp = pConfScreen->defaultbpp;
    s->defaultfbbpp = pConfScreen->defaultfbbpp;
    s->screennum = pConfScreen->screennum;
    s->numMonitors = pConfScreen->numMonitors;
    if (s->numMonitors > 0) {
	s->monitorNames = xf86DupStringArray(pConfScreen->monitorNames,
					     s->numMonitors);
	if (pConfScreen->monitorNames && !s->monitorNames) {
	    xf86ConfFreeScreenData(s);
	    xfree(s);
	    return NULL;
	}
	if (pConfScreen->monitorNums) {
	    s->monitorNums = xcalloc(s->numMonitors, sizeof(int));
	    if (!s->monitorNums) {
		xf86ConfFreeScreenData(s);
		xfree(s);
		return NULL;
	    }
	    memcpy(s->monitorNums, pConfScreen->monitorNums,
		   s->numMonitors * sizeof(int));
	}
	if (depth > 0 && pConfScreen->monitors) {
	    s->monitors = xcalloc(s->numMonitors, sizeof(MonPtr));
	    if (!s->monitors) {
		xf86ConfFreeScreenData(s);
		xfree(s);
		return NULL;
	    }
	    for (i = 0; i < s->numMonitors; i++) {
		s->monitors[i] =
		    xf86ConfDupMonitor(pConfScreen->monitors[i], depth - 1);
		if (pConfScreen->monitors[i] && !s->monitors[i]) {
		    xf86ConfFreeScreenData(s);
		    xfree(s);
		    return NULL;
		}
	    }
	    s->monitor = s->monitors[0];
	}
    }

    if (pConfScreen->device) {
	if (depth > 0) {
	    s->device = xf86ConfDupGraphicsDevice(pConfScreen->device);
	    if (!s->device) {
		xf86ConfFreeScreenData(s);
		xfree(s);
		return NULL;
	    }
	} else {
	    s->device = xf86ConfAllocGraphicsDevice();
	    if (!s->device) {
		xf86ConfFreeScreenData(s);
		xfree(s);
		return NULL;
	    }
	    s->device->identifier = xstrdup(pConfScreen->device->identifier);
	    if (pConfScreen->device->identifier && !s->device->identifier) {
		xf86ConfFreeScreenData(s);
		xfree(s);
		return NULL;
	    }
	}
    }
    s->options = xf86OptionListDup(pConfScreen->options);
    if (pConfScreen->options && !s->options) {
	xf86ConfFreeScreenData(s);
	xfree(s);
	return NULL;
    }

    s->numdisplays = pConfScreen->numdisplays;
    if (s->numdisplays > 0 && pConfScreen->displayList) {
	s->displayList = xcalloc(s->numdisplays, sizeof(DispPtr));
	if (!s->displayList) {
	    xf86ConfFreeScreenData(s);
	    xfree(s);
	    return NULL;
	}
	for (i = 0; i < s->numdisplays; i++) {
	    s->displayList[i] = xf86ConfDupDisplay(pConfScreen->displayList[i]);
	    if (pConfScreen->displayList[i] && !s->displayList[i]) {
		xf86ConfFreeScreenData(s);
		xfree(s);
		return NULL;
	    }
	}
    }

    s->numXvAdaptors = pConfScreen->numXvAdaptors;
    if (s->numXvAdaptors > 0) {
	s->xvAdaptorNames = xf86DupStringArray(pConfScreen->xvAdaptorNames,
					       s->numXvAdaptors);
	if (pConfScreen->xvAdaptorNames && !s->xvAdaptorNames) {
	    xf86ConfFreeScreenData(s);
	    xfree(s);
	    return NULL;
	}
	if (depth > 0) {
	    s->xvAdaptorList =
		xcalloc(s->numXvAdaptors, sizeof(confXvAdaptorPtr));
	    if (!s->xvAdaptorList) {
		xf86ConfFreeScreenData(s);
		xfree(s);
		return NULL;
	    }
	    for (i = 0; i < s->numXvAdaptors; i++) {
		s->xvAdaptorList[i] =
		    xf86ConfDupXvAdaptor(pConfScreen->xvAdaptorList[i]);
		if (pConfScreen->xvAdaptorList[i] && !s->xvAdaptorList[i]) {
		    xf86ConfFreeScreenData(s);
		    xfree(s);
		    return NULL;
		}
	    }
	}
    }
    return s;
}

static void
resolveScreenCleanup(confScreenPtr pConfScreen, Bool cleanMonNames)
{
    int i;

    if (pConfScreen->monitors) {
	for (i = 0; i < pConfScreen->numMonitors; i++)
	    xf86ConfFreeMonitorData(pConfScreen->monitors[i]);
	xfree(pConfScreen->monitors);
	pConfScreen->monitors = NULL;
    }
    if (cleanMonNames) {
	if (pConfScreen->monitorNames) {
	    for (i = 0; i < pConfScreen->numMonitors; i++)
		xfree(pConfScreen->monitorNames[i]);
	    xfree(pConfScreen->monitorNames);
	    pConfScreen->monitorNames = NULL;
	}
	if (pConfScreen->monitorNums) {
	    xfree(pConfScreen->monitorNums);
	    pConfScreen->monitorNums = NULL;
	}
	pConfScreen->numMonitors = 0;
    }
    if (pConfScreen->device) {
	xf86ConfFreeGraphicsDeviceData(pConfScreen->device);
	pConfScreen->device = NULL;
    }
    if (pConfScreen->xvAdaptorList) {
	for (i = 0; i < pConfScreen->numXvAdaptors; i++)
	    xf86ConfFreeXvAdaptorData(pConfScreen->xvAdaptorList[i]);
	xfree(pConfScreen->xvAdaptorList);
	pConfScreen->xvAdaptorList = NULL;
    }
}

confScreenPtr
xf86ConfResolveScreen(ConfigHandle handle, confScreenPtr pConfScreen,
		      int depth)
{
    int i;
    Bool defaultMonitor = FALSE;

    if (!pConfScreen || depth < 1)
	return pConfScreen;

    /* Clean out any fields that we will be filling in. */
    resolveScreenCleanup(pConfScreen, FALSE);
    if (pConfScreen->numMonitors > 0 && pConfScreen->monitorNames) {
	pConfScreen->monitors =
	    xcalloc(pConfScreen->numMonitors, sizeof(MonPtr));
	if (!pConfScreen->monitors)
	    return NULL;
	for (i = 0; i < pConfScreen->numMonitors; i++) {
	    if (!pConfScreen->monitorNames[i])
		continue;

	    pConfScreen->monitors[i] =
		xf86ConfGetMonitorByName(handle, pConfScreen->monitorNames[i],
					 depth - 1);
	    if (!pConfScreen->monitors[i]) {
		continue;
	    }
	    if (pConfScreen->monitorNums[i])
		pConfScreen->monitors[i]->monitorNum =
			pConfScreen->monitorNums[i];
	}
    } else {
	/* If no monitor is specified, create a default one. */
	XF86ConfMonitorRec defMon;
	MonPtr newMonitor;
	
	bzero(&defMon, sizeof(defMon));
	defMon.mon_identifier = xstrdup("<default monitor>");
	/*
	 * TARGET_REFRESH_RATE may be defined to effectively limit the
	 * default resolution to the largest that has a "good" refresh
	 * rate.
	 */
#ifdef TARGET_REFRESH_RATE
	defMon.mon_option_lst = xf86ReplaceRealOption(defMon.mon_option_lst,
						      "TargetRefresh",
						      TARGET_REFRESH_RATE);
#endif
	pConfScreen->numMonitors = 1;
	pConfScreen->monitorNames = xcalloc(1, sizeof(char *));
	pConfScreen->monitorNums = xcalloc(1, sizeof(int));
	pConfScreen->monitors = xcalloc(1, sizeof(MonPtr));
	newMonitor = xcalloc(1, sizeof(*newMonitor));
	if (!pConfScreen->monitorNames || !pConfScreen->monitorNums ||
	    !pConfScreen->monitors || !newMonitor) {
	    resolveScreenCleanup(pConfScreen, TRUE);
	    xfree(newMonitor);
	    return NULL;
	}
	if (!convertMonitor(newMonitor, &defMon)) {
	    resolveScreenCleanup(pConfScreen, TRUE);
	    xfree(newMonitor);
	    return NULL;
	}
	if (depth - 1 > 0) {
	    if (!xf86ConfResolveMonitor(handle, newMonitor)) {
		resolveScreenCleanup(pConfScreen, TRUE);
		xfree(newMonitor);
		return NULL;
	    }
	}
	newMonitor->defaultMon = TRUE;
	pConfScreen->monitors[0] = newMonitor;
	pConfScreen->monitorNums[0] = newMonitor->monitorNum;
	pConfScreen->monitorNames[0] = xstrdup(newMonitor->id);
	if (newMonitor->id && !pConfScreen->monitorNames[0]) {
	    resolveScreenCleanup(pConfScreen, TRUE);
	    return NULL;
	}
	defaultMonitor = TRUE;
    }
    if (pConfScreen->monitors)
	pConfScreen->monitor = pConfScreen->monitors[0];

    if (defaultMonitor) {
	xf86MsgVerb(X_INFO, 5,
		    "Created %d default Monitor%s for the "
		    "Screen section \"%s\".\n",
		    pConfScreen->numMonitors, PLURAL(pConfScreen->numMonitors),
		    pConfScreen->id);
    } else {
	xf86MsgVerb(X_INFO, 5,
		    "Found %d Monitor%s in the Screen section \"%s\".\n",
		    pConfScreen->numMonitors, PLURAL(pConfScreen->numMonitors),
		    pConfScreen->id);
    }

    pConfScreen->device =
	xf86ConfGetGraphicsDeviceByName(handle, pConfScreen->deviceName);

    if (pConfScreen->device) {
	pConfScreen->device->active = TRUE;
	pConfScreen->device->myScreenSection = pConfScreen;
    }

    if (pConfScreen->numXvAdaptors > 0 && pConfScreen->xvAdaptorNames) {
	pConfScreen->xvAdaptorList =
	    xcalloc(pConfScreen->numXvAdaptors, sizeof(confXvAdaptorPtr));
	if (!pConfScreen->xvAdaptorList) {
	    resolveScreenCleanup(pConfScreen, defaultMonitor);
	    return NULL;
	}
	for (i = 0; i < pConfScreen->numXvAdaptors; i++) {
	    pConfScreen->xvAdaptorList[i] =
		xf86ConfGetXvAdaptorByName(handle,
					   pConfScreen->xvAdaptorNames[i]);
	}
    }

    if (defaultMonitor) {
	xf86Msg(X_WARNING, "No monitor specified for screen \"%s\".\n"
		"\tUsing a default monitor configuration.\n", pConfScreen->id);
    }
    return pConfScreen;
}

int
xf86ConfCheckResolvedScreen(const confScreenRec *pConfScreen, int depth,
			    Bool strict)
{
    int i;
    int failures = 0;

    if (!pConfScreen || depth < 1)
	return 0;

    if (pConfScreen->numMonitors > 0 && pConfScreen->monitorNames) {
	for (i = 0; i < pConfScreen->numMonitors; i++) {
	    if (!pConfScreen->monitorNames[i])
		continue;
	    if (pConfScreen->monitors && pConfScreen->monitors[i]) {
		failures +=
		    xf86ConfCheckResolvedMonitor(pConfScreen->monitors[i],
						 depth - 1, strict);
	    } else {
		xf86Msg(X_ERROR, "No Monitor \"%s\" "
				 "(referenced by Screen \"%s\").\n",
			pConfScreen->monitorNames[i], pConfScreen->id);
		failures++;
	    }
	}
    } else if (strict) {
	xf86Msg(X_ERROR, "No Monitor references in Screen \"%s\".\n",
		pConfScreen->id);
	failures++;
    }

    if (pConfScreen->deviceName) {
	if (!pConfScreen->device) {
	    xf86Msg(X_ERROR, "No Device \"%s\" "
			       "(referenced by Screen \"%s\").\n",
		    pConfScreen->deviceName, pConfScreen->id);
	    failures++;
	}
    } else if (strict) {
	xf86Msg(X_ERROR, "No Device references in Screen \"%s\".\n",
		pConfScreen->id);
	failures++;
    }

    if (pConfScreen->numXvAdaptors > 0 && pConfScreen->xvAdaptorNames) {
	for (i = 0; i < pConfScreen->numXvAdaptors; i++) {
	    if (!pConfScreen->xvAdaptorNames[i])
		continue;
	    if (!pConfScreen->xvAdaptorList || !pConfScreen->xvAdaptorList[i]) {
		xf86Msg(X_ERROR, "No VideoAdaptor \"%s\" "
				 "(referenced by Screen \"%s\").\n",
			pConfScreen->xvAdaptorNames[i], pConfScreen->id);
		failures++;
	    }
	}
    }
    return failures;
}

/*
 * assignIndices takes an array of numbers indexed by config file ordering
 * and assigns values to the unassigned (negative) values.  The values
 * assigned begin with the largest already-assigned value + 1, and the
 * unassigned values are incremented in config file order.
 *
 * Note: duplicate already-assigned values are not resolved.  This is typically
 * a configuration error, but handling such things is up to the driver, and
 * optional.
 *
 * Examples:
 *
 *   1. {-1, 0, -1, 1} -> {2, 0, 3, 1}
 *   2. {0, 1, 2, 1} -> {0, 1, 2, 1}
 *   3. {1, 3, -1, 5} -> {1, 3, 6, 5}
 */

static void
assignIndices(int *mapping, int count)
{
    int i;
    int max = -1;

    /* First pass: find largest assigned value. */
    for (i = 0; i < count; i++) {
	if (mapping[i] > max)
	    max = mapping[i];
    }

    /* Second pass: assign values to unassigned slots. */
    for (i = 0; i < count; i++) {
	if (mapping[i] < 0)
	    mapping[i] = ++max;
    }
}

static confScreenPtr
convertScreen(confScreenPtr pConfScreen, const XF86ConfScreenRec *confScreen)
{
    int count;
    XF86ConfDisplayPtr dispptr;
    XF86ConfAdaptorLinkPtr conf_adaptor;
    XF86ConfMonitorListPtr mlistp;
    int i;
    int *mapping;

    if (!pConfScreen || !confScreen)
	return NULL;

    pConfScreen->handle = confScreen;
    pConfScreen->id = xstrdup(confScreen->scrn_identifier);
    if (confScreen->scrn_identifier && !pConfScreen->id) {
	xf86ConfFreeScreenData(pConfScreen);
	return NULL;
    }
    pConfScreen->defaultdepth = confScreen->scrn_defaultdepth;
    pConfScreen->defaultbpp = confScreen->scrn_defaultbpp;
    pConfScreen->defaultfbbpp = confScreen->scrn_defaultfbbpp;
    pConfScreen->screennum = -1;

    /* Figure out how many monitor references there are. */
    mlistp = confScreen->scrn_monitor_lst;
    count = 0;
    while (mlistp) {
	count++;
	mlistp = mlistp->list.next;
    }
    pConfScreen->numMonitors = count;
    if (count > 0) {
	pConfScreen->monitorNames = xcalloc(count, sizeof(char *));
	if (!pConfScreen->monitorNames) {
	    xf86ConfFreeScreenData(pConfScreen);
	    return NULL;
	}
	mapping = xcalloc(count, sizeof(int));
	if (!mapping) {
	    xf86ConfFreeScreenData(pConfScreen);
	    return NULL;
	}
	mlistp = confScreen->scrn_monitor_lst;
	for (i = 0; i < count; i++) {
	    mapping[i] = mlistp->monitor_num;
	    mlistp = mlistp->list.next;
	}
	assignIndices(mapping, count);
	pConfScreen->monitorNums = mapping;
	mlistp = confScreen->scrn_monitor_lst;
	for (i = 0; i < count; i++) {
	    pConfScreen->monitorNames[i] = xstrdup(mlistp->monitor_str);
	    if (mlistp->monitor_str && !pConfScreen->monitorNames[i]) {
		xf86ConfFreeScreenData(pConfScreen);
		return NULL;
	    }
	    mlistp = mlistp->list.next;
	}
    }

    pConfScreen->deviceName = xstrdup(confScreen->scrn_device_str);
    if (confScreen->scrn_device_str && !pConfScreen->deviceName) {
	xf86ConfFreeScreenData(pConfScreen);
	return NULL;
    }
    pConfScreen->options = xf86OptionListDup(confScreen->scrn_option_lst);
    if (confScreen->scrn_option_lst && !pConfScreen->options) {
	xf86ConfFreeScreenData(pConfScreen);
	return NULL;
    }
    
    /* Figure out how many display subsections there are, and allocate them. */
    dispptr = confScreen->scrn_display_lst;
    count = 0;
    while (dispptr) {
	count++;
	dispptr = dispptr->list.next;
    }
    pConfScreen->numdisplays = count;
    if (count > 0) {
	pConfScreen->displayList = xcalloc(count, sizeof(DispPtr));
	if (!pConfScreen->displayList) {
	    xf86ConfFreeScreenData(pConfScreen);
	    return NULL;
	}
	count = 0;
	dispptr = confScreen->scrn_display_lst;
	while (dispptr) {
	    pConfScreen->displayList[count] = xf86ConfAllocDisplay();
	    if (!pConfScreen->displayList[count]) {
		xf86ConfFreeScreenData(pConfScreen);
		return NULL;
	    }
	    if (!convertDisplay(pConfScreen->displayList[count], dispptr)) {
		xf86ConfFreeScreenData(pConfScreen);
		return NULL;
	    }
	    count++;
	    dispptr = dispptr->list.next;
	}
    }

    /*
     * Figure out how many videoadaptor references there.
     */
    count = 0;
    conf_adaptor = confScreen->scrn_adaptor_lst;
    while (conf_adaptor) {
	count++;
	conf_adaptor = conf_adaptor->list.next;
    }
    pConfScreen->numXvAdaptors = count;
    if (count > 0) {
	pConfScreen->xvAdaptorNames = xcalloc(count, sizeof(char *));
	if (!pConfScreen->xvAdaptorNames) {
	    xf86ConfFreeScreenData(pConfScreen);
	    return NULL;
	}
	conf_adaptor = confScreen->scrn_adaptor_lst;
	count = 0;
	while (conf_adaptor) {
	    pConfScreen->xvAdaptorNames[count] =
		xstrdup(conf_adaptor->al_adaptor_str);
	    if (conf_adaptor->al_adaptor_str &&
		!pConfScreen->xvAdaptorNames[count]) {
		xf86ConfFreeScreenData(pConfScreen);
		return NULL;
	    }
	    count++;
	    conf_adaptor = conf_adaptor->list.next;
	}
    }
    return pConfScreen;
}

confScreenPtr
xf86ConfGetScreenByName(ConfigHandle handle, const char *name, int depth)
{
    const XF86ConfigRec *pConfig;
    XF86ConfScreenPtr s;
    confScreenPtr pConfScreen = NULL;

    if (!name)
	return NULL;

    pConfig = ConfigHandleToConfigRead(handle);
    for (s = pConfig->conf_screen_lst; s; s = s->list.next) {
	if (xf86nameCompare(s->scrn_identifier, name) == 0) {
	    break;
	}
    }
    if (s) {
	pConfScreen = xf86ConfAllocScreen();
	if (pConfScreen) {
	    if (!convertScreen(pConfScreen, s)) {
		xfree(pConfScreen);
		return NULL;
	    }
	    if (depth > 0) {
		if (!xf86ConfResolveScreen(handle, pConfScreen, depth)) {
		    xf86ConfFreeScreenData(pConfScreen);
		    xfree(pConfScreen);
		    return NULL;
		}
	    }
	    return pConfScreen;
	}
    }
    return NULL;
}

static const confScreenRec *
getNextActiveScreen(ConfigDataHandle prev)
{
    int i;
    Bool found = FALSE;

    for (i = 0; i < xf86Info.serverLayout->numScreens; i++) {
	if (!prev) {
	    found = TRUE;
	    break;
	} else if (xf86Info.serverLayout->screenLayouts[i]->screen->handle ==
		   prev) {
	    i++;
	    found = TRUE;
	    break;
	}
    }
    if (found && i < xf86Info.serverLayout->numScreens)
	return xf86Info.serverLayout->screenLayouts[i]->screen;
    else
	return NULL;
}

confScreenPtr
xf86ConfGetNextScreen(ConfigHandle handle, ConfigDataHandle prevScreenHandle,
		      int depth)
{
    const XF86ConfigRec *pConfig;
    XF86ConfScreenPtr s;
    confScreenPtr pConfScreen = NULL;

    if (handle == ACTIVE_CONFIG)
	return xf86ConfDupScreen(getNextActiveScreen(prevScreenHandle), depth);

    pConfig = ConfigHandleToConfigRead(handle);
    if (!prevScreenHandle) {
	s = pConfig->conf_screen_lst;
    } else {
	for (s = pConfig->conf_screen_lst; s; s = s->list.next) {
	    if (s == prevScreenHandle) {
		s = s->list.next;
		break;
	    }
	}
    }
    if (s) {
	pConfScreen = xf86ConfAllocScreen();
	if (pConfScreen) {
	    if (!convertScreen(pConfScreen, s)) {
		xfree(pConfScreen);
		return NULL;
	    }
	    if (depth > 0) {
		if (!xf86ConfResolveScreen(handle, pConfScreen, depth)) {
		    xf86ConfFreeScreenData(pConfScreen);
		    xfree(pConfScreen);
		    return NULL;
		}
	    }
	    return pConfScreen;
	}
    }
    return NULL;
}

DisplayModePtr
xf86ConfAllocMode()
{
    DisplayModePtr pMode;

    pMode = xcalloc(1, sizeof(*pMode));
    return pMode;
}

void
xf86ConfFreeModeData(DisplayModePtr pMode)
{
    if (!pMode)
	return;

    if (pMode->name) {
	xfree(pMode->name);
	pMode->name = NULL;
    }
    return;
}

DisplayModePtr
xf86ConfDupMode(const DisplayModeRec *pMode, int depth)
{
    DisplayModePtr m;

    if (!pMode)
	return NULL;

    m = xf86ConfAllocMode();
    if (!m)
	return NULL;

    if (depth > 0) {
	*m = *pMode;
	m->prev = NULL;
	m->next = NULL;
	m->name = NULL;
    } else {
	m->Clock = pMode->Clock;
	m->HDisplay = pMode->HDisplay;
	m->HSyncStart = pMode->HSyncStart;
	m->HSyncEnd = pMode->HSyncEnd;
	m->HTotal = pMode->HTotal;
	m->VDisplay = pMode->VDisplay;
	m->VSyncStart = pMode->VSyncStart;
	m->VSyncEnd = pMode->VSyncEnd;
	m->VTotal = pMode->VTotal;
	m->Flags = pMode->Flags;
	m->HSkew = pMode->HSkew;
	m->VScan = pMode->VScan;
    }
    m->name = xstrdup(pMode->name);
    if (pMode->name && !m->name) {
	xf86ConfFreeModeData(m);
	xfree(m);
	return NULL;
    }
    return m;
}

DisplayModePtr
xf86ConfAllocModeList(int n)
{
    DisplayModePtr pModes, prev = NULL, first = NULL, last = NULL;
    int i;

    if (n <= 0)
	return NULL;

    for (i = 0; i < n; i++) {
	pModes = xf86ConfAllocMode();
	if (!pModes) {
	    xf86ConfFreeModeList(first);
	    return NULL;
	}
	if (prev) {
	    prev->next = pModes;
	    pModes->prev = prev;
	}
	if (!first)
	    first = pModes;
	prev = last = pModes;
    }
    /* Pass back the 'last' value through first->prev. */
    if (first)
	first->prev = last;
    return first;
}

void
xf86ConfFreeModeList(DisplayModePtr pModes)
{
    DisplayModePtr m, next, first;

    if (!pModes)
	return;

    m = first = pModes;
    do {
	next = m->next;
	xf86ConfFreeModeData(m);
	xfree(m);
	m = next;
    } while (m && m != first);
}

DisplayModePtr
xf86ConfDupModeList(const DisplayModeRec *pModes, int depth)
{
    DisplayModePtr m, prev = NULL, first = NULL, last = NULL;
    const DisplayModeRec *pModeFirst;

    if (!pModes)
	return NULL;

    pModeFirst = pModes;
    do {
	m = xf86ConfDupMode(pModes, depth);
	if (!m) {
	    xf86ConfFreeModeList(first);
	    return NULL;
	}
	if (prev) {
	    prev->next = m;
	    m->prev = prev;
	}
	if (!first)
	    first = m;
	prev = last = m;
	pModes = pModes->next;
    } while (pModes && pModes != pModeFirst);
    /* Pass back the 'last' value through first->prev. */
    if (first)
	first->prev = last;
    return first;
}

static DisplayModePtr
convertMode(DisplayModePtr pMode, const XF86ConfModeLineRec *confMode)
{
    if (!pMode || !confMode)
	return NULL;

    pMode->type = 0;
    pMode->Clock = confMode->ml_clock;
    pMode->HDisplay = confMode->ml_hdisplay;
    pMode->HSyncStart = confMode->ml_hsyncstart;
    pMode->HSyncEnd = confMode->ml_hsyncend;
    pMode->HTotal = confMode->ml_htotal;
    pMode->VDisplay = confMode->ml_vdisplay;
    pMode->VSyncStart = confMode->ml_vsyncstart;
    pMode->VSyncEnd = confMode->ml_vsyncend;
    pMode->VTotal = confMode->ml_vtotal;
    pMode->Flags = confMode->ml_flags;
    pMode->HSkew = confMode->ml_hskew;
    pMode->VScan = confMode->ml_vscan;
    pMode->name = xstrdup(confMode->ml_identifier);
    if (confMode->ml_identifier && !pMode->name) {
	xf86ConfFreeModeData(pMode);
	return NULL;
    }
    return pMode;
}

confModeSetPtr
xf86ConfAllocModeSet()
{
    confModeSetPtr pModeSet;

    pModeSet = xcalloc(1, sizeof(*pModeSet));
    pModeSet->handle = pModeSet;
    return pModeSet;
}

void
xf86ConfFreeModeSetData(confModeSetPtr pModeSet)
{
    if (!pModeSet)
	return;

    if (pModeSet->identifier) {
	xfree(pModeSet->identifier);
	pModeSet->identifier = NULL;
    }
    if (pModeSet->options) {
	xf86OptionListFree(pModeSet->options);
	pModeSet->options = NULL;
    }
    if (pModeSet->modes) {
	xf86ConfFreeModeList(pModeSet->modes);
	pModeSet->modes = NULL;
    }
}

confModeSetPtr
xf86ConfDupModeSet(const confModeSetRec *pModeSet, int depth)
{
    confModeSetPtr ms;

    if (!pModeSet)
	return NULL;

    ms = xf86ConfAllocModeSet();
    if (!ms)
	return NULL;

    ms->handle = pModeSet->handle;
    ms->identifier = xstrdup(pModeSet->identifier);
    if (pModeSet->identifier && !ms->identifier) {
	xf86ConfFreeModeSetData(ms);
	xfree(ms);
	return NULL;
    }
    ms->options = xf86OptionListDup(pModeSet->options);
    if (pModeSet->options && !ms->options) {
	xf86ConfFreeModeSetData(ms);
	xfree(ms);
	return NULL;
    }
    ms->modes = xf86ConfDupModeList(pModeSet->modes, depth);
    if (pModeSet->modes && !ms->modes) {
	xf86ConfFreeModeSetData(ms);
	xfree(ms);
	return NULL;
    }

    /*
     * Note: As per xf86ConfDupModeList(), the last value is passed
     * back through ms->modes->prev.
     */
    return ms;
}

static confModeSetPtr
convertModeSet(confModeSetPtr pModeSet, const XF86ConfModesRec *confModeSet)
{
    DisplayModePtr m;
    XF86ConfModeLinePtr cmlp;
    int count;

    if (!pModeSet || !confModeSet)
	return NULL;

    pModeSet->handle = confModeSet;
    pModeSet->identifier = xstrdup(confModeSet->modes_identifier);
    if (confModeSet->modes_identifier && !pModeSet->identifier) {
	xf86ConfFreeModeSetData(pModeSet);
	return NULL;
    }
    pModeSet->options = xf86OptionListDup(confModeSet->modes_option_lst);
    if (confModeSet->modes_option_lst && !pModeSet->options) {
	xf86ConfFreeModeSetData(pModeSet);
	return NULL;
    }
    pModeSet->modes = NULL;
    /* Cound the number of modes. */
    cmlp = confModeSet->mon_modeline_lst;
    count = 0;
    while (cmlp) {
	count++;
	cmlp = cmlp->list.next;
    }
    if (count > 0) {
	pModeSet->modes = xf86ConfAllocModeList(count);
	if (!pModeSet->modes) {
	    xf86ConfFreeModeSetData(pModeSet);
	    return NULL;
	}
	cmlp = confModeSet->mon_modeline_lst;
	m = pModeSet->modes;
	while (cmlp && m) {
	    if (!convertMode(m, cmlp)) {
		xf86ConfFreeModeSetData(pModeSet);
		return NULL;
	    }
	    cmlp = cmlp->list.next;
	    m = m->next;
	}
    }

    /*
     * Note: As per xf86ConfAllocModeList(), the last value is passed
     * back through pModeSet->modes->prev.
     */
    return pModeSet;
}

confModeSetPtr
xf86ConfGetModeSetByName(ConfigHandle handle, const char *name)
{
    const XF86ConfigRec *pConfig;
    XF86ConfModesPtr cmp;
    confModeSetPtr pModeSet = NULL;

    if (!name)
	return NULL;

    pConfig = ConfigHandleToConfigRead(handle);
    for (cmp = pConfig->conf_modes_lst; cmp; cmp = cmp->list.next) {
	if (xf86nameCompare(cmp->modes_identifier, name) == 0) {
	    break;
	}
    }
    if (cmp) {
	pModeSet = xf86ConfAllocModeSet();
	if (pModeSet) {
	    if (convertModeSet(pModeSet, cmp))
		return pModeSet;
	    else
		xfree(pModeSet);
	}
    }
    return NULL;
}

confModeSetPtr
xf86ConfGetNextModeSet(ConfigHandle handle, ConfigDataHandle prevModeSetHandle)
{
    const XF86ConfigRec *pConfig;
    XF86ConfModesPtr cmp;
    confModeSetPtr pModeSet = NULL;

    if (handle == ACTIVE_CONFIG)
	return NULL;

    pConfig = ConfigHandleToConfigRead(handle);
    if (!prevModeSetHandle) {
	cmp = pConfig->conf_modes_lst;
    } else {
	for (cmp = pConfig->conf_modes_lst; cmp; cmp = cmp->list.next) {
	    if (cmp == prevModeSetHandle) {
		cmp = cmp->list.next;
		break;
	    }
	}
    }
    if (cmp) {
	pModeSet = xf86ConfAllocModeSet();
	if (pModeSet) {
	    if (convertModeSet(pModeSet, cmp))
		return pModeSet;
	    else
		xfree(pModeSet);
	}
    }
    return NULL;
}

MonPtr
xf86ConfAllocMonitor()
{
    MonPtr pMonitor;

    pMonitor = xcalloc(1, sizeof(*pMonitor));
    pMonitor->handle = pMonitor;
    return pMonitor;
}

void
xf86ConfFreeMonitorData(MonPtr pMonitor)
{
    int i;

    if (!pMonitor)
	return;

    if (pMonitor->id) {
	xfree(pMonitor->id);
	pMonitor->id = NULL;
    }
    if (pMonitor->vendor) {
	xfree(pMonitor->vendor);
	pMonitor->vendor = NULL;
    }
    if (pMonitor->model) {
	xfree(pMonitor->model);
	pMonitor->model = NULL;
    }
    if (pMonitor->modeSetNames) {
	for (i = 0; i < pMonitor->numModeSetNames; i++) {
	    if (pMonitor->modeSetNames[i]) {
		xfree(pMonitor->modeSetNames[i]);
		pMonitor->modeSetNames[i] = NULL;
	    }
	}
	xfree(pMonitor->modeSetNames);
	pMonitor->modeSetNames = NULL;
    }
    pMonitor->numModeSetNames = 0;
    if (pMonitor->Modes) {
	xf86ConfFreeModeList(pMonitor->Modes);
	pMonitor->Modes = NULL;
	pMonitor->Last = NULL;
    }
    if (pMonitor->options) {
	xf86OptionListFree(pMonitor->options);
	pMonitor->options = NULL;
    }
}

MonPtr
xf86ConfDupMonitor(const MonRec *pMonitor, int depth)
{
    int i;
    MonPtr m;
    
    if (!pMonitor)
	return NULL;

    m = xf86ConfAllocMonitor();
    if (!m)
	return NULL;

    m->handle = pMonitor->handle;
    m->defaultMon = pMonitor->defaultMon;
    m->flags = pMonitor->flags;
    m->id = xstrdup(pMonitor->id);
    if (pMonitor->id && !m->id) {
	xf86ConfFreeMonitorData(m);
	xfree(m);
	return NULL;
    }
    m->vendor = xstrdup(pMonitor->vendor);
    if (pMonitor->vendor && !m->vendor) {
	xf86ConfFreeMonitorData(m);
	xfree(m);
	return NULL;
    }
    m->model = xstrdup(pMonitor->model);
    if (pMonitor->model && !m->model) {
	xf86ConfFreeMonitorData(m);
	xfree(m);
	return NULL;
    }
    m->Modes = xf86ConfDupModeList(pMonitor->Modes, depth);
    if (pMonitor->Modes && !m->Modes) {
	xf86ConfFreeMonitorData(m);
	xfree(m);
	return NULL;
    }
    if (m->Modes) {
	m->Last = m->Modes->prev;
	m->Modes->prev = NULL;
    }
    m->gamma = pMonitor->gamma;
    m->widthmm = pMonitor->widthmm;
    m->heightmm = pMonitor->heightmm;
    m->options = xf86OptionListDup(pMonitor->options);
    if (pMonitor->options && !m->options) {
	xf86ConfFreeMonitorData(m);
	xfree(m);
	return NULL;
    }
    memcpy(m->hsync, pMonitor->hsync, sizeof(m->hsync));
    memcpy(m->vrefresh, pMonitor->vrefresh, sizeof(m->vrefresh));
    m->nHsync = pMonitor->nHsync;
    m->nVrefresh = pMonitor->nVrefresh;

    m->numModeSetNames = pMonitor->numModeSetNames;
    if (m->numModeSetNames > 0 && pMonitor->modeSetNames) {
	m->modeSetNames = xcalloc(m->numModeSetNames + 1, sizeof(char *));
	if (!m->modeSetNames) {
	    xf86ConfFreeMonitorData(m);
	    xfree(m);
	    return NULL;
	}
	for (i = 0; i < m->numModeSetNames; i++) {
	    m->modeSetNames[i] = xstrdup(pMonitor->modeSetNames[i]);
	    if (pMonitor->modeSetNames[i] && !m->modeSetNames[i]) {
		xf86ConfFreeMonitorData(m);
		xfree(m);
		return NULL;
	    }
	}
    }
    return m;
}

MonPtr
xf86ConfResolveMonitor(ConfigHandle handle, MonPtr pMonitor)
{
    confModeSetPtr pModeSet;
    DisplayModePtr modes = NULL, last = NULL;
    DisplayModePtr localModes, localLast;
    int i;

    if (!pMonitor)
	return NULL;

    localModes = pMonitor->Modes;
    localLast = pMonitor->Last;
    pMonitor->Modes = NULL;
    pMonitor->Last = NULL;

    /* Put the UseModes references first. */
    if (pMonitor->modeSetNames && pMonitor->numModeSetNames > 0) {
	for (i = 0; i < pMonitor->numModeSetNames; i++) {
	    if (!pMonitor->modeSetNames[i])
		continue;
	    pModeSet =
		xf86ConfGetModeSetByName(handle, pMonitor->modeSetNames[i]);
	    if (!pModeSet) {
		continue;
	    }
	    modes = pModeSet->modes;
	    pModeSet->modes = NULL;
	    xf86ConfFreeModeSetData(pModeSet);
	    xfree(pModeSet);
	    pModeSet = NULL;
	    if (modes) {
		last = modes->prev;
		modes->prev = pMonitor->Last;
		if (!pMonitor->Modes)
			pMonitor->Modes = modes;
		else
			pMonitor->Last->next = modes;
		pMonitor->Last = last;
	    }
	}
    }

    /* Add back in the local modelines. */
    if (localModes) {
	localModes->prev = pMonitor->Last;
	if (!pMonitor->Modes)
	    pMonitor->Modes = localModes;
	else
	    pMonitor->Last->next = localModes;
	pMonitor->Last = localLast;
    }

    /* Add the (VESA) default modes. */
    if (!addDefaultModes(pMonitor)) {
	xf86Msg(X_WARNING, "Could not add default built-in modes.\n");
    }
    return pMonitor;
}

int
xf86ConfCheckResolvedMonitor(const MonRec *pMonitor, int depth, Bool strict)
{
    int failures = 0;

    if (!pMonitor || depth < 1)
	return 0;

    if (strict && (!pMonitor->Modes || !pMonitor->Last)) {
	xf86Msg(X_ERROR, "No modes for Monitor \"%s\".\n", pMonitor->id);
	failures++;
    }
    return failures;
}

static MonPtr
convertMonitor(MonPtr pMonitor, const XF86ConfMonitorRec *confMonitor)
{
    int count, i;
    XF86ConfModesLinkPtr modesLink;
    Gamma zeros = {0.0, 0.0, 0.0};
    float badgamma = 0.0;
    XF86ConfModeLinePtr cmodep;
    DisplayModePtr mode;
    
    if (!pMonitor || !confMonitor)
	return NULL;

    pMonitor->handle = confMonitor;
    pMonitor->id = xstrdup(confMonitor->mon_identifier);
    if (confMonitor->mon_identifier && !pMonitor->id) {
	xf86ConfFreeMonitorData(pMonitor);
	return NULL;
    }
    pMonitor->vendor = xstrdup(confMonitor->mon_vendor);
    if (confMonitor->mon_vendor && !pMonitor->vendor) {
	xf86ConfFreeMonitorData(pMonitor);
	return NULL;
    }
    pMonitor->model = xstrdup(confMonitor->mon_modelname);
    if (confMonitor->mon_modelname && !pMonitor->model) {
	xf86ConfFreeMonitorData(pMonitor);
	return NULL;
    }
    pMonitor->Modes = NULL;
    pMonitor->Last = NULL;
    pMonitor->gamma = zeros;
    pMonitor->widthmm = confMonitor->mon_width;
    pMonitor->heightmm = confMonitor->mon_height;
    pMonitor->options = xf86OptionListDup(confMonitor->mon_option_lst);
    if (confMonitor->mon_option_lst && !pMonitor->options) {
	xf86ConfFreeMonitorData(pMonitor);
	return NULL;
    }

    for (i = 0; i < confMonitor->mon_n_hsync; i++) {
	pMonitor->hsync[i].hi = confMonitor->mon_hsync[i].hi;
	pMonitor->hsync[i].lo = confMonitor->mon_hsync[i].lo;
    }
    pMonitor->nHsync = confMonitor->mon_n_hsync;
    for (i = 0; i < confMonitor->mon_n_vrefresh; i++) {
	pMonitor->vrefresh[i].hi = confMonitor->mon_vrefresh[i].hi;
	pMonitor->vrefresh[i].lo = confMonitor->mon_vrefresh[i].lo;
    }
    pMonitor->nVrefresh = confMonitor->mon_n_vrefresh;

    if (confMonitor->mon_gamma_red > GAMMA_ZERO)
	pMonitor->gamma.red = confMonitor->mon_gamma_red;
    if (confMonitor->mon_gamma_green > GAMMA_ZERO)
	pMonitor->gamma.green = confMonitor->mon_gamma_green;
    if (confMonitor->mon_gamma_blue > GAMMA_ZERO)
	pMonitor->gamma.blue = confMonitor->mon_gamma_blue;
    
    /* Check that the gamma values are within range. */
    if (pMonitor->gamma.red > GAMMA_ZERO &&
	(pMonitor->gamma.red < GAMMA_MIN ||
	 pMonitor->gamma.red > GAMMA_MAX)) {
	badgamma = pMonitor->gamma.red;
    } else if (pMonitor->gamma.green > GAMMA_ZERO &&
	(pMonitor->gamma.green < GAMMA_MIN ||
	 pMonitor->gamma.green > GAMMA_MAX)) {
	badgamma = pMonitor->gamma.green;
    } else if (pMonitor->gamma.blue > GAMMA_ZERO &&
	(pMonitor->gamma.blue < GAMMA_MIN ||
	 pMonitor->gamma.blue > GAMMA_MAX)) {
	badgamma = pMonitor->gamma.blue;
    }
    if (badgamma > GAMMA_ZERO) {
	xf86ConfigError("Gamma value %.f is out of range (%.2f - %.1f)\n",
			badgamma, GAMMA_MIN, GAMMA_MAX);
	xf86ConfFreeMonitorData(pMonitor);
	return NULL;
    }

    /* Count the UseModes references. */
    count = 0;
    modesLink = confMonitor->mon_modes_sect_lst;
    while (modesLink) {
	count++;
	modesLink = modesLink->list.next;
    }
    pMonitor->numModeSetNames = count;
    if (count > 0) {
	pMonitor->modeSetNames = xcalloc(count + 1, sizeof(char *));
	if (!pMonitor->modeSetNames) {
	    xf86ConfFreeMonitorData(pMonitor);
	    return NULL;
	}
	modesLink = confMonitor->mon_modes_sect_lst;
	count = 0;
	while (modesLink) {
	    pMonitor->modeSetNames[count] = xstrdup(modesLink->ml_modes_str);
	    if (modesLink->ml_modes_str && !pMonitor->modeSetNames[count]) {
		xf86ConfFreeMonitorData(pMonitor);
		return NULL;
	    }
	    count++;
	    modesLink = modesLink->list.next;
	}
    }

    cmodep = confMonitor->mon_modeline_lst;
    count = 0;
    while (cmodep) {
	count++;
	cmodep = cmodep->list.next;
    }
    if (count > 0) {
	pMonitor->Modes = xf86ConfAllocModeList(count);
	if (!pMonitor->Modes) {
	    xf86ConfFreeMonitorData(pMonitor);
	    return NULL;
	}
	cmodep = confMonitor->mon_modeline_lst;
	mode = pMonitor->Modes;
	while (cmodep && mode) {
	    if (!convertMode(mode, cmodep)) {
		xf86ConfFreeMonitorData(pMonitor);
		return NULL;
	    }
	    cmodep = cmodep->list.next;
	    mode = mode->next;
	}
    }
    if (pMonitor->Modes) {
	pMonitor->Last = pMonitor->Modes->prev;
	pMonitor->Modes->prev = NULL;
    }
    return pMonitor;
}

MonPtr
xf86ConfGetMonitorByName(ConfigHandle handle, const char *name, int depth)
{
    const XF86ConfigRec *pConfig;
    XF86ConfMonitorPtr m;
    MonPtr pMonitor = NULL;

    if (!name)
	return NULL;

    pConfig = ConfigHandleToConfigRead(handle);
    for (m = pConfig->conf_monitor_lst; m; m = m->list.next) {
	if (xf86nameCompare(m->mon_identifier, name) == 0) {
	    break;
	}
    }
    if (m) {
	pMonitor = xf86ConfAllocMonitor();
	if (pMonitor) {
	    if (!convertMonitor(pMonitor, m)) {
		xfree(pMonitor);
		return NULL;
	    }
	    if (depth > 0) {
		if (!xf86ConfResolveMonitor(handle, pMonitor)) {
		    xf86ConfFreeMonitorData(pMonitor);
		    xfree(pMonitor);
		    return NULL;
		}
	    }
	    return pMonitor;
	}
    }
    return NULL;
}

static const MonRec *
getNextActiveMonitor(ConfigDataHandle prev)
{
    const confScreenRec *pConfScreen = NULL;
    int i = 0;
    Bool found = FALSE;

    while ((pConfScreen = getNextActiveScreen(pConfScreen))) {
	for (i = 0; i < pConfScreen->numMonitors; i++) {
	    if (!prev) {
		found = TRUE;
		break;
	    } else if (pConfScreen->monitors[i]->handle == prev) {
		i++;
		found = TRUE;
		break;
	    }
	}
	if (found) {
	    if (i < pConfScreen->numMonitors)
		break;
	    else {
		prev = NULL;
		found = FALSE;
	    }
	}
    }
    if (found)
	return pConfScreen->monitors[i];
    else
	return NULL;
}

MonPtr
xf86ConfGetNextMonitor(ConfigHandle handle, ConfigDataHandle prevMonitorHandle,
		       int depth)
{
    const XF86ConfigRec *pConfig;
    XF86ConfMonitorPtr m;
    MonPtr pMonitor = NULL;

    if (handle == ACTIVE_CONFIG)
	return xf86ConfDupMonitor(getNextActiveMonitor(prevMonitorHandle),
				  depth);

    pConfig = ConfigHandleToConfigRead(handle);
    if (!prevMonitorHandle) {
	m = pConfig->conf_monitor_lst;
    } else {
	for (m = pConfig->conf_monitor_lst; m; m = m->list.next) {
	    if (m == prevMonitorHandle) {
		m = m->list.next;
		break;
	    }
	}
    }
    if (m) {
	pMonitor = xf86ConfAllocMonitor();
	if (pMonitor) {
	    if (!convertMonitor(pMonitor, m)) {
		xfree(pMonitor);
		return NULL;
	    }
	    if (depth > 0) {
		if (!xf86ConfResolveMonitor(handle, pMonitor)) {
		    xf86ConfFreeMonitorData(pMonitor);
		    xfree(pMonitor);
		    return NULL;
		}
	    }
	    return pMonitor;
	}
    }
    return NULL;
}

static int
lookupVisual(const char *visname)
{
    int i;

    if (!visname || !*visname)
	return -1;

    for (i = 0; i <= DirectColor; i++) {
	if (!xf86nameCompare(visname, xf86VisualNames[i]))
	    break;
    }

    if (i <= DirectColor)
	return i;
    return -1;
}

DispPtr
xf86ConfAllocDisplay()
{
    DispPtr pDisplay;
    rgb noColour = {(unsigned int)-1, (unsigned int)-1, (unsigned int)-1};

    pDisplay = xcalloc(1, sizeof(*pDisplay));
    pDisplay->monitorNum = -1;
    pDisplay->frameX0 = -1;
    pDisplay->frameY0 = -1;
    pDisplay->blackColour = noColour;
    pDisplay->whiteColour = noColour;
    pDisplay->defaultVisual = -1;
    return pDisplay;
}

void
xf86ConfFreeDisplayData(DispPtr pDisplay)
{
    int i;

    if (!pDisplay)
	return;

    if (pDisplay->modes) {
	for (i = 0; pDisplay->modes[i]; i++) {
	    xfree(pDisplay->modes[i]);
	    pDisplay->modes[i] = NULL;
	}
	xfree(pDisplay->modes);
	pDisplay->modes = NULL;
    }
    if (pDisplay->options) {
	xf86OptionListFree(pDisplay->options);
	pDisplay->options = NULL;
    }
}

DispPtr
xf86ConfDupDisplay(const DispRec *pDisplay)
{
    DispPtr d;
    char **p;
    int i, count;

    if (!pDisplay)
	return NULL;

    d = xf86ConfAllocDisplay();
    if (!d)
	return NULL;

    *d = *pDisplay;
    d->options = NULL;
    d->modes = NULL; 
    d->options = xf86OptionListDup(pDisplay->options);
    if (pDisplay->options && !d->options) {
	xf86ConfFreeDisplayData(d);
	xfree(d);
	return NULL;
    }
    p = pDisplay->modes;
    count = 0;
    while (*p) {
	count++;
	p++;
    }
    d->modes = xcalloc(count + 1, sizeof(char*));
    if (!d->modes) {
	xf86ConfFreeDisplayData(d);
	xfree(d);
	return NULL;
    }
    for (i = 0; i < count; i++) {
	d->modes[i] = xstrdup(pDisplay->modes[i]);
	if (pDisplay->modes[i] && !d->modes[i]) {
	    xf86ConfFreeDisplayData(d);
	    xfree(d);
	    return NULL;
	}
    }
    return d;
}

static DispPtr
convertDisplay(DispPtr pDisplay, const XF86ConfDisplayRec *confDisplay)
{
    int count = 0;
    XF86ModePtr mode;
    
    if (!pDisplay || !confDisplay)
	return NULL;

    pDisplay->handle = confDisplay;
    pDisplay->frameX0 = confDisplay->disp_frameX0;
    pDisplay->frameY0 = confDisplay->disp_frameY0;
    pDisplay->virtualX = confDisplay->disp_virtualX;
    pDisplay->virtualY = confDisplay->disp_virtualY;
    pDisplay->depth = confDisplay->disp_depth;
    pDisplay->fbbpp = confDisplay->disp_bpp;
    pDisplay->weight.red = confDisplay->disp_weight.red;
    pDisplay->weight.green = confDisplay->disp_weight.green;
    pDisplay->weight.blue = confDisplay->disp_weight.blue;
    pDisplay->blackColour.red = confDisplay->disp_black.red;
    pDisplay->blackColour.green = confDisplay->disp_black.green;
    pDisplay->blackColour.blue  = confDisplay->disp_black.blue;
    pDisplay->whiteColour.red = confDisplay->disp_white.red;
    pDisplay->whiteColour.green = confDisplay->disp_white.green;
    pDisplay->whiteColour.blue = confDisplay->disp_white.blue;
    pDisplay->options = xf86OptionListDup(confDisplay->disp_option_lst);
    if (confDisplay->disp_option_lst && !pDisplay->options) {
	xf86ConfFreeDisplayData(pDisplay);
	return NULL;
    }
    pDisplay->monitorNum = confDisplay->monitor_num;
    if (confDisplay->disp_visual) {
	pDisplay->defaultVisual = lookupVisual(confDisplay->disp_visual);
	if (pDisplay->defaultVisual == -1) {
	    xf86ConfigError("Invalid visual name: \"%s\"",
			    confDisplay->disp_visual);
	    return FALSE;
	}
    } else {
	pDisplay->defaultVisual = -1;
    }

    /* Hook in the modes. */
    mode = confDisplay->disp_mode_lst;
    while (mode) {
	count++;
	mode = mode->list.next;
    }
    pDisplay->modes = xcalloc(count + 1, sizeof(char*));
    if (!pDisplay->modes) {
	xf86ConfFreeDisplayData(pDisplay);
	return NULL;
    }

    mode = confDisplay->disp_mode_lst;
    count = 0;
    while (mode) {
	pDisplay->modes[count] = xstrdup(mode->mode_name);
	if (mode->mode_name && !pDisplay->modes[count]) {
	    xf86ConfFreeDisplayData(pDisplay);
	    return NULL;
	}
	count++;
	mode = mode->list.next;
    }
    return pDisplay;
}

GDevPtr
xf86ConfAllocGraphicsDevice()
{
    GDevPtr pGDev;

    pGDev = xcalloc(1, sizeof(*pGDev));
    pGDev->chipID = -1;
    pGDev->chipRev = -1;
    pGDev->screen = -1;
    pGDev->handle = pGDev;
    return pGDev;
}

void
xf86ConfFreeGraphicsDeviceData(GDevPtr pGDev)
{
    if (!pGDev)
	return;

    if (pGDev->identifier) {
	xfree(pGDev->identifier);
	pGDev->identifier = NULL;
    }
    if (pGDev->vendor) {
	xfree(pGDev->vendor);
	pGDev->vendor = NULL;
    }
    if (pGDev->board) {
	xfree(pGDev->board);
	pGDev->board = NULL;
    }
    if (pGDev->chipset) {
	xfree(pGDev->chipset);
	pGDev->chipset = NULL;
    }
    if (pGDev->ramdac) {
	xfree(pGDev->ramdac);
	pGDev->ramdac = NULL;
    }
    if (pGDev->driver) {
	xfree(pGDev->driver);
	pGDev->driver = NULL;
    }
    if (pGDev->clockchip) {
	xfree(pGDev->clockchip);
	pGDev->clockchip = NULL;
    }
    if (pGDev->busID) {
	xfree(pGDev->busID);
	pGDev->busID = NULL;
    }
    if (pGDev->options) {
	xf86OptionListFree(pGDev->options);
	pGDev->options = NULL;
    }
}

GDevPtr
xf86ConfDupGraphicsDevice(const GDevRec *pGDev)
{
    GDevPtr g;

    if (!pGDev)
	return NULL;

    g = xf86ConfAllocGraphicsDevice();
    if (!g)
	return NULL;

    g->handle = pGDev->handle;
    g->identifier = xstrdup(pGDev->identifier);
    if (pGDev->identifier && !g->identifier) {
	xf86ConfFreeGraphicsDeviceData(g);
	xfree(g);
	return NULL;
    }
    g->vendor = xstrdup(pGDev->vendor);
    if (pGDev->vendor && !g->vendor) {
	xf86ConfFreeGraphicsDeviceData(g);
	xfree(g);
	return NULL;
    }
    g->board = xstrdup(pGDev->board);
    if (pGDev->board && !g->board) {
	xf86ConfFreeGraphicsDeviceData(g);
	xfree(g);
	return NULL;
    }
    g->chipset = xstrdup(pGDev->chipset);
    if (pGDev->chipset && !g->chipset) {
	xf86ConfFreeGraphicsDeviceData(g);
	xfree(g);
	return NULL;
    }
    g->ramdac = xstrdup(pGDev->ramdac);
    if (pGDev->ramdac && !g->ramdac) {
	xf86ConfFreeGraphicsDeviceData(g);
	xfree(g);
	return NULL;
    }
    g->driver = xstrdup(pGDev->driver);
    if (pGDev->driver && !g->driver) {
	xf86ConfFreeGraphicsDeviceData(g);
	xfree(g);
	return NULL;
    }
    g->videoRam = pGDev->videoRam;
    g->BiosBase = pGDev->BiosBase;
    g->MemBase = pGDev->MemBase;
    g->IOBase = pGDev->IOBase;
    g->clockchip = xstrdup(pGDev->clockchip);
    if (pGDev->clockchip && !g->clockchip) {
	xf86ConfFreeGraphicsDeviceData(g);
	xfree(g);
	return NULL;
    }
    g->busID = xstrdup(pGDev->busID);
    if (pGDev->busID && !g->busID) {
	xf86ConfFreeGraphicsDeviceData(g);
	xfree(g);
	return NULL;
    }
    g->textClockFreq = pGDev->textClockFreq;
    g->chipID = pGDev->chipID;
    g->chipRev = pGDev->chipRev;
    g->options = xf86OptionListDup(pGDev->options);
    if (pGDev->options && !g->options) {
	xf86ConfFreeGraphicsDeviceData(g);
	xfree(g);
	return NULL;
    }
    g->irq = pGDev->irq;
    g->screen = pGDev->screen;

    memcpy(g->dacSpeeds, pGDev->dacSpeeds, sizeof(g->dacSpeeds));
    g->numclocks = pGDev->numclocks;
    memcpy(g->clock, pGDev->clock, sizeof(g->clock));
    g->claimed = pGDev->claimed;
    return g;
}

static GDevPtr
convertGraphicsDevice(GDevPtr pGDev, const XF86ConfDeviceRec *confDevice)
{
    int i;

    if (!pGDev || !confDevice)
	return NULL;

    pGDev->handle = confDevice;
    pGDev->identifier = xstrdup(confDevice->dev_identifier);
    if (confDevice->dev_identifier && !pGDev->identifier) {
	xf86ConfFreeGraphicsDeviceData(pGDev);
	return NULL;
    }
    pGDev->vendor = xstrdup(confDevice->dev_vendor);
    if (confDevice->dev_vendor && !pGDev->vendor) {
	xf86ConfFreeGraphicsDeviceData(pGDev);
	return NULL;
    }
    pGDev->board = xstrdup(confDevice->dev_board);
    if (confDevice->dev_board && !pGDev->board) {
	xf86ConfFreeGraphicsDeviceData(pGDev);
	return NULL;
    }
    pGDev->chipset = xstrdup(confDevice->dev_chipset);
    if (confDevice->dev_chipset && !pGDev->chipset) {
	xf86ConfFreeGraphicsDeviceData(pGDev);
	return NULL;
    }
    pGDev->ramdac = xstrdup(confDevice->dev_ramdac);
    if (confDevice->dev_ramdac && !pGDev->ramdac) {
	xf86ConfFreeGraphicsDeviceData(pGDev);
	return NULL;
    }
    pGDev->driver = xstrdup(confDevice->dev_driver);
    if (confDevice->dev_driver && !pGDev->driver) {
	xf86ConfFreeGraphicsDeviceData(pGDev);
	return NULL;
    }
    pGDev->videoRam = confDevice->dev_videoram;
    pGDev->BiosBase = confDevice->dev_bios_base;
    pGDev->MemBase = confDevice->dev_mem_base;
    pGDev->IOBase = confDevice->dev_io_base;
    pGDev->clockchip = xstrdup(confDevice->dev_clockchip);
    if (confDevice->dev_clockchip && !pGDev->clockchip) {
	xf86ConfFreeGraphicsDeviceData(pGDev);
	return NULL;
    }
    pGDev->busID = xstrdup(confDevice->dev_busid);
    if (confDevice->dev_busid && !pGDev->busID) {
	xf86ConfFreeGraphicsDeviceData(pGDev);
	return NULL;
    }
    pGDev->textClockFreq = confDevice->dev_textclockfreq;
    pGDev->chipID = confDevice->dev_chipid;
    pGDev->chipRev = confDevice->dev_chiprev;
    pGDev->options = xf86OptionListDup(confDevice->dev_option_lst);
    if (confDevice->dev_option_lst && !pGDev->options) {
	xf86ConfFreeGraphicsDeviceData(pGDev);
	return NULL;
    }
    pGDev->irq = confDevice->dev_irq;
    pGDev->screen = confDevice->dev_screen;

    for (i = 0; i < MAXDACSPEEDS; i++) {
	if (i < CONF_MAXDACSPEEDS)
	    pGDev->dacSpeeds[i] = confDevice->dev_dacSpeeds[i];
	else
	    pGDev->dacSpeeds[i] = 0;
    }
    pGDev->numclocks = confDevice->dev_clocks;
    if (pGDev->numclocks > MAXCLOCKS)
	pGDev->numclocks = MAXCLOCKS;
    for (i = 0; i < pGDev->numclocks; i++) {
	pGDev->clock[i] = confDevice->dev_clock[i];
    }
    pGDev->claimed = FALSE;
    return pGDev;
}

GDevPtr
xf86ConfGetGraphicsDeviceByName(ConfigHandle handle, const char *name)
{
    const XF86ConfigRec *pConfig;
    XF86ConfDevicePtr d;
    GDevPtr pGDev = NULL;

    if (!name)
	return NULL;

    pConfig = ConfigHandleToConfigRead(handle);
    for (d = pConfig->conf_device_lst; d; d = d->list.next) {
	if (xf86nameCompare(d->dev_identifier, name) == 0) {
	    break;
	}
    }
    if (d) {
	pGDev = xf86ConfAllocGraphicsDevice();
	if (pGDev) {
	    if (convertGraphicsDevice(pGDev, d))
		return pGDev;
	    else
		xfree(pGDev);
	}
    }
    return NULL;
}

static const GDevRec *
getNextActiveGraphicsDevice(ConfigDataHandle prev)
{
    const confScreenRec *pConfScreen = NULL;
    Bool found = FALSE;

    while ((pConfScreen = getNextActiveScreen(pConfScreen))) {
	if (!prev) {
	    found = TRUE;
	    break;
	} else if (pConfScreen->device->handle == prev) {
	    pConfScreen = getNextActiveScreen(pConfScreen);
	    found = TRUE;;
	    break;
	}
    }
    if (found && pConfScreen)
	return pConfScreen->device;
    else
	return NULL;
}

GDevPtr
xf86ConfGetNextGraphicsDevice(ConfigHandle handle,
			      ConfigDataHandle prevDeviceHandle)
{
    const XF86ConfigRec *pConfig;
    XF86ConfDevicePtr d;
    GDevPtr pGDev = NULL;

    if (handle == ACTIVE_CONFIG)
	return xf86ConfDupGraphicsDevice(
			getNextActiveGraphicsDevice(prevDeviceHandle));

    pConfig = ConfigHandleToConfigRead(handle);
    if (!prevDeviceHandle) {
	d = pConfig->conf_device_lst;
    } else {
	for (d = pConfig->conf_device_lst; d; d = d->list.next) {
	    if (d == prevDeviceHandle) {
		d = d->list.next;
		break;
	    }
	}
    }
    if (d) {
	pGDev = xf86ConfAllocGraphicsDevice();
	if (pGDev) {
	    if (convertGraphicsDevice(pGDev, d))
		return pGDev;
	    else
		xfree(pGDev);
	}
    }
    return NULL;
}

confDRIBufferPtr
xf86ConfAllocDRIBuffer()
{
    confDRIBufferPtr pDriBuf;

    pDriBuf = xcalloc(1, sizeof(*pDriBuf));
    return pDriBuf;
}

void
xf86ConfFreeDRIBufferData(confDRIBufferPtr pDriBuf)
{
    if (!pDriBuf)
	return;
}

confDRIBufferPtr
xf86ConfDupDRIBuffer(const confDRIBufferRec *pDriBuf)
{
    confDRIBufferPtr b;

    if (!pDriBuf)
	return NULL;

    b = xf86ConfAllocDRIBuffer();
    b->count = pDriBuf->count;
    b->size = pDriBuf->size;
    b->flags = pDriBuf->flags;
    return b;
}

confDRIPtr
xf86ConfAllocDRI()
{
    confDRIPtr pDri;

    pDri = xcalloc(1, sizeof(*pDri));
    pDri->group = -1;
    pDri->mode = 0;
    pDri->handle = pDri;
    return pDri;
}

void
xf86ConfFreeDRIData(confDRIPtr pDri)
{
    int i;

    if (!pDri)
	return;

    if (pDri->id) {
	xfree(pDri->id);
	pDri->id = NULL;
    }
    if (pDri->groupName) {
	xfree(pDri->groupName);
	pDri->groupName = NULL;
    }
    if (pDri->options) {
	xf86OptionListFree(pDri->options);
	pDri->options = NULL;
    }
    if (pDri->bufsList) {
	for (i = 0; i < pDri->bufs_count; i++) {
	    xf86ConfFreeDRIBufferData(pDri->bufsList[i]);
	    xfree(pDri->bufsList[i]);
	    pDri->bufsList[i] = NULL;
	}
	xfree(pDri->bufsList);
	pDri->bufsList = NULL;
    }
    pDri->bufs_count = 0;
}

confDRIPtr
xf86ConfDupDRI(const confDRIRec *pDri)
{
    confDRIPtr d;
    int i;

    if (!pDri)
	return NULL;

    d = xf86ConfAllocDRI();
    if (!d)
	return NULL;

    d->handle = pDri->handle;
    d->id = xstrdup(pDri->id);
    if (pDri->id && !d->id) {
	xf86ConfFreeDRIData(d);
	xfree(d);
	return NULL;
    }
    d->options = xf86OptionListDup(pDri->options);
    if (pDri->options && !d->options) {
	xf86ConfFreeDRIData(d);
	xfree(d);
	return NULL;
    }
    d->groupName = xstrdup(pDri->groupName);
    if (pDri->groupName && !d->groupName) {
	xf86ConfFreeDRIData(d);
	xfree(d);
	return NULL;
    }
    d->group = pDri->group;
    d->mode = pDri->mode;
    d->bufs_count = pDri->bufs_count;
    if (d->bufs_count > 0 && pDri->bufsList) {
	d->bufsList = xcalloc(d->bufs_count, sizeof(confDRIBufferPtr));
	if (!d->bufsList) {
	    xf86ConfFreeDRIData(d);
	    xfree(d);
	    return NULL;
	}
	for (i = 0; i < d->bufs_count; i++) {
	    d->bufsList[i] = xf86ConfDupDRIBuffer(pDri->bufsList[i]);
	    if (!d->bufsList[i]) {
		xf86ConfFreeDRIData(d);
		xfree(d);
		return NULL;
	    }
	}
    }
    return d;
}

static confDRIBufferPtr
convertDRIBuffer(confDRIBufferPtr pDriBuf, const XF86ConfBuffersRec *bufConf)
{
    if (!pDriBuf || !bufConf)
	return NULL;

    pDriBuf->count = bufConf->buf_count;
    pDriBuf->size = bufConf->buf_size;
    /*
     * FIXME: Flags not implemented.  These could be used, for example,
     * to specify a contiguous block and/or write-combining cache policy.
     */
    pDriBuf->flags = XF86DRI_NO_FLAGS;
    return pDriBuf;
}

static confDRIPtr
convertDRI(confDRIPtr pDri, const XF86ConfDRIRec *driConf)
{
    struct group *groupId;
    const XF86ConfBuffersRec *db;
    int count, i;

    if (!pDri || !driConf)
	return NULL;

    pDri->handle = driConf;
    pDri->id = xstrdup(driConf->dri_identifier);
    if (driConf->dri_identifier && !pDri->id) {
	xf86ConfFreeDRIData(pDri);
	return NULL;
    }
    pDri->options = xf86OptionListDup(driConf->dri_option_lst);
    if (driConf->dri_option_lst && !pDri->options) {
	xf86ConfFreeDRIData(pDri);
	return NULL;
    }
    if (driConf->dri_group_name) {
	pDri->groupName = xstrdup(driConf->dri_group_name);
	if (!pDri->groupName) {
	    xf86ConfFreeDRIData(pDri);
	    return NULL;
	}
	if ((groupId = getgrnam(driConf->dri_group_name)))
	    pDri->group = groupId->gr_gid;
    } else {
	if (driConf->dri_group >= 0)
	    pDri->group = driConf->dri_group;
    }
    pDri->mode = driConf->dri_mode;

    /* Count how many buffers references there are. */
    count = 0;
    db = driConf->dri_buffers_lst;
    while (db) {
	count++;
	db = db->list.next;
    }

    pDri->bufs_count = count;
    if (count > 0) {
	pDri->bufsList = xcalloc(1, sizeof(confDRIBufferPtr));
	if (!pDri->bufsList) {
	    xf86ConfFreeDRIData(pDri);
	    return NULL;
	}
	db = driConf->dri_buffers_lst;
	for (i = 0; i < count; i++) {
	    pDri->bufsList[i] = xf86ConfAllocDRIBuffer();
	    if (!convertDRIBuffer(pDri->bufsList[i], db)) {
		xf86ConfFreeDRIData(pDri);
		return NULL;
	    }
	}
    }
    return pDri;
}

confDRIPtr
xf86ConfGetDRIByName(ConfigHandle handle, const char *name)
{
    const XF86ConfigRec *pConfig;
    XF86ConfDRIPtr d;
    confDRIPtr pDri = NULL;

    if (!name)
	return NULL;

    pConfig = ConfigHandleToConfigRead(handle);
    for (d = pConfig->conf_dri_lst; d; d = d->list.next) {
	if (xf86nameCompare(d->dri_identifier, name) == 0)
	    break;
    }
    if (d) {
	pDri = xf86ConfAllocDRI();
	if (pDri) {
	    if (convertDRI(pDri, d))
		return pDri;
	    else
		xfree(pDri);
	}
    }
    return NULL;
}

confDRIPtr
xf86ConfGetNextDRI(ConfigHandle handle, ConfigDataHandle prevDRIHandle)
{
    const XF86ConfigRec *pConfig;
    XF86ConfDRIPtr d;
    confDRIPtr pDri = NULL;

    if (handle == ACTIVE_CONFIG) {
	if (!prevDRIHandle)
	    return xf86ConfDupDRI(&xf86ConfigDRI);
	else
	    return NULL;
    }

    pConfig = ConfigHandleToConfigRead(handle);
    if (!prevDRIHandle) {
	d = pConfig->conf_dri_lst;
    } else {
	for (d = pConfig->conf_dri_lst; d; d = d->list.next) {
	    if (d == prevDRIHandle) {
		d = d->list.next;
		break;
	    }
	}
    }
    if (d) {
	pDri = xf86ConfAllocDRI();
	if (pDri) {
	    if (convertDRI(pDri, d))
		return pDri;
	    else
		xfree(pDri);
	}
    }
    return NULL;
}

static confDRIPtr
configDRI(ConfigHandle handle, const XF86ConfDRIRec *driConf, MessageType from)
{
    confDRIPtr d = NULL;

    /* If driConf is supplied, us it.  If not, use the first DRI section. */
    if (driConf) {
	d = xf86ConfAllocDRI();
	if (!d)
	    return NULL;
	if (!(d = convertDRI(d, driConf))) {
	    xfree(d);
	    return NULL;
	}
    } else {
	d = xf86ConfGetNextDRI(handle, NULL);
    }
    /* If no DRI section found, create the default. */
    if (!d) {
	d = xf86ConfAllocDRI();
    }
    return d;
}

IDevPtr
xf86ConfAllocInputDevice()
{
    IDevPtr pIDev;

    pIDev = xcalloc(1, sizeof(*pIDev));
    pIDev->handle = pIDev;
    pIDev->from = X_NONE;
    return pIDev;
}

void
xf86ConfFreeInputDeviceData(IDevPtr pIDev)
{
    if (!pIDev)
	return;

    if (pIDev->identifier) {
	xfree(pIDev->identifier);
	pIDev->identifier = NULL;
    }
    if (pIDev->driver) {
	xfree(pIDev->driver);
	pIDev->driver = NULL;
    }
    if (pIDev->commonOptions) {
	xf86OptionListFree(pIDev->commonOptions);
	pIDev->commonOptions = NULL;
    }
    if (pIDev->extraOptions) {
	xf86OptionListFree(pIDev->extraOptions);
	pIDev->extraOptions = NULL;
    }
    return;
}

IDevPtr
xf86ConfDupInputDevice(const IDevRec *pIDev, int depth)
{
    IDevPtr i;

    if (!pIDev)
	return NULL;

    i = xf86ConfAllocInputDevice();
    if (!i)
	return NULL;

    i->handle = pIDev->handle;
    i->from = pIDev->from;
    i->identifier = xstrdup(pIDev->identifier);
    if (pIDev->identifier && !i->identifier) {
	xf86ConfFreeInputDeviceData(i);
	xfree(i);
	return NULL;
    }
    i->driver = xstrdup(pIDev->driver);
    if (pIDev->driver && !i->driver) {
	xf86ConfFreeInputDeviceData(i);
	xfree(i);
	return NULL;
    }
    i->commonOptions = xf86OptionListDup(pIDev->commonOptions);
    if (pIDev->commonOptions && !i->commonOptions) {
	xf86ConfFreeInputDeviceData(i);
	xfree(i);
	return NULL;
    }
    if (depth > 0) {
	i->extraOptions = xf86OptionListDup(pIDev->extraOptions);
	if (pIDev->extraOptions && !i->extraOptions) {
	    xf86ConfFreeInputDeviceData(i);
	    xfree(i);
	    return NULL;
	}
    }
    return i;
}

static IDevPtr
convertInputDevice(IDevPtr pIDev, const XF86ConfInputRec *confInput)
{
    if (!pIDev || !confInput)
	return NULL;

    pIDev->handle = confInput;
    pIDev->from = X_CONFIG;
    pIDev->identifier = xstrdup(confInput->inp_identifier);
    if (confInput->inp_identifier && !pIDev->identifier) {
	xf86ConfFreeInputDeviceData(pIDev);
	return NULL;
    }
    pIDev->driver = xstrdup(confInput->inp_driver);
    if (confInput->inp_driver && !pIDev->driver) {
	xf86ConfFreeInputDeviceData(pIDev);
	return NULL;
    }
    pIDev->commonOptions = xf86OptionListDup(confInput->inp_option_lst);
    if (confInput->inp_option_lst && !pIDev->commonOptions) {
	xf86ConfFreeInputDeviceData(pIDev);
	return NULL;
    }
    pIDev->extraOptions = NULL;
    return pIDev;
}

IDevPtr
xf86ConfGetInputDeviceByName(ConfigHandle handle, const char *name)
{
    const XF86ConfigRec *pConfig;
    XF86ConfInputPtr i;
    IDevPtr pIDev = NULL;

    if (!name)
	return NULL;

    pConfig = ConfigHandleToConfigRead(handle);
    for (i = pConfig->conf_input_lst; i; i = i->list.next) {
	if (xf86nameCompare(i->inp_identifier, name) == 0) {
	    break;
	}
    }
    if (i) {
	pIDev = xf86ConfAllocInputDevice();
	if (pIDev) {
	    if (convertInputDevice(pIDev, i))
		return pIDev;
	    else
		xfree(pIDev);
	}
    }
    return NULL;
}

static const IDevRec *
getNextActiveInputDevice(ConfigDataHandle prev)
{
    int i;
    Bool found = FALSE;

    for (i = 0; i < xf86Info.serverLayout->numInputs; i++) {
	if (!prev) {
	    found = TRUE;
	    break;
	} else if (xf86Info.serverLayout->inputDevs[i]->handle == prev) {
	    i++;
	    found = TRUE;
	    break;
	}
    }
    if (found && i < xf86Info.serverLayout->numInputs)
	return xf86Info.serverLayout->inputDevs[i];
    else
	return NULL;
}

IDevPtr
xf86ConfGetNextInputDevice(ConfigHandle handle, ConfigDataHandle prevIDevHandle,
			   int depth)
{
    const XF86ConfigRec *pConfig;
    XF86ConfInputPtr i;
    IDevPtr pIDev = NULL;

    if (handle == ACTIVE_CONFIG)
	return xf86ConfDupInputDevice(getNextActiveInputDevice(prevIDevHandle),
				      depth);

    pConfig = ConfigHandleToConfigRead(handle);
    if (!prevIDevHandle) {
	i = pConfig->conf_input_lst;
    } else {
	for (i = pConfig->conf_input_lst; i; i = i->list.next) {
	    if (i == prevIDevHandle) {
		i = i->list.next;
		break;
	    }
	}
    }
    if (i) {
	pIDev = xf86ConfAllocInputDevice();
	if (pIDev) {
	    if (convertInputDevice(pIDev, i))
		return pIDev;
	    else
		xfree(pIDev);
	}
    }
    return NULL;
}

IDevPtr
xf86ConfGetInputDeviceByDriver(ConfigHandle handle, const char *driver)
{
    const XF86ConfigRec *pConfig;
    XF86ConfInputPtr i;
    IDevPtr pIDev = NULL;

    if (!driver)
	return NULL;

    pConfig = ConfigHandleToConfigRead(handle);
    for (i = pConfig->conf_input_lst; i; i = i->list.next) {
	if (xf86nameCompare(i->inp_driver, driver) == 0) {
	    break;
	}
    }
    if (i) {
	pIDev = xf86ConfAllocInputDevice();
	if (pIDev) {
	    if (convertInputDevice(pIDev, i))
		return pIDev;
	    else
		xfree(pIDev);
	}
    }
    return NULL;
}

IDevPtr
xf86ConfGetInputDeviceByOption(ConfigHandle handle, const char *option)
{
    const XF86ConfigRec *pConfig;
    XF86ConfInputPtr i;
    IDevPtr pIDev = NULL;

    if (!option)
	return NULL;

    pConfig = ConfigHandleToConfigRead(handle);
    for (i = pConfig->conf_input_lst; i; i = i->list.next) {
	if (xf86CheckBoolOption(i->inp_option_lst, option, FALSE)) {
	    break;
	}
    }
    if (i) {
	pIDev = xf86ConfAllocInputDevice();
	if (pIDev) {
	    if (convertInputDevice(pIDev, i))
		return pIDev;
	    else
		xfree(pIDev);
	}
    }
    return NULL;
}

confVendorSubPtr
xf86ConfAllocVendorSub()
{
    confVendorSubPtr pVendorSub;

    pVendorSub = xcalloc(1, sizeof(*pVendorSub));
    pVendorSub->handle = pVendorSub;
    return pVendorSub;
}

void
xf86ConfFreeVendorSubData(confVendorSubPtr pVendorSub)
{
    if (!pVendorSub)
	return;

    if (pVendorSub->identifier) {
	xfree(pVendorSub->identifier);
	pVendorSub->identifier = NULL;
    }
    if (pVendorSub->name) {
	xfree(pVendorSub->name);
	pVendorSub->name = NULL;
    }
    if (pVendorSub->options) {
	xf86OptionListFree(pVendorSub->options);
	pVendorSub->options = NULL;
    }
}

confVendorSubPtr
xf86ConfDupVendorSub(const confVendorSubRec *pVendorSub)
{
    confVendorSubPtr sv;

    if (!pVendorSub)
	return NULL;

    sv = xf86ConfAllocVendorSub();
    if (!sv)
	return NULL;

    sv->handle = pVendorSub->handle;
    sv->identifier = xstrdup(pVendorSub->identifier);
    if (pVendorSub->identifier && !sv->identifier) {
	xf86ConfFreeVendorSubData(sv);
	xfree(sv);
	return NULL;
    }
    sv->name = xstrdup(pVendorSub->name);
    if (pVendorSub->name && !sv->name) {
	xf86ConfFreeVendorSubData(sv);
	xfree(sv);
	return NULL;
    }
    sv->options = xf86OptionListDup(pVendorSub->options);
    if (pVendorSub->options && !sv->options) {
	xf86ConfFreeVendorSubData(sv);
	xfree(sv);
	return NULL;
    }
    return sv;
}

/*
 * Convert a Vendor subsection from the parser's format to the server's format.
 */
static confVendorSubPtr
convertVendorSub(confVendorSubPtr pVendorSub,
		 const XF86ConfVendSubRec *vendorSubConf)
{
    if (!pVendorSub || !vendorSubConf)
	return NULL;

    pVendorSub->handle = vendorSubConf;
    pVendorSub->identifier = xstrdup(vendorSubConf->vs_identifier);
    if (vendorSubConf->vs_identifier && !pVendorSub->identifier) {
	xf86ConfFreeVendorSubData(pVendorSub);
	return NULL;
    }
    pVendorSub->name = xstrdup(vendorSubConf->vs_name);
    if (vendorSubConf->vs_name && !pVendorSub->name) {
	xf86ConfFreeVendorSubData(pVendorSub);
	return NULL;
    }
    pVendorSub->options = xf86OptionListDup(vendorSubConf->vs_option_lst);
    if (vendorSubConf->vs_option_lst && !pVendorSub->options) {
	xf86ConfFreeVendorSubData(pVendorSub);
	return NULL;
    }
    return pVendorSub;
}

confVendorPtr
xf86ConfAllocVendor()
{
    confVendorPtr pVendor;

    pVendor = xcalloc(1, sizeof(*pVendor));
    pVendor->handle = pVendor;
    return pVendor;
}

void
xf86ConfFreeVendorData(confVendorPtr pVendor)
{
    int i;

    if (!pVendor)
	return;

    if (pVendor->identifier) {
	xfree(pVendor->identifier);
	pVendor->identifier = NULL;
    }
    if (pVendor->vendorName) {
	xfree(pVendor->vendorName);
	pVendor->vendorName = NULL;
    }
    if (pVendor->options) {
	xf86OptionListFree(pVendor->options);
	pVendor->options = NULL;
    }
    if (pVendor->subs) {
	for (i = 0; i < pVendor->numSubs; i++) {
	    xf86ConfFreeVendorSubData(pVendor->subs[i]);
	    xfree(pVendor->subs[i]);
	    pVendor->subs[i] = NULL;
	}
	xfree(pVendor->subs);
	pVendor->subs = NULL;
    }
    pVendor->numSubs = 0;
}

confVendorPtr
xf86ConfDupVendor(const confVendorRec *pVendor)
{
    confVendorPtr v;
    int i;

    if (!pVendor)
	return NULL;

    v = xf86ConfAllocVendor();
    if (!v)
	return NULL;

    v->handle = pVendor->handle;
    v->identifier = xstrdup(pVendor->identifier);
    if (pVendor->identifier && !v->identifier) {
	xf86ConfFreeVendorData(v);
	xfree(v);
	return NULL;
    }
    v->vendorName = xstrdup(pVendor->vendorName);
    if (pVendor->vendorName && !v->vendorName) {
	xf86ConfFreeVendorData(v);
	xfree(v);
	return NULL;
    }
    v->options = xf86OptionListDup(pVendor->options);
    if (pVendor->options && !v->options) {
	xf86ConfFreeVendorData(v);
	xfree(v);
	return NULL;
    }

    v->numSubs = pVendor->numSubs;
    if (v->numSubs && pVendor->subs) {
	v->subs = xcalloc(v->numSubs, sizeof(confVendorSubPtr));
	if (!v->subs) {
	    xf86ConfFreeVendorData(v);
	    xfree(v);
	    return NULL;
	}
	for (i = 0; i < v->numSubs; i++) {
	    v->subs[i] = xf86ConfDupVendorSub(pVendor->subs[i]);
	    if (!v->subs[i]) {
		xf86ConfFreeVendorData(v);
		xfree(v);
		return NULL;
	    }
	}
    }
    return v;
}

/*
 * Convert a Vendor section from the parser's format to the server's format.
 */
static confVendorPtr
convertVendor(confVendorPtr pVendor, const XF86ConfVendorRec *vendorConf)
{
    XF86ConfVendSubPtr vsp;
    int count, i;

    if (!pVendor || !vendorConf)
	return NULL;

    pVendor->handle = vendorConf;
    pVendor->identifier = xstrdup(vendorConf->vnd_identifier);
    if (vendorConf->vnd_identifier && !pVendor->identifier) {
	xf86ConfFreeVendorData(pVendor);
	return NULL;
    }
    pVendor->vendorName = xstrdup(vendorConf->vnd_name);
    if (vendorConf->vnd_name && !pVendor->vendorName) {
	xf86ConfFreeVendorData(pVendor);
	return NULL;
    }
    pVendor->options = xf86OptionListDup(vendorConf->vnd_option_lst);
    if (vendorConf->vnd_option_lst && !pVendor->options) {
	xf86ConfFreeVendorData(pVendor);
	return NULL;
    }

    /* Count how many vendor subsections there are. */
    vsp = vendorConf->vnd_sub_lst;
    count = 0;
    while (vsp) {
	count++;
	vsp = vsp->list.next;
    }
    pVendor->numSubs = count;
    if (count > 0) {
	pVendor->subs = xcalloc(count, sizeof(confVendorSubPtr));
	if (!pVendor->subs) {
	    xf86ConfFreeVendorData(pVendor);
	    return NULL;
	}
	vsp = vendorConf->vnd_sub_lst;
	for (i = 0; i < count; i++) {
	    pVendor->subs[i] = xf86ConfAllocVendorSub();
	    if (!pVendor->subs[i]) {
		xf86ConfFreeVendorData(pVendor);
		return NULL;
	    }
	    if (!convertVendorSub(pVendor->subs[i], vsp)) {
		xf86ConfFreeVendorData(pVendor);
		return NULL;
	    }
	    vsp = vsp->list.next;
	}
    }
    return pVendor;
}

confVendorPtr
xf86ConfGetVendorByName(ConfigHandle handle, const char *name)
{
    const XF86ConfigRec *pConfig;
    XF86ConfVendorPtr v;
    confVendorPtr pVendor = NULL;

    if (!name)
	return NULL;

    pConfig = ConfigHandleToConfigRead(handle);
    for (v = pConfig->conf_vendor_lst; v; v = v->list.next) {
	if (xf86nameCompare(v->vnd_identifier, name) == 0)
	    break;
    }
    if (v) {
	pVendor = xf86ConfAllocVendor();
	if (pVendor) {
	    if (convertVendor(pVendor, v))
		return pVendor;
	    else
		xfree(pVendor);
	}
    }
    return NULL;
}

confVendorPtr
xf86ConfGetVendorByVendorName(ConfigHandle handle, const char *vname)
{
    const XF86ConfigRec *pConfig;
    XF86ConfVendorPtr v;
    confVendorPtr pVendor = NULL;

    if (!vname)
	return NULL;

    pConfig = ConfigHandleToConfigRead(handle);
    for (v = pConfig->conf_vendor_lst; v; v = v->list.next) {
	if (xf86nameCompare(v->vnd_name, vname) == 0)
	    break;
    }
    if (v) {
	pVendor = xf86ConfAllocVendor();
	if (pVendor) {
	    if (convertVendor(pVendor, v))
		return pVendor;
	    else
		xfree(pVendor);
	}
    }
    return NULL;
}

confVendorPtr
xf86ConfGetNextVendor(ConfigHandle handle, ConfigDataHandle prevVendorHandle)
{
    const XF86ConfigRec *pConfig;
    XF86ConfVendorPtr v;
    confVendorPtr pVendor = NULL;

    if (handle == ACTIVE_CONFIG)
	return NULL;

    pConfig = ConfigHandleToConfigRead(handle);
    if (!prevVendorHandle) {
	v = pConfig->conf_vendor_lst;
    } else {
	for (v = pConfig->conf_vendor_lst; v; v = v->list.next) {
	    if (v == prevVendorHandle) {
		v = v->list.next;
		break;
	    }
	}
    }
    if (v) {
	pVendor = xf86ConfAllocVendor();
	if (pVendor) {
	    if (convertVendor(pVendor, v))
		return pVendor;
	    else
		xfree(pVendor);
	}
    }
    return NULL;
}

static Bool
addDefaultModes(MonPtr pMonitor)
{
    DisplayModePtr mode;
    int i = 0;

    while (xf86DefaultModes[i].name != NULL) {
	if (!xf86ModeIsPresent(xf86DefaultModes[i].name, pMonitor->Modes,
			       0, M_T_DEFAULT)) {
	    do {
		mode = xnfalloc(sizeof(DisplayModeRec));
		memcpy(mode, &xf86DefaultModes[i], sizeof(DisplayModeRec));
		if (xf86DefaultModes[i].name)
		    mode->name = xnfstrdup(xf86DefaultModes[i].name);
		xf86AddModeToMonitor(pMonitor, mode);
		i++;
	    } while((xf86DefaultModes[i].name != NULL) &&
		    (!strcmp(xf86DefaultModes[i].name,
			     xf86DefaultModes[i-1].name)));
	} else
	    i++;
    }
    return TRUE;
}

/* Load a config file. */

ConfigStatus
xf86LoadConfigFile(const char *filename, Bool append)
{
    char *searchpath;
    MessageType from = X_DEFAULT;
    XF86ConfigPtr pConfig;

    pConfig = (XF86ConfigPtr)xf86Info.config;
    /* Free any previously allocated config. */
    if (!append && pConfig) {
	xf86freeConfig(pConfig);
	xf86Info.config = pConfig = NULL;
    }

    if (!PRIVS_ELEVATED)
	searchpath = ROOT_CONFIGPATH;
    else
	searchpath = USER_CONFIGPATH;

    if (!filename) {
	if (xf86ConfigFile)
	    from = X_CMDLINE;

	filename = xf86openConfigFile(searchpath, xf86ConfigFile, PROJECTROOT);
	if (filename) {
	    xf86MsgVerb(from, 0, "Using config file: \"%s\".\n", filename);
	    xf86ConfigFile = xnfstrdup(filename);
	} else {
	    xf86Msg(X_ERROR, "Unable to locate/open config file.");
	    if (xf86ConfigFile)
		xf86ErrorFVerb(0, ": \"%s\"", xf86ConfigFile);
	    xf86ErrorFVerb(0, "\n");
	    return CONFIG_NOFILE;
	}
    }

    if (!(xf86Info.config = xf86parseConfigFile(pConfig))) {
	xf86Msg(X_ERROR, "Problem parsing the config file \"%s\".\n",
		filename);
	return CONFIG_PARSE_ERROR;
    }

    xf86closeConfigFile ();
    return CONFIG_OK;
}

Bool
xf86CheckForLayoutOrScreen(ConfigHandle handle)
{
    const XF86ConfigRec *pConfig;

    pConfig = ConfigHandleToConfigRead(handle);
    if (pConfig && (pConfig->conf_layout_lst || pConfig->conf_screen_lst)) {
	return TRUE;
    }
    return FALSE;
}

static void
printLayoutSummary(const serverLayoutRec *pServerLayout)
{
    int i, j;
    screenLayoutPtr pScreenLayout;
    IDevPtr pIDev;
    GDevPtr pGDev;

    if (!pServerLayout)
	return;

    xf86Msg(pServerLayout->from, "ServerLayout \"%s\"\n", pServerLayout->id);
    for (i = 0; i < pServerLayout->numScreens; i++) {
	if (!pServerLayout->screenLayouts[i])
	    continue;
	pScreenLayout = pServerLayout->screenLayouts[i];
	if (pScreenLayout->screen) {
	    char *position = NULL;
	    switch (pScreenLayout->where) {
	    case PosAbsolute:
		xasprintf(&position, "(%d, %d)", pScreenLayout->x,
			  pScreenLayout->y);
		break;
	    case PosRightOf:
		xasprintf(&position, "Right of \"%s\"", pScreenLayout->refname);
		break;
	    case PosLeftOf:
		xasprintf(&position, "Left of \"%s\"", pScreenLayout->refname);
		break;
	    case PosAbove:
		xasprintf(&position,"Above \"%s\"", pScreenLayout->refname);
		break;
	    case PosBelow:
		xasprintf(&position, "Below \"%s\"", pScreenLayout->refname);
		break;
	    case PosRelative:
		xasprintf(&position, "(%d, %d) relative to \"%s\"",
			  pScreenLayout->x, pScreenLayout->y,
			  pScreenLayout->refname);
		break;
	    default:
		position = NULL;
		break;
	    }
	    xf86Msg(xf86ScreenName ? X_CMDLINE : X_DEFAULT,
		    "|-->Screen \"%s\" (%d) %s\n", pScreenLayout->screen->id,
		    pScreenLayout->screen->screennum, EMPTYIFNULL(position));
	    if (position)
		xfree(position);
	    if (pScreenLayout->screen->device) {
		xf86Msg(X_CONFIG, "|  |-->Device \"%s\"\n",
			pScreenLayout->screen->device->identifier);
	    }
	    if (pScreenLayout->screen->monitors) {
		for (j = 0; j < pScreenLayout->screen->numMonitors; j++) {
		    if (pScreenLayout->screen->monitors[j]) {
			xf86Msg(pScreenLayout->screen->monitors[j]->defaultMon ?
				    X_DEFAULT : X_CONFIG,
				"|  |-->Monitor \"%s\" (%d)\n",
				pScreenLayout->screen->monitors[j]->id,
				pScreenLayout->screen->monitors[j]->monitorNum);
		    }
		}
	    }
	    if (pScreenLayout->screen->xvAdaptorList) {
		for (j = 0; j < pScreenLayout->screen->numXvAdaptors; j++) {
		    xf86Msg(X_CONFIG, "|  |-->VideoAdaptor \"%s\"\n",
			pScreenLayout->screen->xvAdaptorList[j]->identifier);
		}
	    }
	}
    }
    if (pServerLayout->inputDevs) {
	for (i = 0; i < pServerLayout->numInputs; i++) {
	    pIDev = pServerLayout->inputDevs[i];
	    if (pIDev) {
		xf86Msg(pIDev->from, "|-->Input Device \"%s\"\n",
			pIDev->identifier);
	    }
	}
    }
    if (pServerLayout->inactiveDevs) {
	for (i = 0; i < pServerLayout->numInactives; i++) {
	    pGDev = pServerLayout->inactiveDevs[i];
	    if (pGDev) {
	    xf86Msg(X_CONFIG, "|-->Inactive Device \"%s\"\n",
		    pGDev->identifier);
	    }
	}
    }
}

/*
 * Process the configuration data from the parser.
 */
ConfigStatus
xf86ProcessConfiguration()
{
    const XF86ConfigRec *pConfig;
    confDRIPtr dri;
    int i;

    pConfig = ConfigHandleToConfigRead(DEFAULT_CONFIG);
    if (!pConfig) {
	xf86Msg(X_ERROR, "No configuration to process.\n");
	return CONFIG_PARSE_ERROR;
    }

    /*
     * Convert the information contained in the parser structures into our
     * own structures.
     */

    /* First check if a layout section is present, and if it is valid. */
    if (!pConfig->conf_layout_lst || xf86ScreenName) {
	if (xf86ScreenName == NULL) {
	    xf86Msg(X_WARNING,
		    "No Layout section.  Using the first Screen section.\n");
	}
	xf86Info.serverLayout =
	    configImpliedServerLayout(DEFAULT_CONFIG, xf86ScreenName);
    } else {
	char *defaultLayout = NULL;

	if (pConfig->conf_flags_lst) {
	    pointer optlist =
		pConfig->conf_flags_lst->flg_option_lst;
	    if (optlist && xf86FindOption(optlist, "defaultserverlayout")) {
		defaultLayout =
		    xf86SetStrOption(optlist, "defaultserverlayout", NULL);
	    }
	}
	xf86Info.serverLayout = configServerLayout(DEFAULT_CONFIG,
						   defaultLayout);
    }
    if (!xf86Info.serverLayout) {
	xf86Msg(X_ERROR, "Unable to determine the screen layout.\n");
	return CONFIG_PARSE_ERROR;
    }

    printLayoutSummary(xf86Info.serverLayout);

    i = xf86ConfCheckResolvedServerLayout(xf86Info.serverLayout,
					  CONFIG_RESOLVE_ALL, TRUE);
    if (i > 0) {
	xf86Msg(X_ERROR, "%d error%s in resolving the ServerLayout \"%s\".\n",
		i, PLURAL(i), xf86Info.serverLayout->id);
	return CONFIG_PARSE_ERROR;
    }
					
    /* Now process everything else */

    xf86Info.confFiles = configFiles(DEFAULT_CONFIG, NULL, X_CONFIG);

    if (!xf86Info.confFiles) {
	xf86Msg(X_ERROR, "Unable to process the Files data.\n");
	return CONFIG_PARSE_ERROR;
    }

    xf86Info.confFlags = configServerFlags(DEFAULT_CONFIG, NULL,
					   xf86Info.serverLayout->options,
					   X_CONFIG);
    if (!xf86Info.confFlags) {
	xf86Msg(X_ERROR, "Unable to process the ServerFlags data.\n");
	return CONFIG_PARSE_ERROR;
    }

    xf86Info.confModules = configModules(DEFAULT_CONFIG, NULL, X_CONFIG);

    if (!xf86Info.confModules) {
	xf86Msg(X_ERROR, "Unable to process the Modules data.\n");
	return CONFIG_PARSE_ERROR;
    }

    dri = configDRI(DEFAULT_CONFIG, NULL, X_CONFIG);
    if (!dri) {
	xf86Msg(X_ERROR, "Unable to process the DRI data.\n");
	return CONFIG_PARSE_ERROR;
    } else {
	xf86ConfigDRI = *dri;
	xfree(dri);
    }

    /*
     * Handle some command line options that can override some of the
     * ServerFlags settings.
     */
#ifdef XF86VIDMODE
    if (xf86VidModeDisabled)
	xf86Info.vidModeEnabled = FALSE;
    if (xf86VidModeAllowNonLocal)
	xf86Info.vidModeAllowNonLocal = TRUE;
#endif

#ifdef XF86MISC
    if (xf86MiscModInDevDisabled)
	xf86Info.miscModInDevEnabled = FALSE;
    if (xf86MiscModInDevAllowNonLocal)
	xf86Info.miscModInDevAllowNonLocal = TRUE;
#endif

    if (xf86AllowMouseOpenFail)
	xf86Info.allowMouseOpenFail = TRUE;
    return CONFIG_OK;
}


/* These make the equivalent parser functions visible to the common layer. */
Bool
xf86PathIsAbsolute(const char *path)
{
    return (xf86pathIsAbsolute(path) != 0);
}

Bool
xf86PathIsSafe(const char *path)
{
    return (xf86pathIsSafe(path) != 0);
}

