📄 xmlconfig.c
字号:
/* * XML DRI client-side driver configuration * Copyright (C) 2003 Felix Kuehling * * 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 * FELIX KUEHLING, OR ANY OTHER CONTRIBUTORS 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. * *//** * \file xmlconfig.c * \brief Driver-independent client-side part of the XML configuration * \author Felix Kuehling */#include "glheader.h"#include <string.h>#include <assert.h>#include <expat.h>#include <fcntl.h>#include <unistd.h>#include <errno.h>#include "imports.h"#include "dri_util.h"#include "xmlconfig.h"/* * OS dependent ways of getting the name of the running program */#if (defined(__unix__) || defined(unix)) && !defined(USG)#include <sys/param.h>#endif#undef GET_PROGRAM_NAME#if (defined(__GNU_LIBRARY__) || defined(__GLIBC__)) && !defined(__UCLIBC__)# if !defined(__GLIBC__) || (__GLIBC__ < 2)/* These aren't declared in any libc5 header */extern char *program_invocation_name, *program_invocation_short_name;# endif# define GET_PROGRAM_NAME() program_invocation_short_name#elif defined(__FreeBSD__) && (__FreeBSD__ >= 2)# include <osreldate.h># if (__FreeBSD_version >= 440000)# include <stdlib.h># define GET_PROGRAM_NAME() getprogname()# endif#elif defined(__NetBSD__) && defined(__NetBSD_Version) && (__NetBSD_Version >= 106000100)# include <stdlib.h># define GET_PROGRAM_NAME() getprogname()#elif defined(__sun)/* Solaris has getexecname() which returns the full path - return just the basename to match BSD getprogname() */# include <stdlib.h># include <libgen.h># define GET_PROGRAM_NAME() basename(getexecname())#endif#if !defined(GET_PROGRAM_NAME)# if defined(OpenBSD) || defined(NetBSD) || defined(__UCLIBC__)/* This is a hack. It's said to work on OpenBSD, NetBSD and GNU. * Rogelio M.Serrano Jr. reported it's also working with UCLIBC. It's * used as a last resort, if there is no documented facility available. */static const char *__getProgramName () { extern const char *__progname; char * arg = strrchr(__progname, '/'); if (arg) return arg+1; else return __progname;}# define GET_PROGRAM_NAME() __getProgramName()# else# define GET_PROGRAM_NAME() ""# warning "Per application configuration won't work with your OS version."# endif#endif/** \brief Find an option in an option cache with the name as key */static GLuint findOption (const driOptionCache *cache, const char *name) { GLuint len = strlen (name); GLuint size = 1 << cache->tableSize, mask = size - 1; GLuint hash = 0; GLuint i, shift; /* compute a hash from the variable length name */ for (i = 0, shift = 0; i < len; ++i, shift = (shift+8) & 31) hash += (GLuint)name[i] << shift; hash *= hash; hash = (hash >> (16-cache->tableSize/2)) & mask; /* this is just the starting point of the linear search for the option */ for (i = 0; i < size; ++i, hash = (hash+1) & mask) { /* if we hit an empty entry then the option is not defined (yet) */ if (cache->info[hash].name == 0) break; else if (!strcmp (name, cache->info[hash].name)) break; } /* this assertion fails if the hash table is full */ assert (i < size); return hash;}/** \brief Count the real number of options in an option cache */static GLuint countOptions (const driOptionCache *cache) { GLuint size = 1 << cache->tableSize; GLuint i, count = 0; for (i = 0; i < size; ++i) if (cache->info[i].name) count++; return count;}/** \brief Like strdup but using MALLOC and with error checking. */#define XSTRDUP(dest,source) do { \ GLuint len = strlen (source); \ if (!(dest = MALLOC (len+1))) { \ fprintf (stderr, "%s: %d: out of memory.\n", __FILE__, __LINE__); \ abort(); \ } \ memcpy (dest, source, len+1); \} while (0)static int compare (const void *a, const void *b) { return strcmp (*(char *const*)a, *(char *const*)b);}/** \brief Binary search in a string array. */static GLuint bsearchStr (const XML_Char *name, const XML_Char *elems[], GLuint count) { const XML_Char **found; found = bsearch (&name, elems, count, sizeof (XML_Char *), compare); if (found) return found - elems; else return count;}/** \brief Locale-independent integer parser. * * Works similar to strtol. Leading space is NOT skipped. The input * number may have an optional sign. Radix is specified by base. If * base is 0 then decimal is assumed unless the input number is * prefixed by 0x or 0X for hexadecimal or 0 for octal. After * returning tail points to the first character that is not part of * the integer number. If no number was found then tail points to the * start of the input string. */static GLint strToI (const XML_Char *string, const XML_Char **tail, int base) { GLint radix = base == 0 ? 10 : base; GLint result = 0; GLint sign = 1; GLboolean numberFound = GL_FALSE; const XML_Char *start = string; assert (radix >= 2 && radix <= 36); if (*string == '-') { sign = -1; string++; } else if (*string == '+') string++; if (base == 0 && *string == '0') { numberFound = GL_TRUE; if (*(string+1) == 'x' || *(string+1) == 'X') { radix = 16; string += 2; } else { radix = 8; string++; } } do { GLint digit = -1; if (radix <= 10) { if (*string >= '0' && *string < '0' + radix) digit = *string - '0'; } else { if (*string >= '0' && *string <= '9') digit = *string - '0'; else if (*string >= 'a' && *string < 'a' + radix - 10) digit = *string - 'a' + 10; else if (*string >= 'A' && *string < 'A' + radix - 10) digit = *string - 'A' + 10; } if (digit != -1) { numberFound = GL_TRUE; result = radix*result + digit; string++; } else break; } while (GL_TRUE); *tail = numberFound ? string : start; return sign * result;}/** \brief Locale-independent floating-point parser. * * Works similar to strtod. Leading space is NOT skipped. The input * number may have an optional sign. '.' is interpreted as decimal * point and may occor at most once. Optionally the number may end in * [eE]<exponent>, where <exponent> is an integer as recognized by * strToI. In that case the result is number * 10^exponent. After * returning tail points to the first character that is not part of * the floating point number. If no number was found then tail points * to the start of the input string. * * Uses two passes for maximum accuracy. */static GLfloat strToF (const XML_Char *string, const XML_Char **tail) { GLint nDigits = 0, pointPos, exponent; GLfloat sign = 1.0f, result = 0.0f, scale; const XML_Char *start = string, *numStart; /* sign */ if (*string == '-') { sign = -1.0f; string++; } else if (*string == '+') string++; /* first pass: determine position of decimal point, number of * digits, exponent and the end of the number. */ numStart = string; while (*string >= '0' && *string <= '9') { string++; nDigits++; } pointPos = nDigits; if (*string == '.') { string++; while (*string >= '0' && *string <= '9') { string++; nDigits++; } } if (nDigits == 0) { /* no digits, no number */ *tail = start; return 0.0f; } *tail = string; if (*string == 'e' || *string == 'E') { const XML_Char *expTail; exponent = strToI (string+1, &expTail, 10); if (expTail == string+1) exponent = 0; else *tail = expTail; } else exponent = 0; string = numStart; /* scale of the first digit */ scale = sign * (GLfloat)pow (10.0, (GLdouble)(pointPos-1 + exponent)); /* second pass: parse digits */ do { if (*string != '.') { assert (*string >= '0' && *string <= '9'); result += scale * (GLfloat)(*string - '0'); scale *= 0.1f; nDigits--; } string++; } while (nDigits > 0); return result;}/** \brief Parse a value of a given type. */static GLboolean parseValue (driOptionValue *v, driOptionType type, const XML_Char *string) { const XML_Char *tail = NULL; /* skip leading white-space */ string += strspn (string, " \f\n\r\t\v"); switch (type) { case DRI_BOOL: if (!strcmp (string, "false")) { v->_bool = GL_FALSE; tail = string + 5; } else if (!strcmp (string, "true")) { v->_bool = GL_TRUE; tail = string + 4; } else return GL_FALSE; break; case DRI_ENUM: /* enum is just a special integer */ case DRI_INT: v->_int = strToI (string, &tail, 0); break; case DRI_FLOAT: v->_float = strToF (string, &tail); break; } if (tail == string) return GL_FALSE; /* empty string (or containing only white-space) */ /* skip trailing white space */ if (*tail) tail += strspn (tail, " \f\n\r\t\v"); if (*tail) return GL_FALSE; /* something left over that is not part of value */ return GL_TRUE;}/** \brief Parse a list of ranges of type info->type. */static GLboolean parseRanges (driOptionInfo *info, const XML_Char *string) { XML_Char *cp, *range; GLuint nRanges, i; driOptionRange *ranges; XSTRDUP (cp, string); /* pass 1: determine the number of ranges (number of commas + 1) */ range = cp; for (nRanges = 1; *range; ++range) if (*range == ',') ++nRanges; if ((ranges = MALLOC (nRanges*sizeof(driOptionRange))) == NULL) { fprintf (stderr, "%s: %d: out of memory.\n", __FILE__, __LINE__);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -