Merge remote-tracking branch 'origin/5.12' into dev

Conflicts:
	src/gui/painting/qdrawhelper.cpp

Change-Id: I4916e07b635e1d3830e9b46ef7914f99bec3098e
This commit is contained in:
Liang Qi 2018-12-04 09:58:43 +01:00
commit 5d5c00c676
181 changed files with 1770 additions and 38058 deletions

View File

@ -306,10 +306,7 @@ Gui, printing, widget options:
-mtdev ............. Enable mtdev support [auto]
-tslib ............. Enable tslib support [auto]
-xcb-xinput ........ Enable XInput2 support [auto]
-xkbcommon-x11 ..... Select xkbcommon used in combination with xcb
[system/qt/no]
-xkbcommon-evdev ... Enable X-less xkbcommon in combination with libinput
[auto]
-xkbcommon ......... Enable key mapping support [auto]
Image formats:
-gif ............... Enable reading support for GIF [auto]

View File

@ -212,7 +212,7 @@
"verifySpec": [ "shared", "use_gold_linker", "compiler-flags", "qmakeargs", "commit" ],
"compile": [ "verifyspec" ],
"detectPkgConfig": [ "cross_compile", "machineTuple" ],
"library": [ "pkg-config" ],
"library": [ "pkg-config", "compiler-flags" ],
"getPkgConfigVariable": [ "pkg-config" ]
},

View File

@ -2,10 +2,15 @@ QT += widgets
requires(qtConfig(filedialog))
HEADERS += mainwindow.h \
previewform.h
previewform.h \
encodingdialog.h
SOURCES += main.cpp \
mainwindow.cpp \
previewform.cpp
previewform.cpp \
encodingdialog.cpp
RESOURCES += codecs.qrc
EXAMPLE_FILES = encodedfiles

View File

@ -0,0 +1,5 @@
<RCC>
<qresource prefix="/" >
<file>images/editcopy.png</file>
</qresource>
</RCC>

View File

@ -0,0 +1,333 @@
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * 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.
** * Neither the name of The Qt Company Ltd nor the names of its
** contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS 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 COPYRIGHT
** OWNER OR 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."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "encodingdialog.h"
#if QT_CONFIG(action)
# include <QAction>
#endif
#include <QDialogButtonBox>
#include <QFormLayout>
#include <QLabel>
#include <QLineEdit>
#include <QVBoxLayout>
#if QT_CONFIG(clipboard)
# include <QGuiApplication>
# include <QClipboard>
#endif
#include <QTextStream>
// Helpers for formatting character sequences
// Format a special character like '\x0a'
template <class Int>
static void formatEscapedNumber(QTextStream &str, Int value, int base,
int width = 0,char prefix = 0)
{
str << '\\';
if (prefix)
str << prefix;
const auto oldPadChar = str.padChar();
const auto oldFieldWidth = str.fieldWidth();
const auto oldFieldAlignment = str.fieldAlignment();
const auto oldIntegerBase = str.integerBase();
str.setPadChar(QLatin1Char('0'));
str.setFieldWidth(width);
str.setFieldAlignment(QTextStream::AlignRight);
str.setIntegerBase(base);
str << value;
str.setIntegerBase(oldIntegerBase);
str.setFieldAlignment(oldFieldAlignment);
str.setFieldWidth(oldFieldWidth);
str.setPadChar(oldPadChar);
}
template <class Int>
static bool formatSpecialCharacter(QTextStream &str, Int value)
{
bool result = true;
switch (value) {
case '\\':
str << "\\\\";
break;
case '\"':
str << "\\\"";
break;
case '\n':
str << "\\n";
break;
default:
result = false;
break;
}
return result;
}
// Format a sequence of characters (QChar, ushort (UTF-16), uint (UTF-32)
// or just char (Latin1, Utf-8)) with the help of traits specifying
// how to obtain the code for checking the printable-ness and how to
// stream out the plain ASCII values.
template <EncodingDialog::Encoding>
struct FormattingTraits
{
};
template <>
struct FormattingTraits<EncodingDialog::Unicode>
{
static ushort code(QChar c) { return c.unicode(); }
static char toAscii(QChar c) { return c.toLatin1(); }
};
template <>
struct FormattingTraits<EncodingDialog::Utf8>
{
static ushort code(char c) { return uchar(c); }
static char toAscii(char c) { return c; }
};
template <>
struct FormattingTraits<EncodingDialog::Utf16>
{
static ushort code(ushort c) { return c; }
static char toAscii(ushort c) { return char(c); }
};
template <>
struct FormattingTraits<EncodingDialog::Utf32>
{
static uint code(uint c) { return c; }
static char toAscii(uint c) { return char(c); }
};
template <>
struct FormattingTraits<EncodingDialog::Latin1>
{
static uchar code(char c) { return uchar(c); }
static char toAscii(char c) { return c; }
};
static bool isHexDigit(char c)
{
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f')
|| (c >= 'A' && c <= 'F');
}
template <EncodingDialog::Encoding encoding, class Iterator>
static void formatStringSequence(QTextStream &str, Iterator i1, Iterator i2,
int escapeIntegerBase, int escapeWidth,
char escapePrefix = 0)
{
str << '"';
bool separateHexEscape = false;
for (; i1 != i2; ++i1) {
const auto code = FormattingTraits<encoding>::code(*i1);
if (code >= 0x80) {
formatEscapedNumber(str, code, escapeIntegerBase, escapeWidth, escapePrefix);
separateHexEscape = escapeIntegerBase == 16 && escapeWidth == 0;
} else {
if (!formatSpecialCharacter(str, code)) {
const char c = FormattingTraits<encoding>::toAscii(*i1);
// For variable width/hex: Terminate the literal to stop digit parsing
// ("\x12" "34...").
if (separateHexEscape && isHexDigit(c))
str << "\" \"";
str << c;
}
separateHexEscape = false;
}
}
str << '"';
}
static QString encodedString(const QString &value, EncodingDialog::Encoding e)
{
QString result;
QTextStream str(&result);
switch (e) {
case EncodingDialog::Unicode:
formatStringSequence<EncodingDialog::Unicode>(str, value.cbegin(), value.cend(),
16, 4, 'u');
break;
case EncodingDialog::Utf8: {
const QByteArray utf8 = value.toUtf8();
str << "u8";
formatStringSequence<EncodingDialog::Utf8>(str, utf8.cbegin(), utf8.cend(),
8, 3);
}
break;
case EncodingDialog::Utf16: {
auto utf16 = value.utf16();
auto utf16End = utf16 + value.size();
str << 'u';
formatStringSequence<EncodingDialog::Utf16>(str, utf16, utf16End,
16, 0, 'x');
}
break;
case EncodingDialog::Utf32: {
auto utf32 = value.toUcs4();
str << 'U';
formatStringSequence<EncodingDialog::Utf32>(str, utf32.cbegin(), utf32.cend(),
16, 0, 'x');
}
break;
case EncodingDialog::Latin1: {
const QByteArray latin1 = value.toLatin1();
formatStringSequence<EncodingDialog::Latin1>(str, latin1.cbegin(), latin1.cend(),
16, 0, 'x');
}
break;
case EncodingDialog::EncodingCount:
break;
}
return result;
}
// Dialog helpers
static const char *encodingLabels[]
{
QT_TRANSLATE_NOOP("EncodingDialog", "Unicode:"),
QT_TRANSLATE_NOOP("EncodingDialog", "UTF-8:"),
QT_TRANSLATE_NOOP("EncodingDialog", "UTF-16:"),
QT_TRANSLATE_NOOP("EncodingDialog", "UTF-32:"),
QT_TRANSLATE_NOOP("EncodingDialog", "Latin1:")
};
static const char *encodingToolTips[]
{
QT_TRANSLATE_NOOP("EncodingDialog", "Unicode points for use with any encoding (C++, Python)"),
QT_TRANSLATE_NOOP("EncodingDialog", "QString::fromUtf8()"),
QT_TRANSLATE_NOOP("EncodingDialog", "QStringViewLiteral(), wchar_t on Windows"),
QT_TRANSLATE_NOOP("EncodingDialog", "wchar_t on Unix (Ucs4)"),
QT_TRANSLATE_NOOP("EncodingDialog", "QLatin1String")
};
// A read-only line edit with a tool button to copy the contents
class DisplayLineEdit : public QLineEdit
{
Q_OBJECT
public:
explicit DisplayLineEdit(const QIcon &icon, QWidget *parent = nullptr);
public slots:
void copyAll();
};
DisplayLineEdit::DisplayLineEdit(const QIcon &icon, QWidget *parent) :
QLineEdit(parent)
{
setReadOnly(true);
#if QT_CONFIG(clipboard) && QT_CONFIG(action)
auto copyAction = addAction(icon, QLineEdit::TrailingPosition);
connect(copyAction, &QAction::triggered, this, &DisplayLineEdit::copyAll);
#endif
}
void DisplayLineEdit::copyAll()
{
#if QT_CONFIG(clipboard)
QGuiApplication::clipboard()->setText(text());
#endif
}
static void addFormLayoutRow(QFormLayout *formLayout, const QString &text,
QWidget *w, const QString &toolTip)
{
auto label = new QLabel(text);
label->setToolTip(toolTip);
w->setToolTip(toolTip);
label->setBuddy(w);
formLayout->addRow(label, w);
}
EncodingDialog::EncodingDialog(QWidget *parent) :
QDialog(parent)
{
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
setWindowTitle(tr("Encodings"));
auto formLayout = new QFormLayout;
auto sourceLineEdit = new QLineEdit(this);
sourceLineEdit->setClearButtonEnabled(true);
connect(sourceLineEdit, &QLineEdit::textChanged, this, &EncodingDialog::textChanged);
addFormLayoutRow(formLayout, tr("&Source:"), sourceLineEdit, tr("Enter text"));
const auto copyIcon = QIcon::fromTheme(QLatin1String("edit-copy"),
QIcon(QLatin1String(":/images/editcopy")));
for (int i = 0; i < EncodingCount; ++i) {
m_lineEdits[i] = new DisplayLineEdit(copyIcon, this);
addFormLayoutRow(formLayout, tr(encodingLabels[i]),
m_lineEdits[i], tr(encodingToolTips[i]));
}
auto mainLayout = new QVBoxLayout(this);
mainLayout->addLayout(formLayout);
auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Close);
connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
mainLayout->addWidget(buttonBox);
}
void EncodingDialog::textChanged(const QString &t)
{
if (t.isEmpty()) {
for (auto lineEdit : m_lineEdits)
lineEdit->clear();
} else {
for (int i = 0; i < EncodingCount; ++i)
m_lineEdits[i]->setText(encodedString(t, static_cast<Encoding>(i)));
}
}
#include "encodingdialog.moc"

View File

@ -0,0 +1,73 @@
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * 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.
** * Neither the name of The Qt Company Ltd nor the names of its
** contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS 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 COPYRIGHT
** OWNER OR 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."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef ENCODINGDIALOG_H
#define ENCODINGDIALOG_H
#include <QDialog>
QT_FORWARD_DECLARE_CLASS(QLineEdit)
class EncodingDialog : public QDialog
{
Q_OBJECT
public:
explicit EncodingDialog(QWidget *parent = nullptr);
enum Encoding { Unicode, Utf8, Utf16, Utf32, Latin1, EncodingCount };
private slots:
void textChanged(const QString &t);
private:
QLineEdit *m_lineEdits[EncodingCount];
};
#endif // ENCODINGDIALOG_H

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -51,6 +51,7 @@
#include <QtWidgets>
#include "mainwindow.h"
#include "encodingdialog.h"
#include "previewform.h"
MainWindow::MainWindow()
@ -188,9 +189,27 @@ void MainWindow::createMenus()
QAction *exitAct = fileMenu->addAction(tr("E&xit"), this, &QWidget::close);
exitAct->setShortcuts(QKeySequence::Quit);
auto toolMenu = menuBar()->addMenu(tr("&Tools"));
auto encodingAction = toolMenu->addAction(tr("Encodings"), this, &MainWindow::encodingDialog);
encodingAction->setShortcut(Qt::CTRL + Qt::Key_E);
encodingAction->setToolTip(tr("Shows a dialog allowing to convert to common encoding in programming languages."));
menuBar()->addSeparator();
QMenu *helpMenu = menuBar()->addMenu(tr("&Help"));
helpMenu->addAction(tr("&About"), this, &MainWindow::about);
helpMenu->addAction(tr("About &Qt"), qApp, &QApplication::aboutQt);
}
void MainWindow::encodingDialog()
{
if (!m_encodingDialog) {
m_encodingDialog = new EncodingDialog(this);
const QRect screenGeometry = QApplication::desktop()->screenGeometry(this);
m_encodingDialog->setMinimumWidth(screenGeometry.width() / 4);
}
m_encodingDialog->show();
m_encodingDialog->raise();
}

View File

@ -59,6 +59,8 @@ class QAction;
class QTextCodec;
class QPlainTextEdit;
QT_END_NAMESPACE
class EncodingDialog;
class PreviewForm;
class MainWindow : public QMainWindow
@ -73,6 +75,7 @@ private slots:
void save();
void about();
void aboutToShowSaveAsMenu();
void encodingDialog();
private:
void findCodecs();
@ -82,6 +85,7 @@ private:
QPlainTextEdit *textEdit;
PreviewForm *previewForm;
QList<QTextCodec *> codecs;
EncodingDialog *m_encodingDialog = nullptr;
};
#endif

View File

@ -87,6 +87,3 @@ QMAKE_LIBS_OPENGL_ES2 = -lGLESv2
!exists($$NDK_ROOT): error("You need to set the ANDROID_NDK_ROOT environment variable to point to your Android NDK.")
load(qt_config)
QMAKE_DEFAULT_LIBDIRS = $$QMAKE_LIBDIR
QMAKE_DEFAULT_INCDIRS = $$QMAKE_INCDIR

View File

@ -106,7 +106,7 @@ QMAKE_LIBS_OPENGL_ES2_DEBUG = gdi32.lib user32.lib
QMAKE_LIBS_COMPAT = advapi32.lib shell32.lib comdlg32.lib user32.lib gdi32.lib ws2_32.lib
QMAKE_LIBS_QT_ENTRY = -lqtmain
QMAKE_IDL = midl /NOLOGO
QMAKE_IDL = midl
QMAKE_LIB = lib /NOLOGO
QMAKE_RC = rc /NOLOGO

View File

@ -65,7 +65,8 @@ for (MODULE_UNDER_TEST, CMAKE_QT_MODULES_UNDER_TEST) {
CMAKE_MODULES_UNDER_TEST = $$join(CMAKE_MODULES_UNDER_TEST, ;)
check.commands = \
$(MKDIR) $$BUILD_DIR && $$QMAKE_CD $$BUILD_DIR && \
$$sprintf($$QMAKE_MKDIR_CMD, $$BUILD_DIR) $$escape_expand(\\n\\t) \
$$QMAKE_CD $$BUILD_DIR && \
cmake $$CMAKE_TEST_LOCATION $$CMAKE_GENERATOR \
-DCMAKE_C_COMPILER=$$QMAKE_CC \
-DCMAKE_CXX_COMPILER=$$QMAKE_CXX \

View File

@ -146,7 +146,7 @@ inspect_binary() {
echo "found namespaced class names, updating class entries..."
fi
classes=$(otool -o "$target" | grep class_ro_t)
classes=$(otool -o -v "$target" | grep class_ro_t)
while read -a class; do
address="$(sanitize_address ${class[1]})"

View File

@ -9,7 +9,6 @@ for(ever) {
error("Library '$$name' is not defined.")
!contains(use, nolink) {
QMAKE_LIBDIR += $$eval(QMAKE_LIBDIR_$$nu)
debug: \
LIBS$${suffix} += $$eval(QMAKE_LIBS_$${nu}_DEBUG) $$eval(QMAKE_LIBS_$$nu)
else: \

View File

@ -365,9 +365,13 @@ defineTest(qtConfTest_linkerSupportsFlag) {
}
defineReplace(qtConfFindInPathList) {
# This nesting is consistent with Apple ld -search_paths_first,
# and presumably with GNU ld (no actual documentation found).
for (dir, 2) {
exists("$$dir/$${1}"): \
return("$$dir/$${1}")
for (file, 1) {
exists("$$dir/$$file"): \
return("$$dir/$$file")
}
}
return()
}
@ -488,6 +492,110 @@ defineTest(qtConfSetupLibraries) {
}
}
# libs-var, libs, in-paths, out-paths-var
defineTest(qtConfResolveLibs) {
ret = true
paths = $$3
out =
copy = false
for (l, 2) {
$$copy {
copy = false
out += $$l
} else: equals(l, "-s") {
# em++ flag to link libraries from emscripten-ports; passed on literally.
copy = true
out += $$l
} else: contains(l, "^-L.*") {
lp = $$replace(l, "^-L", )
!exists($$lp/.) {
qtLog("Library path $$val_escape(lp) is invalid.")
ret = false
} else {
paths += $$lp
}
} else: contains(l, "^-l.*") {
lib = $$replace(l, "^-l", )
lcan =
unix {
# Under UNIX, we look for actual shared libraries, in addition
# to static ones.
lcan += \
$${QMAKE_PREFIX_SHLIB}$${lib}.$${QMAKE_EXTENSION_SHLIB} \
$${QMAKE_PREFIX_STATICLIB}$${lib}.$${QMAKE_EXTENSION_STATICLIB}
} else {
# Under Windows, we look only for static libraries, as even for DLLs
# one actually links against a static import library.
mingw {
lcan += \
# MinGW supports UNIX-style library naming in addition to
# the MSVC style.
lib$${lib}.dll.a lib$${lib}.a \
# Fun fact: prefix-less libraries are also supported.
$${lib}.dll.a $${lib}.a
}
lcan += $${lib}.lib
}
l = $$qtConfFindInPathList($$lcan, $$paths $$EXTRA_LIBDIR $$QMAKE_DEFAULT_LIBDIRS)
isEmpty(l) {
qtLog("None of [$$val_escape(lcan)] found in [$$val_escape(paths)] and global paths.")
ret = false
} else {
out += $$l
}
} else {
out += $$l
}
}
$$1 = $$out
export($$1)
!isEmpty(4) {
$$4 = $$paths
export($$4)
}
return($$ret)
}
# source-var
defineTest(qtConfResolveAllLibs) {
ret = true
!qtConfResolveLibs($${1}.libs, $$eval($${1}.libs), , $${1}.libdirs): \
ret = false
for (b, $${1}.builds._KEYS_): \
!qtConfResolveLibs($${1}.builds.$${b}, $$eval($${1}.builds.$${b}), $$eval($${1}.libdirs), ): \
ret = false
return($$ret)
}
# libs-var, in-paths, libs
defineTest(qtConfResolvePathLibs) {
ret = true
for (libdir, 2) {
!exists($$libdir/.) {
qtLog("Library path $$val_escape(libdir) is invalid.")
ret = false
}
}
!qtConfResolveLibs($$1, $$3, $$2): \
ret = false
return($$ret)
}
# includes-var, includes
defineTest(qtConfResolvePathIncs) {
ret = true
for (incdir, 2) {
!exists($$incdir/.) {
qtLog("Include path $$val_escape(incdir) is invalid.")
ret = false
}
}
2 -= $$QMAKE_DEFAULT_INCDIRS
$$1 = $$2
export($$1)
return($$ret)
}
# the library is specified inline in a 'libs' field.
# overrides from the command line are accepted.
defineTest(qtConfLibrary_inline) {
@ -517,7 +625,6 @@ defineTest(qtConfLibrary_inline) {
vars += $$eval(config.commandline.rev_assignments.$${iv})
defined(config.input.$${iv}, var) {
eval($${1}.builds.$${b} = $$eval(config.input.$${iv}))
export($${1}.builds.$${b})
$${1}.builds._KEYS_ *= $${b}
any = true
} else {
@ -532,35 +639,30 @@ defineTest(qtConfLibrary_inline) {
export($${1}.builds._KEYS_)
# we also reset the generic libs, to avoid surprises.
$${1}.libs =
export($${1}.libs)
}
# direct libs. overwrites inline libs.
defined(config.input.$${input}.libs, var) {
defined(config.input.$${input}.libs, var): \
eval($${1}.libs = $$eval(config.input.$${input}.libs))
export($${1}.libs)
}
includes = $$eval(config.input.$${input}.incdir)
# prefix. prepends to (possibly overwritten) inline libs.
prefix = $$eval(config.input.$${input}.prefix)
!isEmpty(prefix) {
$${1}.includedir = $$prefix/include
export($${1}.includedir)
includes += $$prefix/include
$${1}.libs = -L$$prefix/lib $$eval($${1}.libs)
export($${1}.libs)
}
incdir = $$eval(config.input.$${input}.incdir)
!isEmpty(incdir) {
$${1}.includedir = $$incdir
export($${1}.includedir)
}
libdir = $$eval(config.input.$${input}.libdir)
!isEmpty(libdir) {
!isEmpty(libdir): \
$${1}.libs = -L$$libdir $$eval($${1}.libs)
export($${1}.libs)
}
!qtConfResolveAllLibs($$1): \
return(false)
!qtConfResolvePathIncs($${1}.includedir, $$includes): \
return(false)
return(true)
}
@ -572,17 +674,13 @@ defineTest(qtConfLibrary_makeSpec) {
isEmpty(spec): \
error("makeSpec source in library '$$eval($${1}.library)' does not specify 'spec'.")
$${1}.includedir = $$eval(QMAKE_INCDIR_$$spec)
export($${1}.includedir)
$${1}.libs =
for (l, QMAKE_LIBDIR_$$spec): \
$${1}.libs += -L$$l
$${1}.libs += $$eval(QMAKE_LIBS_$$spec)
export($${1}.libs)
!qtConfResolvePathLibs($${1}.libs, $$eval(QMAKE_LIBDIR_$$spec), $$eval(QMAKE_LIBS_$$spec)): \
return(false)
# the library definition is always in scope, so no point in exporting it.
$${1}.export = false
export($${1}.export)
!qtConfResolvePathIncs($${1}.includedir, $$eval(QMAKE_INCDIR_$$spec)): \
return(false)
# note that the object is re-exported, because we resolve the libraries.
return(true)
}
@ -602,13 +700,15 @@ defineTest(qtConfLibrary_pkgConfig) {
}
qtRunLoggedCommand("$$pkg_config --modversion $$args", version)|return(false)
qtRunLoggedCommand("$$pkg_config --libs-only-L $$args", libpaths)|return(false)
qtRunLoggedCommand("$$pkg_config --libs-only-l $$args", libs)|return(false)
version ~= s/[^0-9.].*$//
$${1}.version = $$first(version)
export($${1}.version)
eval($${1}.libs = $$libpaths $$libs)
export($${1}.libs)
qtRunLoggedCommand("$$pkg_config --libs-only-L $$args", libpaths)|return(false)
qtRunLoggedCommand("$$pkg_config --libs-only-l $$args", libs)|return(false)
eval(libs = $$libpaths $$libs)
!qtConfResolveLibs($${1}.libs, $$libs): \
return(false)
qtRunLoggedCommand("$$pkg_config --cflags $$args", $${1}.cflags)|return(false)
# Split CFLAGS into stuff that goes into DEFINES, INCLUDEPATH, and other stuff.
@ -633,10 +733,11 @@ defineTest(qtConfLibrary_pkgConfig) {
}
!isEmpty(ignored): \
qtLog("Note: Dropped compiler flags '$$ignored'.")
!qtConfResolvePathIncs($${1}.includedir, $$includes): \
return(false)
$${1}.defines = $$defines
export($${1}.defines)
$${1}.includedir = $$includes
export($${1}.includedir)
return(true)
}

View File

@ -34,19 +34,30 @@ THE_TARGET = $$qt5LibraryTarget($$TARGET)
MODULE_PRI = $$MODULE_QMAKE_OUTDIR/mkspecs/modules/qt_ext_$${MODULE}.pri
ucmodule = $$upper($$MODULE)
win32|CONFIG(static, static|shared) {
prefix = $$QMAKE_PREFIX_STATICLIB
suffix = $$QMAKE_EXTENSION_STATICLIB
} else {
prefix = $$QMAKE_PREFIX_SHLIB
suffix = $$QMAKE_EXTENSION_SHLIB
}
MODULE_PRI_CONT = \
"QMAKE_INCDIR_$${ucmodule} = $$val_escape(MODULE_INCLUDEPATH)" \
"QMAKE_DEFINES_$${ucmodule} = $$val_escape(MODULE_DEFINES)"
debug_and_release {
win32: MODULE_DEBUG_LIBS = -L$$DESTDIR -l$${TARGET}d
darwin: MODULE_DEBUG_LIBS = -L$$DESTDIR -l$${TARGET}_debug
MODULE_RELEASE_LIBS = -L$$DESTDIR -l$$TARGET
win32: \
MODULE_DEBUG_LIBS = $$DESTDIR/$$prefix$${TARGET}d.$$suffix
else: darwin: \
MODULE_DEBUG_LIBS = $$DESTDIR/$$prefix$${TARGET}_debug.$$suffix
else: \
error("'$$QMAKE_PLATFORM' does not do debug_and_release.")
MODULE_RELEASE_LIBS = $$DESTDIR/$$prefix$${TARGET}.$$suffix
MODULE_PRI_CONT += \
"QMAKE_LIBS_$${ucmodule} =" \ # Needed for the module to be recognized.
"QMAKE_LIBS_$${ucmodule}_DEBUG = $$val_escape(MODULE_DEBUG_LIBS)" \
"QMAKE_LIBS_$${ucmodule}_RELEASE = $$val_escape(MODULE_RELEASE_LIBS)"
} else {
MODULE_LIBS = -L$$DESTDIR -l$$THE_TARGET
MODULE_LIBS = $$DESTDIR/$$prefix$${THE_TARGET}.$$suffix
MODULE_PRI_CONT += \
"QMAKE_LIBS_$${ucmodule} = $$val_escape(MODULE_LIBS)"
}

View File

@ -128,8 +128,8 @@ isEmpty($${target_prefix}.INCDIRS) {
# paths, so it can't just be used in place of the above code).
# What's more, -print-search-dirs can't be used on clang on Apple because it
# won't print all the library paths (only the clang-internal ones).
output = $$system("$$cmd_prefix $$QMAKE_CXX -print-search-dirs", lines, ec)
!equals(ec, 0): qtCompilerErrror($$QMAKE_CXX, $$output)
output = $$system("$$cmd_prefix $$QMAKE_LINK $$QMAKE_LFLAGS -print-search-dirs", lines, ec)
!equals(ec, 0): qtCompilerErrror($$QMAKE_LINK, $$output)
for (line, output) {
contains(line, "^libraries: .*") {

View File

@ -41,14 +41,14 @@ contains(TEMPLATE, .*app) {
appjs.name = application qtloader.js
appjs.output = $$DESTDIR/qtloader.js
appjs.commands = $$QMAKE_COPY $$WASM_PLUGIN_PATH/qtloader.js $$DESTDIR
appjs.commands = $$QMAKE_COPY $$shell_path($$WASM_PLUGIN_PATH/qtloader.js) $$shell_path($$DESTDIR)
appjs.input = $$WASM_PLUGIN_PATH/qtloader.js
appjs.depends = $$appjs.input
QMAKE_EXTRA_COMPILERS += appjs
appsvg.name = application qtlogo.svg
appsvg.output = $$DESTDIR/qtlogo.svg
appsvg.commands = $$QMAKE_COPY $$WASM_PLUGIN_PATH/qtlogo.svg $$DESTDIR
appsvg.commands = $$QMAKE_COPY $$shell_path($$WASM_PLUGIN_PATH/qtlogo.svg) $$shell_path($$DESTDIR)
appsvg.input = $$WASM_PLUGIN_PATH/qtlogo.svg
appsvg.depends = $$appsvg.input
QMAKE_EXTRA_COMPILERS += appsvg

View File

@ -2325,6 +2325,7 @@ MakefileGenerator::writeHeader(QTextStream &t)
if (ofile.lastIndexOf(Option::dir_sep) != -1)
ofile.remove(0, ofile.lastIndexOf(Option::dir_sep) +1);
t << "MAKEFILE = " << escapeFilePath(ofile) << endl << endl;
t << "EQ = =\n\n";
}
QList<MakefileGenerator::SubTarget*>
@ -2869,6 +2870,7 @@ MakefileGenerator::escapeDependencyPath(const QString &path) const
static const QRegExp criticalChars(QStringLiteral("([\t #])"));
#endif
ret.replace(criticalChars, QStringLiteral("\\\\1"));
ret.replace(QLatin1Char('='), QStringLiteral("$(EQ)"));
debug_msg(2, "escapeDependencyPath: %s -> %s", path.toLatin1().constData(), ret.toLatin1().constData());
}
return ret;

View File

@ -109,10 +109,10 @@ int QMakeVfs::idForFileName(const QString &fn, VfsFlags flags)
return id;
}
#endif
if (!(flags & VfsAccessedOnly)) {
#ifdef PROPARSER_THREAD_SAFE
QMutexLocker locker(&s_mutex);
QMutexLocker locker(&s_mutex);
#endif
if (!(flags & VfsAccessedOnly)) {
int &id = s_fileIdMap[fn];
if (!id) {
id = ++s_fileIdCounter;

View File

@ -1,14 +0,0 @@
include(xkbcommon.pri)
# Build xkbcommon-x11 support library, it depends on -lxcb and -lxcb-xkb, linking is done
# in xcb-plugin.pro (linked to system libraries or if Qt was configured with -qt-xcb then
# linked to -lxcb-static).
INCLUDEPATH += $$PWD/xkbcommon/src/x11
# Need to rename several files, qmake has problems processing a project when
# sub-directories contain files with an equal names.
SOURCES += \
$$PWD/xkbcommon/src/x11/util.c \
$$PWD/xkbcommon/src/x11/x11-keymap.c \ # renamed: keymap.c -> x11-keymap.c
$$PWD/xkbcommon/src/x11/x11-state.c # renamed: state.c -> x11-state.c

View File

@ -1,60 +0,0 @@
# Requires GNU C extensions
CONFIG -= strict_c
INCLUDEPATH += $$PWD/xkbcommon \
$$PWD/xkbcommon/xkbcommon \
$$PWD/xkbcommon/src \
$$PWD/xkbcommon/src/xkbcomp
include($$shadowed($$PWD/../gui/qtgui-config.pri))
# Unused (but needs to be set to something) - we don't use APIs that read xkb
# config files from file system. We use APIs that fetch the necessary keymap
# details directly from X server.
DEFINES += DFLT_XKB_CONFIG_ROOT='\\"/usr/share/X11/xkb\\"'
# Unused (but needs to be set to something) - After QTBUG-42181, this needs to
# be become a configure switch.
DEFINES += XLOCALEDIR='\\"/usr/share/X11/locale/\\"'
### RMLVO names can be overwritten with environmental variables (see libxkbcommon documentation)
DEFINES += DEFAULT_XKB_RULES='\\"evdev\\"'
DEFINES += DEFAULT_XKB_MODEL='\\"pc105\\"'
DEFINES += DEFAULT_XKB_LAYOUT='\\"us\\"'
# Need to rename several files, qmake has problems processing a project when
# sub-directories contain files with an equal names.
SOURCES += \
$$PWD/xkbcommon/src/keysym-utf.c \
$$PWD/xkbcommon/src/keymap.c \
$$PWD/xkbcommon/src/keymap-priv.c \
$$PWD/xkbcommon/src/utils.c \
$$PWD/xkbcommon/src/atom.c \
$$PWD/xkbcommon/src/compose/paths.c \
$$PWD/xkbcommon/src/compose/parser.c \
$$PWD/xkbcommon/src/compose/compose-state.c \ # renamed: keymap.c -> compose-state.c
$$PWD/xkbcommon/src/compose/table.c \
$$PWD/xkbcommon/src/xkbcomp/xkbcomp-keymap.c \ # renamed: keymap.c -> xkbcomp-keymap.c
$$PWD/xkbcommon/src/xkbcomp/xkbcomp.c \
$$PWD/xkbcommon/src/xkbcomp/keymap-dump.c \
$$PWD/xkbcommon/src/xkbcomp/rules.c \
$$PWD/xkbcommon/src/xkbcomp/expr.c \
$$PWD/xkbcommon/src/xkbcomp/action.c \
$$PWD/xkbcommon/src/xkbcomp/compat.c \
$$PWD/xkbcommon/src/xkbcomp/types.c \
$$PWD/xkbcommon/src/xkbcomp/scanner.c \
$$PWD/xkbcommon/src/xkbcomp/xkbcomp-parser.c \ # renamed: parser.c -> xkbcomp-parser.c
$$PWD/xkbcommon/src/xkbcomp/ast-build.c \
$$PWD/xkbcommon/src/xkbcomp/keywords.c \
$$PWD/xkbcommon/src/xkbcomp/keycodes.c \
$$PWD/xkbcommon/src/xkbcomp/vmod.c \
$$PWD/xkbcommon/src/xkbcomp/include.c \
$$PWD/xkbcommon/src/xkbcomp/symbols.c \
$$PWD/xkbcommon/src/context-priv.c \
$$PWD/xkbcommon/src/text.c \
$$PWD/xkbcommon/src/context.c \
$$PWD/xkbcommon/src/keysym.c \
$$PWD/xkbcommon/src/utf8.c \
$$PWD/xkbcommon/src/state.c
TR_EXCLUDE += $$PWD/*

View File

@ -1,215 +0,0 @@
The following is a list of all copyright notices and license statements which
appear in the xkbcommon source tree.
If making new contributions, the first form (i.e. Daniel Stone, Ran Benita,
etc) is vastly preferred.
All licenses are derivative of the MIT/X11 license, mostly identical other
than no-endorsement clauses (e.g. paragraph 4 of The Open Group's license).
These statements are split into two sections: one for the code compiled and
distributed as part of the libxkbcommon shared library and the code
component of all tests (i.e. everything under src/ and xkbcommon/, plus the
.c and .h files under test/), and another for the test data under test/data,
which is distributed with the xkbcommon source tarball, but not installed to
the system.
BEGINNING OF SOFTWARE COPYRIGHT/LICENSE STATEMENTS:
-------------------------------------------------------------------------------
Copyright © 2009-2012, 2016 Daniel Stone
Copyright © 2012 Ran Benita <ran234@gmail.com>
Copyright © 2010, 2012 Intel Corporation
Copyright © 2008, 2009 Dan Nicholson
Copyright © 2010 Francisco Jerez <currojerez@riseup.net>
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 (including the next
paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
-------------------------------------------------------------------------------
Copyright 1985, 1987, 1988, 1990, 1998 The Open Group
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
AUTHORS 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 names of the authors or their
institutions 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 authors.
-------------------------------------------------------------------------------
Copyright (c) 1993, 1994, 1995, 1996 by Silicon Graphics Computer Systems, Inc.
Permission to use, copy, modify, and distribute this
software and its documentation for any purpose and without
fee is hereby granted, provided that the above copyright
notice appear in all copies and that both that copyright
notice and this permission notice appear in supporting
documentation, and that the name of Silicon Graphics not be
used in advertising or publicity pertaining to distribution
of the software without specific prior written permission.
Silicon Graphics makes no representation about the suitability
of this software for any purpose. It is provided "as is"
without any express or implied warranty.
SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
THE USE OR PERFORMANCE OF THIS SOFTWARE.
-------------------------------------------------------------------------------
Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the name of Digital not be
used in advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
-------------------------------------------------------------------------------
Copyright (C) 2011 Joseph Adams <joeyadams3.14159@gmail.com>
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
AUTHORS OR COPYRIGHT HOLDERS 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.
-------------------------------------------------------------------------------
END OF SOFTWARE COPYRIGHT/LICENSE STATEMENTS
BEGINNING OF LICENSE STATEMENTS FOR UNDISTRIBUTED DATA FILES IN test/data,
derived from xkeyboard-config:
-------------------------------------------------------------------------------
Copyright 1996 by Joseph Moss
Copyright (C) 2002-2007 Free Software Foundation, Inc.
Copyright (C) Dmitry Golubev <lastguru@mail.ru>, 2003-2004
Copyright (C) 2004, Gregory Mokhin <mokhin@bog.msu.ru>
Copyright (C) 2006 Erdal Ronahî
Permission to use, copy, modify, distribute, and sell this software and its
documentation for any purpose is hereby granted without fee, provided that
the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation, and that the name of the copyright holder(s) not be used in
advertising or publicity pertaining to distribution of the software without
specific, written prior permission. The copyright holder(s) makes no
representations about the suitability of this software for any purpose. It
is provided "as is" without express or implied warranty.
THE COPYRIGHT HOLDER(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
-------------------------------------------------------------------------------
Copyright 1992 by Oki Technosystems Laboratory, Inc.
Copyright 1992 by Fuji Xerox Co., Ltd.
Permission to use, copy, modify, distribute, and sell this software
and its documentation for any purpose is hereby granted without fee,
provided that the above copyright notice appear in all copies and
that both that copyright notice and this permission notice appear
in supporting documentation, and that the name of Oki Technosystems
Laboratory and Fuji Xerox not be used in advertising or publicity
pertaining to distribution of the software without specific, written
prior permission.
Oki Technosystems Laboratory and Fuji Xerox make no representations
about the suitability of this software for any purpose. It is provided
"as is" without express or implied warranty.
OKI TECHNOSYSTEMS LABORATORY AND FUJI XEROX DISCLAIM ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL OKI TECHNOSYSTEMS
LABORATORY AND FUJI XEROX BE LIABLE FOR ANY SPECIAL, INDIRECT OR
CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
OR PERFORMANCE OF THIS SOFTWARE.

View File

@ -1,404 +0,0 @@
libxkbcommon 0.8.2 - 2018-08-05
==================
- Fix various problems found with fuzzing (see commit messages for
more details):
- Fix a few NULL-dereferences, out-of-bounds access and undefined behavior
in the XKB text format parser.
libxkbcommon 0.8.1 - 2018-08-03
==================
- Fix various problems found in the meson build (see commit messages for more
details):
- Fix compilation on Darwin.
- Fix compilation of the x11 tests and demos when XCB is installed in a
non-standard location.
- Fix xkbcommon-x11.pc missing the Requires specification.
- Fix various problems found with fuzzing and Coverity (see commit messages for
more details):
- Fix stack overflow in the XKB text format parser when evaluating boolean
negation.
- Fix NULL-dereferences in the XKB text format parser when some unsupported
tokens appear (the tokens are still parsed for backward compatibility).
- Fix NULL-dereference in the XKB text format parser when parsing an
xkb_geometry section.
- Fix an infinite loop in the Compose text format parser on some inputs.
- Fix an invalid free() when using multiple keysyms.
- Replace the Unicode characters for the leftanglebracket and rightanglebracket
keysyms from the deprecated LEFT/RIGHT-POINTING ANGLE BRACKET to
MATHEMATICAL LEFT/RIGHT ANGLE BRACKET.
- Reject out-of-range Unicode codepoints in xkb_keysym_to_utf8 and
xkb_keysym_to_utf32.
libxkbcommon 0.8.0 - 2017-12-15
==================
- Added xkb_keysym_to_{upper,lower} to perform case-conversion directly on
keysyms. This is useful in some odd cases, but working with the Unicode
representations should be preferred when possible.
- Added Unicode conversion rules for the signifblank and permille keysyms.
- Fixed a bug in the parsing of XKB key type definitions where the number
of levels were determined by the number of level *names*. Keymaps which
omit level names were hence miscompiled.
This regressed in version 0.4.3. Keymaps from xkeyboard-config were not
affected since they don't omit level names.
- New API:
xkb_keysym_to_upper()
xkb_keysym_to_lower()
libxkbcommon 0.7.2 - 2017-08-04
==================
- Added a Meson build system as an alternative to existing autotools build
system.
The intent is to remove the autotools build in one of the next releases.
Please try to convert to it and report any problems.
See http://mesonbuild.com/Quick-guide.html for basic usage, the
meson_options.txt for the project-specific configuration options,
and the PACKAGING file for more details.
There are some noteworthy differences compared to the autotools build:
- Feature auto-detection is not performed. By default, all features are
enabled (currently: docs, x11, wayland). The build fails if any of
the required dependencies are not available. To disable a feature,
pass -Denable-<feature>=false to meson.
- The libraries are either installed as shared or static, as specified
by the -Ddefault_library=shared/static option. With autotools, both
versions are installed by default.
- xorg-util-macros is not used.
- A parser generator (bison/byacc) is always required - there is no
fallback to pre-generated output bundled in the tarball, as there is
in autotools.
- Removed Android.mk support.
- Removed the *-uninstalled.pc pkgconfig files.
- Ported the interactive-wayland demo program to v6 of the xdg-shell
protocol.
- Added new keysym definitions from xproto.
- New API:
XKB_KEY_XF86Keyboard
XKB_KEY_XF86WWAN
XKB_KEY_XF86RFKill
XKB_KEY_XF86AudioPreset
libxkbcommon 0.7.1 - 2017-01-18
==================
- Fixed various reported problems when the current locale is tr_TR.UTF-8.
The function xkb_keysym_from_name() used to perform case-insensitive
string comparisons in a locale-dependent way, but required it to to
work as in the C/ASCII locale (the so called "Turkish i problem").
The function is now no longer affected by the current locale.
- Fixed compilation in NetBSD.
libxkbcommon 0.7.0 - 2016-11-11
==================
- Added support for different "modes" of calculating consumed modifiers.
The existing mode, based on the XKB standard, has proven to be
unintuitive in various shortcut implementations.
A new mode, based on the calculation used by the GTK toolkit, is added.
This mode is less eager to declare a modifier as consumed.
- Added a new interactive demo program using the Wayland protocol.
See the PACKAGING file for the new (optional) test dependencies.
- Fixed a compilation error on GNU Hurd.
- New API:
enum xkb_consumed_mode
XKB_CONSUMED_MODE_XKB
XKB_CONSUMED_MODE_GTK
xkb_state_key_get_consumed_mods2
xkb_state_mod_index_is_consumed2
libxkbcommon 0.6.1 - 2016-04-08
==================
- Added LICENSE to distributed files in tarball releases.
- Minor typo fix in xkb_keymap_get_as_string() documentation.
libxkbcommon 0.6.0 - 2016-03-16
==================
- If the XKB_CONFIG_ROOT environment variable is set, it is used as the XKB
configuration root instead of the path determined at build time.
- Tests and benchmarks now build correctly on OSX.
- An XKB keymap provides a name for each key it defines. Traditionally,
these names are limited to at most 4 characters, and are thus somewhat
obscure, but might still be useful (xkbcommon lifts the 4 character limit).
The new functions xkb_keymap_key_get_name() and xkb_keymap_key_by_name()
can be used to get the name of a key or find a key by name. Note that
a key may have aliases.
- Documentation improvements.
- New API:
xkb_keymap_key_by_name()
xkb_keymap_key_get_name()
libxkbcommon 0.5.0 - 2014-10-18
==================
- Added support for Compose/dead keys in a new module (included in
libxkbcommon). See the documentation or the
xkbcommon/xkbcommon-compose.h header file for more details.
- Improved and reordered some sections of the documentation.
- The doxygen HTML pages were made nicer to read.
- Most tests now run also on non-linux platforms.
- A warning is emitted by default about RMLVO values which are not used
during keymap compilation, which are most often a user misconfiguration.
For example, "terminate:ctrl_alt_backspace" instead of
"terminate:ctrl_alt_bksp".
- Added symbol versioning for libxkbcommon and libxkbcommon-x11.
Note: binaries compiled against this and future versions will not be
able to link against the previous versions of the library.
- Removed several compatablity symbols from the binary (the API isn't
affected). This affects binaries which
1. Were compiled against a pre-stable (<0.2.0) version of libxkbcommon, and
2. Are linked against the this or later version of libxkbcommon.
Such a scenario is likely to fail already.
- If Xvfb is not available, the x11comp test is now correctly skipped
instead of hanging.
- Benchmarks were moved to a separate bench/ directory.
- Build fixes from OpenBSD.
- Fixed a bug where key type entries such as "map[None] = Level2;" were
ignored.
- New API:
XKB_COMPOSE_*
xkb_compose_*
libxkbcommon 0.4.3 - 2014-08-19
==================
- Fixed a bug which caused xkb_x11_keymap_new_from_device() to misrepresent
modifiers for some keymaps.
https://github.com/xkbcommon/libxkbcommon/issues/9
- Fixed a bug which caused xkb_x11_keymap_new_from_device() to ignore XKB
PrivateAction's.
- Modifiers are now always fully resolved after xkb_state_update_mask().
Previously the given state components were used as-is, without
considering virtual modifier mappings.
Note: this only affects non-standard uses of xkb_state_update_mask().
- Added a test for xkbcommon-x11, "x11comp". The test uses the system's
Xvfb server and xkbcomp. If they do not exist or fail, the test is
skipped.
- Fixed memory leaks after parse errors in the XKB yacc parser.
The fix required changes which are currently incompatible with byacc.
libxkbcommon 0.4.2 - 2014-05-15
==================
- Fixed a bug where explicitly passing "--enable-x11" to ./configure would
in fact disable it (regressed in 0.4.1).
- Added @since version annotations to the API documentation for everything
introduced after the initial stable release (0.2.0).
- Added a section to the documentation about keysym transformations, and
clarified which functions perform a given transformation.
- XKB files which fail to compile during keymap construction can no longer
have any effect on the resulting keymap: changes are only applied when
the entire compilation succeeds.
Note: this was a minor correctness issue inherited from xkbcomp.
- Fix an out-of-bounds array access in src/x11/util.c:adopt_atoms()
error-handling code.
Note: it seems impossible to trigger in the current code since the input
size cannot exceed the required size.
libxkbcommon 0.4.1 - 2014-03-27
==================
- Converted README to markdown and added a Quick Guide to the
documentation, which breezes through the most common parts of
xkbcommon.
- Added two new functions, xkb_state_key_get_utf{8,32}(). They
combine the operations of xkb_state_key_get_syms() and
xkb_keysym_to_utf{8,32}(), and provide a nicer interface for it
(espcially for multiple-keysyms-per-level).
- The xkb_state_key_get_utf{8,32}() functions now apply Control
transformation: when the Control modifier is active, the string
is converted to an appropriate control character.
This matches the behavior of libX11's XLookupString(3), and
required by the XKB specification:
https://www.x.org/releases/current/doc/kbproto/xkbproto.html#Interpreting_the_Control_Modifier
https://bugs.freedesktop.org/show_bug.cgi?id=75892
- The consumed modifiers for a key are now calculated similarly
to libX11. The previous behavior caused a bug where Shift would
not cancel an active Caps Lock.
- Make xkbcommon-x11 work with the keymap reported by the XQuartz
X server.
https://bugs.freedesktop.org/show_bug.cgi?id=75798
- Reduce memory usage during keymap compilation some more.
- New API:
xkb_state_key_get_consumed_mods()
xkb_state_key_get_utf8()
xkb_state_key_get_utf32()
- Deprecated API:
XKB_MAP_COMPILE_PLACEHOLDER, XKB_MAP_NO_FLAGS
use XKB_KEYMAP_NO_FLAGS instead.
- Bug fixes.
libxkbcommon 0.4.0 - 2014-02-02
==================
- Add a new add-on library, xkbcommon-x11, to support creating keymaps
with the XKB X11 protocol, by querying the X server directly.
See the xkbcommon/xkbcommon-x11.h header file for more details.
This library requires libxcb-xkb >= 1.10, and is enabled by default.
It can be disabled with the --disable-x11 configure switch.
Distributions are encouraged to split the necessary files for this
library (libxkbcommon-x11.so, xkbcommon-x11.pc, xkbcommon/xkbcommon-x11.h)
to a separate package, such that the main package does not depend on
X11 libraries.
- Fix the keysym <-> name lookup table to not require huge amounts of
relocations.
- Fix a bug in the keysym <-> name lookup, whereby lookup might fail in
some rare cases.
- Reduce memory usage during keymap compilation.
- New API:
New keysyms from xproto 7.0.25 (German T3 layout keysyms).
XKB_MOD_NAME_NUM for the usual NumLock modifier.
xkb_x11_* types and functions, XKB_X11_* constants.
libxkbcommon 0.3.2 - 2013-11-22
==================
- Log messages from the library now look like "xkbcommon: ERROR" by
default, instead of xkbcomp-like "Error: ".
- Apply capitalization transformation on keysyms in
xkb_keysym_get_one_sym(), to match the behavior specified in the XKB
specification:
https://www.x.org/releases/current/doc/kbproto/xkbproto.html#Interpreting_the_Lock_Modifier
- Support byacc for generating the parser, in addition to Bison.
- New API:
XKB_KEY_XF86AudioMicMute keysym from xproto 7.0.24.
XKB_KEYSYM_NO_FLAGS
XKB_CONTEXT_NO_FLAGS
XKB_MAP_COMPILE_NO_FLAGS
- Bug fixes.
libxkbcommon 0.3.1 - 2013-06-03
==================
- Replace the flex scanner with a hand-written one. flex is no longer
a build requirement.
- New API:
xkb_keymap_min_keycode()
xkb_keymap_max_keycode()
xkb_keymap_key_for_each()
libxkbcommon 0.3.0 - 2013-04-01
==================
- Allow passing NULL to *_unref() functions; do nothing instead of
crashing.
- The functions xkb_keymap_num_levels_for_key() and
xkb_keymap_get_syms_by_level() now allow out-of-range values for the
'layout' parameter. The functions now wrap the value around the number
of layouts instead of failing.
- The function xkb_keysym_get_name() now types unicode keysyms in
uppercase and 0-padding, to match the format used by XKeysymToString().
- Building Linux-specific tests is no longer attempted on non-Linux
environments.
- The function xkb_keymap_new_from_names() now accepts a NULL value for
the 'names' parameter, instead of failing. This is equivalent to passing
a 'struct xkb_rule_names' with all fields set to NULL.
- New API:
xkb_keymap_new_from_buffer()
- Bug fixes.

View File

@ -1,75 +0,0 @@
# libxkbcommon
libxkbcommon is a keyboard keymap compiler and support library which
processes a reduced subset of keymaps as defined by the XKB (X Keyboard
Extension) specification. It also contains a module for handling Compose
and dead keys.
## Quick Guide
See [Quick Guide](doc/quick-guide.md).
## Building
libxkbcommon is built with [Meson](http://mesonbuild.com/):
meson setup build
ninja -C build
To build for use with Wayland, you can disable X11 support while still
using the X11 keyboard configuration resource files thusly:
meson setup build \
-Denable-x11=false \
-Dxkb-config-root=/usr/share/X11/xkb \
-Dx-locale-root=/usr/share/X11/locale
ninja -C build
## API
While libxkbcommon's API is somewhat derived from the classic XKB API as found
in X11/extensions/XKB.h and friends, it has been substantially reworked to
expose fewer internal details to clients.
See the [API Documentation](https://xkbcommon.org/doc/current/modules.html).
## Dataset
libxkbcommon does not distribute a keymap dataset itself, other than for
testing purposes. The most common dataset is xkeyboard-config, which is used
by all current distributions for their X11 XKB data. More information on
xkeyboard-config is available here:
https://www.freedesktop.org/wiki/Software/XKeyboardConfig
The dataset for Compose is distributed in libX11, as part of the X locale
data.
## Relation to X11
See [Compatibility](doc/compat.md) notes.
## Development
An extremely rudimentary homepage can be found at
https://xkbcommon.org
xkbcommon is maintained in git at
https://github.com/xkbcommon/libxkbcommon
Patches are always welcome, and may be sent to either
<xorg-devel@lists.x.org> or <wayland-devel@lists.freedesktop.org>
or through github.
Bug reports are also welcome, and may be filed either at
Bugzilla https://bugs.freedesktop.org/describecomponents.cgi?product=libxkbcommon
or
Github https://github.com/xkbcommon/libxkbcommon/issues
The maintainers are
- Daniel Stone <daniel@fooishbar.org>
- Ran Benita <ran234@gmail.com>
## Credits
Many thanks are due to Dan Nicholson for his heroic work in getting xkbcommon
off the ground initially.

View File

@ -1,29 +0,0 @@
{
"Id": "xkbcommon",
"Name": "xkbcommon",
"QDocModule": "qtgui",
"QtUsage": "Used in xcb platform plugin. Configure with -system-xkbcommon-x11 to avoid.",
"Description": "xkbcommon is a keymap compiler and support library which processes a reduced subset of keymaps as defined by the XKB specification.",
"Homepage": "http://xkbcommon.org/",
"Version": "0.8.2 + subsequent commits up to 31f1f355700870c6615399fbfa7934934b3a9a57",
"License": "MIT Licenses (with no-advertisement clause)",
"LicenseId": "MIT",
"LicenseFile": "LICENSE",
"Copyright": "Copyright 2009-2012, 2016 Daniel Stone
Copyright 2012 Ran Benita <ran234@gmail.com>
Copyright 2010, 2012 Intel Corporation
Copyright 2008, 2009 Dan Nicholson
Copyright 2010 Francisco Jerez <currojerez@riseup.net>
Copyright 1985, 1987, 1988, 1990, 1998 The Open Group
Copyright 1993, 1994, 1995, 1996 by Silicon Graphics Computer Systems, Inc.
Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
Copyright 2011 Joseph Adams <joeyadams3.14159@gmail.com>
Copyright 1996 by Joseph Moss
Copyright 2002-2007 Free Software Foundation, Inc.
Copyright 2003-2004 Dmitry Golubev <lastguru@mail.ru>
Copyright 2004, Gregory Mokhin <mokhin@bog.msu.ru>
Copyright 2006 Erdal Ronahî
Copyright 1992 by Oki Technosystems Laboratory, Inc.
Copyright 1992 by Fuji Xerox Co., Ltd."
}

View File

@ -1,225 +0,0 @@
/***********************************************************
* Copyright 1987, 1998 The Open Group
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation.
*
* 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
* OPEN GROUP 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 Open Group 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 Open Group.
*
*
* Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
*
* All Rights Reserved
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose and without fee is hereby granted,
* provided that the above copyright notice appear in all copies and that
* both that copyright notice and this permission notice appear in
* supporting documentation, and that the name of Digital not be
* used in advertising or publicity pertaining to distribution of the
* software without specific, written prior permission.
*
* DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
* DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
* ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
* WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
* SOFTWARE.
*
******************************************************************/
/************************************************************
* Copyright 1994 by Silicon Graphics Computer Systems, Inc.
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting
* documentation, and that the name of Silicon Graphics not be
* used in advertising or publicity pertaining to distribution
* of the software without specific prior written permission.
* Silicon Graphics makes no representation about the suitability
* of this software for any purpose. It is provided "as is"
* without any express or implied warranty.
*
* SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
* GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
********************************************************/
#include "utils.h"
#include "atom.h"
struct atom_node {
xkb_atom_t left, right;
xkb_atom_t atom;
unsigned int fingerprint;
char *string;
};
struct atom_table {
xkb_atom_t root;
darray(struct atom_node) table;
};
struct atom_table *
atom_table_new(void)
{
struct atom_table *table;
table = calloc(1, sizeof(*table));
if (!table)
return NULL;
darray_init(table->table);
/* The original throw-away root is here, at the illegal atom 0. */
darray_resize0(table->table, 1);
return table;
}
void
atom_table_free(struct atom_table *table)
{
struct atom_node *node;
if (!table)
return;
darray_foreach(node, table->table)
free(node->string);
darray_free(table->table);
free(table);
}
const char *
atom_text(struct atom_table *table, xkb_atom_t atom)
{
if (atom == XKB_ATOM_NONE || atom >= darray_size(table->table))
return NULL;
return darray_item(table->table, atom).string;
}
static bool
find_atom_pointer(struct atom_table *table, const char *string, size_t len,
xkb_atom_t **atomp_out, unsigned int *fingerprint_out)
{
xkb_atom_t *atomp = &table->root;
unsigned int fingerprint = 0;
bool found = false;
for (size_t i = 0; i < (len + 1) / 2; i++) {
fingerprint = fingerprint * 27 + string[i];
fingerprint = fingerprint * 27 + string[len - 1 - i];
}
while (*atomp != XKB_ATOM_NONE) {
struct atom_node *node = &darray_item(table->table, *atomp);
if (fingerprint < node->fingerprint) {
atomp = &node->left;
}
else if (fingerprint > node->fingerprint) {
atomp = &node->right;
}
else {
/* Now start testing the strings. */
const int cmp = strncmp(string, node->string, len);
if (cmp < 0 || (cmp == 0 && len < strlen(node->string))) {
atomp = &node->left;
}
else if (cmp > 0) {
atomp = &node->right;
}
else {
found = true;
break;
}
}
}
if (fingerprint_out)
*fingerprint_out = fingerprint;
if (atomp_out)
*atomp_out = atomp;
return found;
}
xkb_atom_t
atom_lookup(struct atom_table *table, const char *string, size_t len)
{
xkb_atom_t *atomp;
if (!string)
return XKB_ATOM_NONE;
if (!find_atom_pointer(table, string, len, &atomp, NULL))
return XKB_ATOM_NONE;
return *atomp;
}
/*
* If steal is true, we do not strdup @string; therefore it must be
* dynamically allocated, NUL-terminated, not be free'd by the caller
* and not be used afterwards. Use to avoid some redundant allocations.
*/
xkb_atom_t
atom_intern(struct atom_table *table, const char *string, size_t len,
bool steal)
{
xkb_atom_t *atomp;
struct atom_node node;
unsigned int fingerprint;
if (!string)
return XKB_ATOM_NONE;
if (find_atom_pointer(table, string, len, &atomp, &fingerprint)) {
if (steal)
free(UNCONSTIFY(string));
return *atomp;
}
if (steal) {
node.string = UNCONSTIFY(string);
}
else {
node.string = strndup(string, len);
if (!node.string)
return XKB_ATOM_NONE;
}
node.left = node.right = XKB_ATOM_NONE;
node.fingerprint = fingerprint;
node.atom = darray_size(table->table);
/* Do this before the append, as it may realloc and change the offsets. */
*atomp = node.atom;
darray_append(table->table, node);
return node.atom;
}

View File

@ -1,49 +0,0 @@
/*
* Copyright © 2009 Dan Nicholson
*
* 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 (including the next
* paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
*/
#ifndef ATOM_H
#define ATOM_H
typedef uint32_t xkb_atom_t;
#define XKB_ATOM_NONE 0
struct atom_table;
struct atom_table *
atom_table_new(void);
void
atom_table_free(struct atom_table *table);
xkb_atom_t
atom_lookup(struct atom_table *table, const char *string, size_t len);
xkb_atom_t
atom_intern(struct atom_table *table, const char *string, size_t len,
bool steal);
const char *
atom_text(struct atom_table *table, xkb_atom_t atom);
#endif /* ATOM_H */

View File

@ -1,196 +0,0 @@
/*
* Copyright © 2013 Ran Benita <ran234@gmail.com>
*
* 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 (including the next
* paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
*/
#include "table.h"
#include "utils.h"
#include "keysym.h"
struct xkb_compose_state {
int refcnt;
enum xkb_compose_state_flags flags;
struct xkb_compose_table *table;
/*
* Offsets into xkb_compose_table::nodes.
*
* They maintain the current and previous position in the trie; see
* xkb_compose_state_feed().
*
* This is also sufficient for inferring the current status; see
* xkb_compose_state_get_status().
*/
uint32_t prev_context;
uint32_t context;
};
XKB_EXPORT struct xkb_compose_state *
xkb_compose_state_new(struct xkb_compose_table *table,
enum xkb_compose_state_flags flags)
{
struct xkb_compose_state *state;
state = calloc(1, sizeof(*state));
if (!state)
return NULL;
state->refcnt = 1;
state->table = xkb_compose_table_ref(table);
state->flags = flags;
state->prev_context = 0;
state->context = 0;
return state;
}
XKB_EXPORT struct xkb_compose_state *
xkb_compose_state_ref(struct xkb_compose_state *state)
{
state->refcnt++;
return state;
}
XKB_EXPORT void
xkb_compose_state_unref(struct xkb_compose_state *state)
{
if (!state || --state->refcnt > 0)
return;
xkb_compose_table_unref(state->table);
free(state);
}
XKB_EXPORT struct xkb_compose_table *
xkb_compose_state_get_compose_table(struct xkb_compose_state *state)
{
return state->table;
}
XKB_EXPORT enum xkb_compose_feed_result
xkb_compose_state_feed(struct xkb_compose_state *state, xkb_keysym_t keysym)
{
uint32_t context;
const struct compose_node *node;
/*
* Modifiers do not affect the sequence directly. In particular,
* they do not cancel a sequence; otherwise it'd be impossible to
* have a sequence like <dead_acute><A> (needs Shift in the middle).
*
* The following test is not really accurate - in order to test if
* a key is "modifier key", we really need the keymap, but we don't
* have it here. However, this is (approximately) what libX11 does
* as well.
*/
if (xkb_keysym_is_modifier(keysym))
return XKB_COMPOSE_FEED_IGNORED;
node = &darray_item(state->table->nodes, state->context);
context = (node->is_leaf ? 0 : node->u.successor);
node = &darray_item(state->table->nodes, context);
while (node->keysym != keysym && node->next != 0) {
context = node->next;
node = &darray_item(state->table->nodes, context);
}
if (node->keysym != keysym)
context = 0;
state->prev_context = state->context;
state->context = context;
return XKB_COMPOSE_FEED_ACCEPTED;
}
XKB_EXPORT void
xkb_compose_state_reset(struct xkb_compose_state *state)
{
state->prev_context = 0;
state->context = 0;
}
XKB_EXPORT enum xkb_compose_status
xkb_compose_state_get_status(struct xkb_compose_state *state)
{
const struct compose_node *prev_node, *node;
prev_node = &darray_item(state->table->nodes, state->prev_context);
node = &darray_item(state->table->nodes, state->context);
if (state->context == 0 && !prev_node->is_leaf)
return XKB_COMPOSE_CANCELLED;
if (state->context == 0)
return XKB_COMPOSE_NOTHING;
if (!node->is_leaf)
return XKB_COMPOSE_COMPOSING;
return XKB_COMPOSE_COMPOSED;
}
XKB_EXPORT int
xkb_compose_state_get_utf8(struct xkb_compose_state *state,
char *buffer, size_t size)
{
const struct compose_node *node =
&darray_item(state->table->nodes, state->context);
if (!node->is_leaf)
goto fail;
/* If there's no string specified, but only a keysym, try to do the
* most helpful thing. */
if (node->u.leaf.utf8 == 0 && node->u.leaf.keysym != XKB_KEY_NoSymbol) {
char name[64];
int ret;
ret = xkb_keysym_to_utf8(node->u.leaf.keysym, name, sizeof(name));
if (ret < 0 || ret == 0) {
/* ret < 0 is impossible.
* ret == 0 means the keysym has no string representation. */
goto fail;
}
return snprintf(buffer, size, "%s", name);
}
return snprintf(buffer, size, "%s",
&darray_item(state->table->utf8, node->u.leaf.utf8));
fail:
if (size > 0)
buffer[0] = '\0';
return 0;
}
XKB_EXPORT xkb_keysym_t
xkb_compose_state_get_one_sym(struct xkb_compose_state *state)
{
const struct compose_node *node =
&darray_item(state->table->nodes, state->context);
if (!node->is_leaf)
return XKB_KEY_NoSymbol;
return node->u.leaf.keysym;
}

View File

@ -1,737 +0,0 @@
/*
* Copyright © 2013 Ran Benita <ran234@gmail.com>
*
* 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 (including the next
* paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
*/
/******************************************************************
Copyright 1992 by Oki Technosystems Laboratory, Inc.
Copyright 1992 by Fuji Xerox Co., Ltd.
Permission to use, copy, modify, distribute, and sell this software
and its documentation for any purpose is hereby granted without fee,
provided that the above copyright notice appear in all copies and
that both that copyright notice and this permission notice appear
in supporting documentation, and that the name of Oki Technosystems
Laboratory and Fuji Xerox not be used in advertising or publicity
pertaining to distribution of the software without specific, written
prior permission.
Oki Technosystems Laboratory and Fuji Xerox make no representations
about the suitability of this software for any purpose. It is provided
"as is" without express or implied warranty.
OKI TECHNOSYSTEMS LABORATORY AND FUJI XEROX DISCLAIM ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL OKI TECHNOSYSTEMS
LABORATORY AND FUJI XEROX BE LIABLE FOR ANY SPECIAL, INDIRECT OR
CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
OR PERFORMANCE OF THIS SOFTWARE.
Author: Yasuhiro Kawai Oki Technosystems Laboratory
Author: Kazunori Nishihara Fuji Xerox
******************************************************************/
#include <errno.h>
#include "utils.h"
#include "scanner-utils.h"
#include "table.h"
#include "paths.h"
#include "utf8.h"
#include "parser.h"
#define MAX_LHS_LEN 10
#define MAX_INCLUDE_DEPTH 5
/*
* Grammar adapted from libX11/modules/im/ximcp/imLcPrs.c.
* See also the XCompose(5) manpage.
*
* FILE ::= { [PRODUCTION] [COMMENT] "\n" | INCLUDE }
* INCLUDE ::= "include" '"' INCLUDE_STRING '"'
* PRODUCTION ::= LHS ":" RHS [ COMMENT ]
* COMMENT ::= "#" {<any character except null or newline>}
* LHS ::= EVENT { EVENT }
* EVENT ::= [MODIFIER_LIST] "<" keysym ">"
* MODIFIER_LIST ::= (["!"] {MODIFIER} ) | "None"
* MODIFIER ::= ["~"] MODIFIER_NAME
* MODIFIER_NAME ::= ("Ctrl"|"Lock"|"Caps"|"Shift"|"Alt"|"Meta")
* RHS ::= ( STRING | keysym | STRING keysym )
* STRING ::= '"' { CHAR } '"'
* CHAR ::= GRAPHIC_CHAR | ESCAPED_CHAR
* GRAPHIC_CHAR ::= locale (codeset) dependent code
* ESCAPED_CHAR ::= ('\\' | '\"' | OCTAL | HEX )
* OCTAL ::= '\' OCTAL_CHAR [OCTAL_CHAR [OCTAL_CHAR]]
* OCTAL_CHAR ::= (0|1|2|3|4|5|6|7)
* HEX ::= '\' (x|X) HEX_CHAR [HEX_CHAR]]
* HEX_CHAR ::= (0|1|2|3|4|5|6|7|8|9|A|B|C|D|E|F|a|b|c|d|e|f)
*
* INCLUDE_STRING is a filesystem path, with the following %-expansions:
* %% - '%'.
* %H - The user's home directory (the $HOME environment variable).
* %L - The name of the locale specific Compose file (e.g.,
* "/usr/share/X11/locale/<localename>/Compose").
* %S - The name of the system directory for Compose files (e.g.,
* "/usr/share/X11/locale").
*/
enum rules_token {
TOK_END_OF_FILE = 0,
TOK_END_OF_LINE,
TOK_INCLUDE,
TOK_INCLUDE_STRING,
TOK_LHS_KEYSYM,
TOK_COLON,
TOK_BANG,
TOK_TILDE,
TOK_STRING,
TOK_IDENT,
TOK_ERROR
};
/* Values returned with some tokens, like yylval. */
union lvalue {
struct {
/* Still \0-terminated. */
const char *str;
size_t len;
} string;
};
static enum rules_token
lex(struct scanner *s, union lvalue *val)
{
skip_more_whitespace_and_comments:
/* Skip spaces. */
while (is_space(peek(s)))
if (next(s) == '\n')
return TOK_END_OF_LINE;
/* Skip comments. */
if (chr(s, '#')) {
skip_to_eol(s);
goto skip_more_whitespace_and_comments;
}
/* See if we're done. */
if (eof(s)) return TOK_END_OF_FILE;
/* New token. */
s->token_line = s->line;
s->token_column = s->column;
s->buf_pos = 0;
/* LHS Keysym. */
if (chr(s, '<')) {
while (peek(s) != '>' && !eol(s) && !eof(s))
buf_append(s, next(s));
if (!chr(s, '>')) {
scanner_err(s, "unterminated keysym literal");
return TOK_ERROR;
}
if (!buf_append(s, '\0')) {
scanner_err(s, "keysym literal is too long");
return TOK_ERROR;
}
val->string.str = s->buf;
val->string.len = s->buf_pos;
return TOK_LHS_KEYSYM;
}
/* Colon. */
if (chr(s, ':'))
return TOK_COLON;
if (chr(s, '!'))
return TOK_BANG;
if (chr(s, '~'))
return TOK_TILDE;
/* String literal. */
if (chr(s, '\"')) {
while (!eof(s) && !eol(s) && peek(s) != '\"') {
if (chr(s, '\\')) {
uint8_t o;
if (chr(s, '\\')) {
buf_append(s, '\\');
}
else if (chr(s, '"')) {
buf_append(s, '"');
}
else if (chr(s, 'x') || chr(s, 'X')) {
if (hex(s, &o))
buf_append(s, (char) o);
else
scanner_warn(s, "illegal hexadecimal escape sequence in string literal");
}
else if (oct(s, &o)) {
buf_append(s, (char) o);
}
else {
scanner_warn(s, "unknown escape sequence (%c) in string literal", peek(s));
/* Ignore. */
}
} else {
buf_append(s, next(s));
}
}
if (!chr(s, '\"')) {
scanner_err(s, "unterminated string literal");
return TOK_ERROR;
}
if (!buf_append(s, '\0')) {
scanner_err(s, "string literal is too long");
return TOK_ERROR;
}
if (!is_valid_utf8(s->buf, s->buf_pos - 1)) {
scanner_err(s, "string literal is not a valid UTF-8 string");
return TOK_ERROR;
}
val->string.str = s->buf;
val->string.len = s->buf_pos;
return TOK_STRING;
}
/* Identifier or include. */
if (is_alpha(peek(s)) || peek(s) == '_') {
s->buf_pos = 0;
while (is_alnum(peek(s)) || peek(s) == '_')
buf_append(s, next(s));
if (!buf_append(s, '\0')) {
scanner_err(s, "identifier is too long");
return TOK_ERROR;
}
if (streq(s->buf, "include"))
return TOK_INCLUDE;
val->string.str = s->buf;
val->string.len = s->buf_pos;
return TOK_IDENT;
}
/* Discard rest of line. */
skip_to_eol(s);
scanner_err(s, "unrecognized token");
return TOK_ERROR;
}
static enum rules_token
lex_include_string(struct scanner *s, struct xkb_compose_table *table,
union lvalue *val_out)
{
while (is_space(peek(s)))
if (next(s) == '\n')
return TOK_END_OF_LINE;
s->token_line = s->line;
s->token_column = s->column;
s->buf_pos = 0;
if (!chr(s, '\"')) {
scanner_err(s, "include statement must be followed by a path");
return TOK_ERROR;
}
while (!eof(s) && !eol(s) && peek(s) != '\"') {
if (chr(s, '%')) {
if (chr(s, '%')) {
buf_append(s, '%');
}
else if (chr(s, 'H')) {
const char *home = secure_getenv("HOME");
if (!home) {
scanner_err(s, "%%H was used in an include statement, but the HOME environment variable is not set");
return TOK_ERROR;
}
if (!buf_appends(s, home)) {
scanner_err(s, "include path after expanding %%H is too long");
return TOK_ERROR;
}
}
else if (chr(s, 'L')) {
char *path = get_locale_compose_file_path(table->locale);
if (!path) {
scanner_err(s, "failed to expand %%L to the locale Compose file");
return TOK_ERROR;
}
if (!buf_appends(s, path)) {
free(path);
scanner_err(s, "include path after expanding %%L is too long");
return TOK_ERROR;
}
free(path);
}
else if (chr(s, 'S')) {
const char *xlocaledir = get_xlocaledir_path();
if (!buf_appends(s, xlocaledir)) {
scanner_err(s, "include path after expanding %%S is too long");
return TOK_ERROR;
}
}
else {
scanner_err(s, "unknown %% format (%c) in include statement", peek(s));
return TOK_ERROR;
}
} else {
buf_append(s, next(s));
}
}
if (!chr(s, '\"')) {
scanner_err(s, "unterminated include statement");
return TOK_ERROR;
}
if (!buf_append(s, '\0')) {
scanner_err(s, "include path is too long");
return TOK_ERROR;
}
val_out->string.str = s->buf;
val_out->string.len = s->buf_pos;
return TOK_INCLUDE_STRING;
}
struct production {
xkb_keysym_t lhs[MAX_LHS_LEN];
unsigned int len;
xkb_keysym_t keysym;
char string[256];
/* At least one of these is true. */
bool has_keysym;
bool has_string;
/* The matching is as follows: (active_mods & modmask) == mods. */
xkb_mod_mask_t modmask;
xkb_mod_mask_t mods;
};
static uint32_t
add_node(struct xkb_compose_table *table, xkb_keysym_t keysym)
{
struct compose_node new = {
.keysym = keysym,
.next = 0,
.is_leaf = true,
};
darray_append(table->nodes, new);
return darray_size(table->nodes) - 1;
}
static void
add_production(struct xkb_compose_table *table, struct scanner *s,
const struct production *production)
{
unsigned lhs_pos;
uint32_t curr;
struct compose_node *node;
curr = 0;
node = &darray_item(table->nodes, curr);
/*
* Insert the sequence to the trie, creating new nodes as needed.
*
* TODO: This can be sped up a bit by first trying the path that the
* previous production took, and only then doing the linear search
* through the trie levels. This will work because sequences in the
* Compose files are often clustered by a common prefix; especially
* in the 1st and 2nd keysyms, which is where the largest variation
* (thus, longest search) is.
*/
for (lhs_pos = 0; lhs_pos < production->len; lhs_pos++) {
while (production->lhs[lhs_pos] != node->keysym) {
if (node->next == 0) {
uint32_t next = add_node(table, production->lhs[lhs_pos]);
/* Refetch since add_node could have realloc()ed. */
node = &darray_item(table->nodes, curr);
node->next = next;
}
curr = node->next;
node = &darray_item(table->nodes, curr);
}
if (lhs_pos + 1 == production->len)
break;
if (node->is_leaf) {
if (node->u.leaf.utf8 != 0 ||
node->u.leaf.keysym != XKB_KEY_NoSymbol) {
scanner_warn(s, "a sequence already exists which is a prefix of this sequence; overriding");
node->u.leaf.utf8 = 0;
node->u.leaf.keysym = XKB_KEY_NoSymbol;
}
{
uint32_t successor = add_node(table, production->lhs[lhs_pos + 1]);
/* Refetch since add_node could have realloc()ed. */
node = &darray_item(table->nodes, curr);
node->is_leaf = false;
node->u.successor = successor;
}
}
curr = node->u.successor;
node = &darray_item(table->nodes, curr);
}
if (!node->is_leaf) {
scanner_warn(s, "this compose sequence is a prefix of another; skipping line");
return;
}
if (node->u.leaf.utf8 != 0 || node->u.leaf.keysym != XKB_KEY_NoSymbol) {
bool same_string =
(node->u.leaf.utf8 == 0 && !production->has_string) ||
(
node->u.leaf.utf8 != 0 && production->has_string &&
streq(&darray_item(table->utf8, node->u.leaf.utf8),
production->string)
);
bool same_keysym =
(node->u.leaf.keysym == XKB_KEY_NoSymbol && !production->has_keysym) ||
(
node->u.leaf.keysym != XKB_KEY_NoSymbol && production->has_keysym &&
node->u.leaf.keysym == production->keysym
);
if (same_string && same_keysym) {
scanner_warn(s, "this compose sequence is a duplicate of another; skipping line");
return;
}
scanner_warn(s, "this compose sequence already exists; overriding");
}
if (production->has_string) {
node->u.leaf.utf8 = darray_size(table->utf8);
darray_append_items(table->utf8, production->string,
strlen(production->string) + 1);
}
if (production->has_keysym) {
node->u.leaf.keysym = production->keysym;
}
}
/* Should match resolve_modifier(). */
#define ALL_MODS_MASK ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3))
static xkb_mod_index_t
resolve_modifier(const char *name)
{
static const struct {
const char *name;
xkb_mod_index_t mod;
} mods[] = {
{ "Shift", 0 },
{ "Ctrl", 2 },
{ "Alt", 3 },
{ "Meta", 3 },
{ "Lock", 1 },
{ "Caps", 1 },
};
for (unsigned i = 0; i < ARRAY_SIZE(mods); i++)
if (streq(name, mods[i].name))
return mods[i].mod;
return XKB_MOD_INVALID;
}
static bool
parse(struct xkb_compose_table *table, struct scanner *s,
unsigned include_depth);
static bool
do_include(struct xkb_compose_table *table, struct scanner *s,
const char *path, unsigned include_depth)
{
FILE *file;
bool ok;
char *string;
size_t size;
struct scanner new_s;
if (include_depth >= MAX_INCLUDE_DEPTH) {
scanner_err(s, "maximum include depth (%d) exceeded; maybe there is an include loop?",
MAX_INCLUDE_DEPTH);
return false;
}
file = fopen(path, "r");
if (!file) {
scanner_err(s, "failed to open included Compose file \"%s\": %s",
path, strerror(errno));
return false;
}
ok = map_file(file, &string, &size);
if (!ok) {
scanner_err(s, "failed to read included Compose file \"%s\": %s",
path, strerror(errno));
goto err_file;
}
scanner_init(&new_s, table->ctx, string, size, path, s->priv);
ok = parse(table, &new_s, include_depth + 1);
if (!ok)
goto err_unmap;
err_unmap:
unmap_file(string, size);
err_file:
fclose(file);
return ok;
}
static bool
parse(struct xkb_compose_table *table, struct scanner *s,
unsigned include_depth)
{
enum rules_token tok;
union lvalue val;
xkb_keysym_t keysym;
struct production production;
enum { MAX_ERRORS = 10 };
int num_errors = 0;
initial:
production.len = 0;
production.has_keysym = false;
production.has_string = false;
production.mods = 0;
production.modmask = 0;
/* fallthrough */
initial_eol:
switch (tok = lex(s, &val)) {
case TOK_END_OF_LINE:
goto initial_eol;
case TOK_END_OF_FILE:
goto finished;
case TOK_INCLUDE:
goto include;
default:
goto lhs_tok;
}
include:
switch (tok = lex_include_string(s, table, &val)) {
case TOK_INCLUDE_STRING:
goto include_eol;
default:
goto unexpected;
}
include_eol:
switch (tok = lex(s, &val)) {
case TOK_END_OF_LINE:
if (!do_include(table, s, val.string.str, include_depth))
goto fail;
goto initial;
default:
goto unexpected;
}
lhs:
tok = lex(s, &val);
lhs_tok:
switch (tok) {
case TOK_COLON:
if (production.len <= 0) {
scanner_warn(s, "expected at least one keysym on left-hand side; skipping line");
goto skip;
}
goto rhs;
case TOK_IDENT:
if (streq(val.string.str, "None")) {
production.mods = 0;
production.modmask = ALL_MODS_MASK;
goto lhs_keysym;
}
goto lhs_mod_list_tok;
case TOK_TILDE:
goto lhs_mod_list_tok;
case TOK_BANG:
production.modmask = ALL_MODS_MASK;
goto lhs_mod_list;
default:
goto lhs_keysym_tok;
}
lhs_keysym:
tok = lex(s, &val);
lhs_keysym_tok:
switch (tok) {
case TOK_LHS_KEYSYM:
keysym = xkb_keysym_from_name(val.string.str, XKB_KEYSYM_NO_FLAGS);
if (keysym == XKB_KEY_NoSymbol) {
scanner_err(s, "unrecognized keysym \"%s\" on left-hand side",
val.string.str);
goto error;
}
if (production.len + 1 > MAX_LHS_LEN) {
scanner_warn(s, "too many keysyms (%d) on left-hand side; skipping line",
MAX_LHS_LEN + 1);
goto skip;
}
production.lhs[production.len++] = keysym;
production.mods = 0;
production.modmask = 0;
goto lhs;
default:
goto unexpected;
}
lhs_mod_list:
tok = lex(s, &val);
lhs_mod_list_tok: {
bool tilde = false;
xkb_mod_index_t mod;
if (tok != TOK_TILDE && tok != TOK_IDENT)
goto lhs_keysym_tok;
if (tok == TOK_TILDE) {
tilde = true;
tok = lex(s, &val);
}
if (tok != TOK_IDENT)
goto unexpected;
mod = resolve_modifier(val.string.str);
if (mod == XKB_MOD_INVALID) {
scanner_err(s, "unrecognized modifier \"%s\"",
val.string.str);
goto error;
}
production.modmask |= 1 << mod;
if (tilde)
production.mods &= ~(1 << mod);
else
production.mods |= 1 << mod;
goto lhs_mod_list;
}
rhs:
switch (tok = lex(s, &val)) {
case TOK_STRING:
if (production.has_string) {
scanner_warn(s, "right-hand side can have at most one string; skipping line");
goto skip;
}
if (val.string.len <= 0) {
scanner_warn(s, "right-hand side string must not be empty; skipping line");
goto skip;
}
if (val.string.len >= sizeof(production.string)) {
scanner_warn(s, "right-hand side string is too long; skipping line");
goto skip;
}
strcpy(production.string, val.string.str);
production.has_string = true;
goto rhs;
case TOK_IDENT:
keysym = xkb_keysym_from_name(val.string.str, XKB_KEYSYM_NO_FLAGS);
if (keysym == XKB_KEY_NoSymbol) {
scanner_err(s, "unrecognized keysym \"%s\" on right-hand side",
val.string.str);
goto error;
}
if (production.has_keysym) {
scanner_warn(s, "right-hand side can have at most one keysym; skipping line");
goto skip;
}
production.keysym = keysym;
production.has_keysym = true;
/* fallthrough */
case TOK_END_OF_LINE:
if (!production.has_string && !production.has_keysym) {
scanner_warn(s, "right-hand side must have at least one of string or keysym; skipping line");
goto skip;
}
add_production(table, s, &production);
goto initial;
default:
goto unexpected;
}
unexpected:
if (tok != TOK_ERROR)
scanner_err(s, "unexpected token");
error:
num_errors++;
if (num_errors <= MAX_ERRORS)
goto skip;
scanner_err(s, "too many errors");
goto fail;
fail:
scanner_err(s, "failed to parse file");
return false;
skip:
while (tok != TOK_END_OF_LINE && tok != TOK_END_OF_FILE)
tok = lex(s, &val);
goto initial;
finished:
return true;
}
bool
parse_string(struct xkb_compose_table *table, const char *string, size_t len,
const char *file_name)
{
struct scanner s;
scanner_init(&s, table->ctx, string, len, file_name, NULL);
if (!parse(table, &s, 0))
return false;
/* Maybe the allocator can use the excess space. */
darray_shrink(table->nodes);
darray_shrink(table->utf8);
return true;
}
bool
parse_file(struct xkb_compose_table *table, FILE *file, const char *file_name)
{
bool ok;
char *string;
size_t size;
ok = map_file(file, &string, &size);
if (!ok) {
log_err(table->ctx, "Couldn't read Compose file %s: %s\n",
file_name, strerror(errno));
return false;
}
ok = parse_string(table, string, size, file_name);
unmap_file(string, size);
return ok;
}

View File

@ -1,36 +0,0 @@
/*
* Copyright © 2013 Ran Benita <ran234@gmail.com>
*
* 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 (including the next
* paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
*/
#ifndef COMPOSE_PARSER_H
#define COMPOSE_PARSER_H
bool
parse_string(struct xkb_compose_table *table,
const char *string, size_t len,
const char *file_name);
bool
parse_file(struct xkb_compose_table *table,
FILE *file, const char *file_name);
#endif

View File

@ -1,203 +0,0 @@
/*
* Copyright © 2014 Ran Benita <ran234@gmail.com>
*
* 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 (including the next
* paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
*/
#include "utils.h"
#include "paths.h"
enum resolve_name_direction {
LEFT_TO_RIGHT,
RIGHT_TO_LEFT,
};
const char *
get_xlocaledir_path(void)
{
const char *dir = secure_getenv("XLOCALEDIR");
if (!dir)
dir = XLOCALEDIR;
return dir;
}
/*
* Files like compose.dir have the format LEFT: RIGHT. Lookup @name in
* such a file and return its matching value, according to @direction.
* @filename is relative to the xlocaledir.
*/
static char *
resolve_name(const char *filename, enum resolve_name_direction direction,
const char *name)
{
int ret;
bool ok;
const char *xlocaledir;
char path[512];
FILE *file;
char *string;
size_t string_size;
const char *end;
const char *s, *left, *right;
char *match;
size_t left_len, right_len, name_len;
xlocaledir = get_xlocaledir_path();
ret = snprintf(path, sizeof(path), "%s/%s", xlocaledir, filename);
if (ret < 0 || (size_t) ret >= sizeof(path))
return false;
file = fopen(path, "r");
if (!file)
return false;
ok = map_file(file, &string, &string_size);
fclose(file);
if (!ok)
return false;
s = string;
end = string + string_size;
name_len = strlen(name);
match = NULL;
while (s < end) {
/* Skip spaces. */
while (s < end && is_space(*s))
s++;
/* Skip comments. */
if (s < end && *s == '#') {
while (s < end && *s != '\n')
s++;
continue;
}
/* Get the left value. */
left = s;
while (s < end && !is_space(*s) && *s != ':')
s++;
left_len = s - left;
/* There's an optional colon between left and right. */
if (s < end && *s == ':')
s++;
/* Skip spaces. */
while (s < end && is_space(*s))
s++;
/* Get the right value. */
right = s;
while (s < end && !is_space(*s))
s++;
right_len = s - right;
/* Discard rest of line. */
while (s < end && *s != '\n')
s++;
if (direction == LEFT_TO_RIGHT) {
if (left_len == name_len && memcmp(left, name, left_len) == 0) {
match = strndup(right, right_len);
break;
}
}
else if (direction == RIGHT_TO_LEFT) {
if (right_len == name_len && memcmp(right, name, right_len) == 0) {
match = strndup(left, left_len);
break;
}
}
}
unmap_file(string, string_size);
return match;
}
char *
resolve_locale(const char *locale)
{
char *alias = resolve_name("locale.alias", LEFT_TO_RIGHT, locale);
return alias ? alias : strdup(locale);
}
const char *
get_xcomposefile_path(void)
{
return secure_getenv("XCOMPOSEFILE");
}
char *
get_home_xcompose_file_path(void)
{
int ret;
const char *home;
char *path;
home = secure_getenv("HOME");
if (!home)
return NULL;
ret = asprintf(&path, "%s/.XCompose", home);
if (ret <0)
return NULL;
return path;
}
char *
get_locale_compose_file_path(const char *locale)
{
char *resolved;
char *path;
/*
* WARNING: Random workaround ahead.
*
* We currently do not support non-UTF-8 Compose files. The C/POSIX
* locale is specified to be the default fallback locale with an
* ASCII charset. But for some reason the compose.dir points the C
* locale to the iso8859-1/Compose file, which is not ASCII but
* ISO8859-1. Since this is bound to happen a lot, and since our API
* is UTF-8 based, and since 99% of the time a C locale is really just
* a misconfiguration for UTF-8, let's do the most helpful thing.
*/
if (streq(locale, "C"))
locale = "en_US.UTF-8";
resolved = resolve_name("compose.dir", RIGHT_TO_LEFT, locale);
if (!resolved)
return NULL;
if (resolved[0] == '/') {
path = resolved;
}
else {
const char *xlocaledir = get_xlocaledir_path();
int ret = asprintf(&path, "%s/%s", xlocaledir, resolved);
free(resolved);
if (ret < 0)
return NULL;
}
return path;
}

View File

@ -1,42 +0,0 @@
/*
* Copyright © 2014 Ran Benita <ran234@gmail.com>
*
* 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 (including the next
* paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
*/
#ifndef COMPOSE_RESOLVE_H
#define COMPOSE_RESOLVE_H
char *
resolve_locale(const char *locale);
const char *
get_xlocaledir_path(void);
const char *
get_xcomposefile_path(void);
char *
get_home_xcompose_file_path(void);
char *
get_locale_compose_file_path(const char *locale);
#endif

View File

@ -1,219 +0,0 @@
/*
* Copyright © 2013 Ran Benita <ran234@gmail.com>
*
* 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 (including the next
* paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
*/
#include "utils.h"
#include "table.h"
#include "parser.h"
#include "paths.h"
static struct xkb_compose_table *
xkb_compose_table_new(struct xkb_context *ctx,
const char *locale,
enum xkb_compose_format format,
enum xkb_compose_compile_flags flags)
{
char *resolved_locale;
struct xkb_compose_table *table;
struct compose_node root;
resolved_locale = resolve_locale(locale);
if (!resolved_locale)
return NULL;
table = calloc(1, sizeof(*table));
if (!table) {
free(resolved_locale);
return NULL;
}
table->refcnt = 1;
table->ctx = xkb_context_ref(ctx);
table->locale = resolved_locale;
table->format = format;
table->flags = flags;
darray_init(table->nodes);
darray_init(table->utf8);
root.keysym = XKB_KEY_NoSymbol;
root.next = 0;
root.is_leaf = true;
root.u.leaf.utf8 = 0;
root.u.leaf.keysym = XKB_KEY_NoSymbol;
darray_append(table->nodes, root);
darray_append(table->utf8, '\0');
return table;
}
XKB_EXPORT struct xkb_compose_table *
xkb_compose_table_ref(struct xkb_compose_table *table)
{
table->refcnt++;
return table;
}
XKB_EXPORT void
xkb_compose_table_unref(struct xkb_compose_table *table)
{
if (!table || --table->refcnt > 0)
return;
free(table->locale);
darray_free(table->nodes);
darray_free(table->utf8);
xkb_context_unref(table->ctx);
free(table);
}
XKB_EXPORT struct xkb_compose_table *
xkb_compose_table_new_from_file(struct xkb_context *ctx,
FILE *file,
const char *locale,
enum xkb_compose_format format,
enum xkb_compose_compile_flags flags)
{
struct xkb_compose_table *table;
bool ok;
if (flags & ~(XKB_COMPOSE_COMPILE_NO_FLAGS)) {
log_err_func(ctx, "unrecognized flags: %#x\n", flags);
return NULL;
}
if (format != XKB_COMPOSE_FORMAT_TEXT_V1) {
log_err_func(ctx, "unsupported compose format: %d\n", format);
return NULL;
}
table = xkb_compose_table_new(ctx, locale, format, flags);
if (!table)
return NULL;
ok = parse_file(table, file, "(unknown file)");
if (!ok) {
xkb_compose_table_unref(table);
return NULL;
}
return table;
}
XKB_EXPORT struct xkb_compose_table *
xkb_compose_table_new_from_buffer(struct xkb_context *ctx,
const char *buffer, size_t length,
const char *locale,
enum xkb_compose_format format,
enum xkb_compose_compile_flags flags)
{
struct xkb_compose_table *table;
bool ok;
if (flags & ~(XKB_COMPOSE_COMPILE_NO_FLAGS)) {
log_err_func(ctx, "unrecognized flags: %#x\n", flags);
return NULL;
}
if (format != XKB_COMPOSE_FORMAT_TEXT_V1) {
log_err_func(ctx, "unsupported compose format: %d\n", format);
return NULL;
}
table = xkb_compose_table_new(ctx, locale, format, flags);
if (!table)
return NULL;
ok = parse_string(table, buffer, length, "(input string)");
if (!ok) {
xkb_compose_table_unref(table);
return NULL;
}
return table;
}
XKB_EXPORT struct xkb_compose_table *
xkb_compose_table_new_from_locale(struct xkb_context *ctx,
const char *locale,
enum xkb_compose_compile_flags flags)
{
struct xkb_compose_table *table;
char *path = NULL;
const char *cpath;
FILE *file;
bool ok;
if (flags & ~(XKB_COMPOSE_COMPILE_NO_FLAGS)) {
log_err_func(ctx, "unrecognized flags: %#x\n", flags);
return NULL;
}
table = xkb_compose_table_new(ctx, locale, XKB_COMPOSE_FORMAT_TEXT_V1,
flags);
if (!table)
return NULL;
cpath = get_xcomposefile_path();
if (cpath) {
file = fopen(cpath, "r");
if (file)
goto found_path;
}
cpath = path = get_home_xcompose_file_path();
if (path) {
file = fopen(path, "r");
if (file)
goto found_path;
}
free(path);
path = NULL;
cpath = path = get_locale_compose_file_path(table->locale);
if (path) {
file = fopen(path, "r");
if (file)
goto found_path;
}
free(path);
path = NULL;
log_err(ctx, "couldn't find a Compose file for locale \"%s\"\n", locale);
xkb_compose_table_unref(table);
return NULL;
found_path:
ok = parse_file(table, file, cpath);
fclose(file);
if (!ok) {
xkb_compose_table_unref(table);
return NULL;
}
log_dbg(ctx, "created compose table from locale %s with path %s\n",
table->locale, path);
free(path);
return table;
}

View File

@ -1,100 +0,0 @@
/*
* Copyright © 2013 Ran Benita <ran234@gmail.com>
*
* 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 (including the next
* paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
*/
#ifndef COMPOSE_COMPOSE_H
#define COMPOSE_COMPOSE_H
#include "xkbcommon/xkbcommon-compose.h"
#include "utils.h"
#include "context.h"
/*
* The compose table data structure is a simple trie. An example will
* help. Given these sequences:
*
* <A> <B> : "first" dead_a
* <A> <C> <D> : "second" dead_b
* <E> <F> : "third" dead_c
*
* the trie would look like:
*
* [root] ---> [<A>] -----------------> [<E>] -#
* | | |
* # v v
* [<B>] ---> [<C>] -# [<F>] -#
* | | -
* # v #
* [<D>] -#
* |
* #
* where:
* - [root] is a special empty root node.
* - [<X>] is a node for a sequence keysym <X>.
* - right arrows are `next` pointers.
* - down arrows are `successor` pointers.
* - # is a nil pointer.
*
* The nodes are all kept in a contiguous array. Pointers are represented
* as integer offsets into this array. A nil pointer is represented as 0
* (which, helpfully, is the offset of the empty root node).
*
* Nodes without a successor are leaf nodes. Since a sequence cannot be a
* prefix of another, these are exactly the nodes which terminate the
* sequences (in a bijective manner).
*
* A leaf contains the result data of its sequence. The result keysym is
* contained in the node struct itself; the result UTF-8 string is a byte
* offset into an array of the form "\0first\0second\0third" (the initial
* \0 is so offset 0 points to an empty string).
*/
struct compose_node {
xkb_keysym_t keysym;
/* Offset into xkb_compose_table::nodes. */
unsigned int next:31;
bool is_leaf:1;
union {
/* Offset into xkb_compose_table::nodes. */
uint32_t successor;
struct {
/* Offset into xkb_compose_table::utf8. */
uint32_t utf8;
xkb_keysym_t keysym;
} leaf;
} u;
};
struct xkb_compose_table {
int refcnt;
enum xkb_compose_format format;
enum xkb_compose_compile_flags flags;
struct xkb_context *ctx;
char *locale;
darray_char utf8;
darray(struct compose_node) nodes;
};
#endif

View File

@ -1,190 +0,0 @@
/*
* Copyright © 2012 Intel Corporation
* Copyright © 2012 Ran Benita
*
* 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 (including the next
* paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
*
* Author: Daniel Stone <daniel@fooishbar.org>
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <unistd.h>
#include "xkbcommon/xkbcommon.h"
#include "utils.h"
#include "context.h"
unsigned int
xkb_context_num_failed_include_paths(struct xkb_context *ctx)
{
return darray_size(ctx->failed_includes);
}
const char *
xkb_context_failed_include_path_get(struct xkb_context *ctx,
unsigned int idx)
{
if (idx >= xkb_context_num_failed_include_paths(ctx))
return NULL;
return darray_item(ctx->failed_includes, idx);
}
xkb_atom_t
xkb_atom_lookup(struct xkb_context *ctx, const char *string)
{
return atom_lookup(ctx->atom_table, string, strlen(string));
}
xkb_atom_t
xkb_atom_intern(struct xkb_context *ctx, const char *string, size_t len)
{
return atom_intern(ctx->atom_table, string, len, false);
}
xkb_atom_t
xkb_atom_steal(struct xkb_context *ctx, char *string)
{
return atom_intern(ctx->atom_table, string, strlen(string), true);
}
const char *
xkb_atom_text(struct xkb_context *ctx, xkb_atom_t atom)
{
return atom_text(ctx->atom_table, atom);
}
void
xkb_log(struct xkb_context *ctx, enum xkb_log_level level, int verbosity,
const char *fmt, ...)
{
va_list args;
if (ctx->log_level < level || ctx->log_verbosity < verbosity)
return;
va_start(args, fmt);
ctx->log_fn(ctx, level, fmt, args);
va_end(args);
}
char *
xkb_context_get_buffer(struct xkb_context *ctx, size_t size)
{
char *rtrn;
if (size >= sizeof(ctx->text_buffer))
return NULL;
if (sizeof(ctx->text_buffer) - ctx->text_next <= size)
ctx->text_next = 0;
rtrn = &ctx->text_buffer[ctx->text_next];
ctx->text_next += size;
return rtrn;
}
#ifndef DEFAULT_XKB_VARIANT
#define DEFAULT_XKB_VARIANT NULL
#endif
#ifndef DEFAULT_XKB_OPTIONS
#define DEFAULT_XKB_OPTIONS NULL
#endif
static const char *
xkb_context_get_default_rules(struct xkb_context *ctx)
{
const char *env = NULL;
if (ctx->use_environment_names)
env = secure_getenv("XKB_DEFAULT_RULES");
return env ? env : DEFAULT_XKB_RULES;
}
static const char *
xkb_context_get_default_model(struct xkb_context *ctx)
{
const char *env = NULL;
if (ctx->use_environment_names)
env = secure_getenv("XKB_DEFAULT_MODEL");
return env ? env : DEFAULT_XKB_MODEL;
}
static const char *
xkb_context_get_default_layout(struct xkb_context *ctx)
{
const char *env = NULL;
if (ctx->use_environment_names)
env = secure_getenv("XKB_DEFAULT_LAYOUT");
return env ? env : DEFAULT_XKB_LAYOUT;
}
static const char *
xkb_context_get_default_variant(struct xkb_context *ctx)
{
const char *env = NULL;
const char *layout = secure_getenv("XKB_DEFAULT_LAYOUT");
/* We don't want to inherit the variant if they haven't also set a
* layout, since they're so closely paired. */
if (layout && ctx->use_environment_names)
env = secure_getenv("XKB_DEFAULT_VARIANT");
return env ? env : DEFAULT_XKB_VARIANT;
}
static const char *
xkb_context_get_default_options(struct xkb_context *ctx)
{
const char *env = NULL;
if (ctx->use_environment_names)
env = secure_getenv("XKB_DEFAULT_OPTIONS");
return env ? env : DEFAULT_XKB_OPTIONS;
}
void
xkb_context_sanitize_rule_names(struct xkb_context *ctx,
struct xkb_rule_names *rmlvo)
{
if (isempty(rmlvo->rules))
rmlvo->rules = xkb_context_get_default_rules(ctx);
if (isempty(rmlvo->model))
rmlvo->model = xkb_context_get_default_model(ctx);
/* Layout and variant are tied together, so don't try to use one from
* the caller and one from the environment. */
if (isempty(rmlvo->layout)) {
rmlvo->layout = xkb_context_get_default_layout(ctx);
rmlvo->variant = xkb_context_get_default_variant(ctx);
}
/* Options can be empty, so respect that if passed in. */
if (rmlvo->options == NULL)
rmlvo->options = xkb_context_get_default_options(ctx);
}

View File

@ -1,331 +0,0 @@
/*
* Copyright © 2012 Intel Corporation
* Copyright © 2012 Ran Benita
*
* 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 (including the next
* paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
*
* Author: Daniel Stone <daniel@fooishbar.org>
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <unistd.h>
#include "xkbcommon/xkbcommon.h"
#include "utils.h"
#include "context.h"
/**
* Append one directory to the context's include path.
*/
XKB_EXPORT int
xkb_context_include_path_append(struct xkb_context *ctx, const char *path)
{
struct stat stat_buf;
int err;
char *tmp;
tmp = strdup(path);
if (!tmp)
goto err;
err = stat(path, &stat_buf);
if (err != 0)
goto err;
if (!S_ISDIR(stat_buf.st_mode))
goto err;
#if defined(HAVE_EACCESS)
if (eaccess(path, R_OK | X_OK) != 0)
goto err;
#elif defined(HAVE_EUIDACCESS)
if (euidaccess(path, R_OK | X_OK) != 0)
goto err;
#endif
darray_append(ctx->includes, tmp);
return 1;
err:
darray_append(ctx->failed_includes, tmp);
return 0;
}
/**
* Append the default include directories to the context.
*/
XKB_EXPORT int
xkb_context_include_path_append_default(struct xkb_context *ctx)
{
const char *home, *root;
char *user_path;
int err;
int ret = 0;
root = secure_getenv("XKB_CONFIG_ROOT");
if (root != NULL)
ret |= xkb_context_include_path_append(ctx, root);
else
ret |= xkb_context_include_path_append(ctx, DFLT_XKB_CONFIG_ROOT);
home = secure_getenv("HOME");
if (!home)
return ret;
err = asprintf(&user_path, "%s/.xkb", home);
if (err <= 0)
return ret;
ret |= xkb_context_include_path_append(ctx, user_path);
free(user_path);
return ret;
}
/**
* Remove all entries in the context's include path.
*/
XKB_EXPORT void
xkb_context_include_path_clear(struct xkb_context *ctx)
{
char **path;
darray_foreach(path, ctx->includes)
free(*path);
darray_free(ctx->includes);
darray_foreach(path, ctx->failed_includes)
free(*path);
darray_free(ctx->failed_includes);
}
/**
* xkb_context_include_path_clear() + xkb_context_include_path_append_default()
*/
XKB_EXPORT int
xkb_context_include_path_reset_defaults(struct xkb_context *ctx)
{
xkb_context_include_path_clear(ctx);
return xkb_context_include_path_append_default(ctx);
}
/**
* Returns the number of entries in the context's include path.
*/
XKB_EXPORT unsigned int
xkb_context_num_include_paths(struct xkb_context *ctx)
{
return darray_size(ctx->includes);
}
/**
* Returns the given entry in the context's include path, or NULL if an
* invalid index is passed.
*/
XKB_EXPORT const char *
xkb_context_include_path_get(struct xkb_context *ctx, unsigned int idx)
{
if (idx >= xkb_context_num_include_paths(ctx))
return NULL;
return darray_item(ctx->includes, idx);
}
/**
* Take a new reference on the context.
*/
XKB_EXPORT struct xkb_context *
xkb_context_ref(struct xkb_context *ctx)
{
ctx->refcnt++;
return ctx;
}
/**
* Drop an existing reference on the context, and free it if the refcnt is
* now 0.
*/
XKB_EXPORT void
xkb_context_unref(struct xkb_context *ctx)
{
if (!ctx || --ctx->refcnt > 0)
return;
xkb_context_include_path_clear(ctx);
atom_table_free(ctx->atom_table);
free(ctx);
}
static const char *
log_level_to_prefix(enum xkb_log_level level)
{
switch (level) {
case XKB_LOG_LEVEL_DEBUG:
return "xkbcommon: DEBUG: ";
case XKB_LOG_LEVEL_INFO:
return "xkbcommon: INFO: ";
case XKB_LOG_LEVEL_WARNING:
return "xkbcommon: WARNING: ";
case XKB_LOG_LEVEL_ERROR:
return "xkbcommon: ERROR: ";
case XKB_LOG_LEVEL_CRITICAL:
return "xkbcommon: CRITICAL: ";
default:
return NULL;
}
}
ATTR_PRINTF(3, 0) static void
default_log_fn(struct xkb_context *ctx, enum xkb_log_level level,
const char *fmt, va_list args)
{
const char *prefix = log_level_to_prefix(level);
if (prefix)
fprintf(stderr, "%s", prefix);
vfprintf(stderr, fmt, args);
}
static enum xkb_log_level
log_level(const char *level) {
char *endptr;
enum xkb_log_level lvl;
errno = 0;
lvl = strtol(level, &endptr, 10);
if (errno == 0 && (endptr[0] == '\0' || is_space(endptr[0])))
return lvl;
if (istreq_prefix("crit", level))
return XKB_LOG_LEVEL_CRITICAL;
if (istreq_prefix("err", level))
return XKB_LOG_LEVEL_ERROR;
if (istreq_prefix("warn", level))
return XKB_LOG_LEVEL_WARNING;
if (istreq_prefix("info", level))
return XKB_LOG_LEVEL_INFO;
if (istreq_prefix("debug", level) || istreq_prefix("dbg", level))
return XKB_LOG_LEVEL_DEBUG;
return XKB_LOG_LEVEL_ERROR;
}
static int
log_verbosity(const char *verbosity) {
char *endptr;
int v;
errno = 0;
v = strtol(verbosity, &endptr, 10);
if (errno == 0)
return v;
return 0;
}
/**
* Create a new context.
*/
XKB_EXPORT struct xkb_context *
xkb_context_new(enum xkb_context_flags flags)
{
const char *env;
struct xkb_context *ctx = calloc(1, sizeof(*ctx));
if (!ctx)
return NULL;
ctx->refcnt = 1;
ctx->log_fn = default_log_fn;
ctx->log_level = XKB_LOG_LEVEL_ERROR;
ctx->log_verbosity = 0;
/* Environment overwrites defaults. */
env = secure_getenv("XKB_LOG_LEVEL");
if (env)
xkb_context_set_log_level(ctx, log_level(env));
env = secure_getenv("XKB_LOG_VERBOSITY");
if (env)
xkb_context_set_log_verbosity(ctx, log_verbosity(env));
if (!(flags & XKB_CONTEXT_NO_DEFAULT_INCLUDES) &&
!xkb_context_include_path_append_default(ctx)) {
log_err(ctx, "failed to add default include path %s\n",
DFLT_XKB_CONFIG_ROOT);
xkb_context_unref(ctx);
return NULL;
}
ctx->use_environment_names = !(flags & XKB_CONTEXT_NO_ENVIRONMENT_NAMES);
ctx->atom_table = atom_table_new();
if (!ctx->atom_table) {
xkb_context_unref(ctx);
return NULL;
}
return ctx;
}
XKB_EXPORT void
xkb_context_set_log_fn(struct xkb_context *ctx,
void (*log_fn)(struct xkb_context *ctx,
enum xkb_log_level level,
const char *fmt, va_list args))
{
ctx->log_fn = (log_fn ? log_fn : default_log_fn);
}
XKB_EXPORT enum xkb_log_level
xkb_context_get_log_level(struct xkb_context *ctx)
{
return ctx->log_level;
}
XKB_EXPORT void
xkb_context_set_log_level(struct xkb_context *ctx, enum xkb_log_level level)
{
ctx->log_level = level;
}
XKB_EXPORT int
xkb_context_get_log_verbosity(struct xkb_context *ctx)
{
return ctx->log_verbosity;
}
XKB_EXPORT void
xkb_context_set_log_verbosity(struct xkb_context *ctx, int verbosity)
{
ctx->log_verbosity = verbosity;
}
XKB_EXPORT void *
xkb_context_get_user_data(struct xkb_context *ctx)
{
if (ctx)
return ctx->user_data;
return NULL;
}
XKB_EXPORT void
xkb_context_set_user_data(struct xkb_context *ctx, void *user_data)
{
ctx->user_data = user_data;
}

View File

@ -1,127 +0,0 @@
/*
* Copyright © 2012 Intel Corporation
*
* 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 (including the next
* paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
*
* Author: Daniel Stone <daniel@fooishbar.org>
*/
#ifndef CONTEXT_H
#define CONTEXT_H
#include "atom.h"
struct xkb_context {
int refcnt;
ATTR_PRINTF(3, 0) void (*log_fn)(struct xkb_context *ctx,
enum xkb_log_level level,
const char *fmt, va_list args);
enum xkb_log_level log_level;
int log_verbosity;
void *user_data;
struct xkb_rule_names names_dflt;
darray(char *) includes;
darray(char *) failed_includes;
struct atom_table *atom_table;
/* Buffer for the *Text() functions. */
char text_buffer[2048];
size_t text_next;
unsigned int use_environment_names : 1;
};
unsigned int
xkb_context_num_failed_include_paths(struct xkb_context *ctx);
const char *
xkb_context_failed_include_path_get(struct xkb_context *ctx,
unsigned int idx);
/*
* Returns XKB_ATOM_NONE if @string was not previously interned,
* otherwise returns the atom.
*/
xkb_atom_t
xkb_atom_lookup(struct xkb_context *ctx, const char *string);
xkb_atom_t
xkb_atom_intern(struct xkb_context *ctx, const char *string, size_t len);
#define xkb_atom_intern_literal(ctx, literal) \
xkb_atom_intern((ctx), (literal), sizeof(literal) - 1)
/**
* If @string is dynamically allocated, NUL-terminated, free'd immediately
* after being interned, and not used afterwards, use this function
* instead of xkb_atom_intern to avoid some unnecessary allocations.
* The caller should not use or free the passed in string afterwards.
*/
xkb_atom_t
xkb_atom_steal(struct xkb_context *ctx, char *string);
const char *
xkb_atom_text(struct xkb_context *ctx, xkb_atom_t atom);
char *
xkb_context_get_buffer(struct xkb_context *ctx, size_t size);
ATTR_PRINTF(4, 5) void
xkb_log(struct xkb_context *ctx, enum xkb_log_level level, int verbosity,
const char *fmt, ...);
void
xkb_context_sanitize_rule_names(struct xkb_context *ctx,
struct xkb_rule_names *rmlvo);
/*
* The format is not part of the argument list in order to avoid the
* "ISO C99 requires rest arguments to be used" warning when only the
* format is supplied without arguments. Not supplying it would still
* result in an error, though.
*/
#define log_dbg(ctx, ...) \
xkb_log((ctx), XKB_LOG_LEVEL_DEBUG, 0, __VA_ARGS__)
#define log_info(ctx, ...) \
xkb_log((ctx), XKB_LOG_LEVEL_INFO, 0, __VA_ARGS__)
#define log_warn(ctx, ...) \
xkb_log((ctx), XKB_LOG_LEVEL_WARNING, 0, __VA_ARGS__)
#define log_err(ctx, ...) \
xkb_log((ctx), XKB_LOG_LEVEL_ERROR, 0, __VA_ARGS__)
#define log_wsgo(ctx, ...) \
xkb_log((ctx), XKB_LOG_LEVEL_CRITICAL, 0, __VA_ARGS__)
#define log_vrb(ctx, vrb, ...) \
xkb_log((ctx), XKB_LOG_LEVEL_WARNING, (vrb), __VA_ARGS__)
/*
* Variants which are prefixed by the name of the function they're
* called from.
* Here we must have the silly 1 variant.
*/
#define log_err_func(ctx, fmt, ...) \
log_err(ctx, "%s: " fmt, __func__, __VA_ARGS__)
#define log_err_func1(ctx, fmt) \
log_err(ctx, "%s: " fmt, __func__)
#endif

View File

@ -1,209 +0,0 @@
/*
* Copyright (C) 2011 Joseph Adams <joeyadams3.14159@gmail.com>
*
* 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
* AUTHORS OR COPYRIGHT HOLDERS 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.
*/
#ifndef CCAN_DARRAY_H
#define CCAN_DARRAY_H
/* Originally taken from: https://ccodearchive.net/info/darray.html
* But modified for libxkbcommon. */
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <limits.h>
#define darray(type) struct { type *item; unsigned size; unsigned alloc; }
#define darray_new() { 0, 0, 0 }
#define darray_init(arr) do { \
(arr).item = 0; (arr).size = 0; (arr).alloc = 0; \
} while (0)
#define darray_free(arr) do { \
free((arr).item); \
darray_init(arr); \
} while (0)
#define darray_steal(arr, to, to_size) do { \
*(to) = (arr).item; \
if (to_size) \
*(unsigned int *) (to_size) = (arr).size; \
darray_init(arr); \
} while (0)
/*
* Typedefs for darrays of common types. These are useful
* when you want to pass a pointer to an darray(T) around.
*
* The following will produce an incompatible pointer warning:
*
* void foo(darray(int) *arr);
* darray(int) arr = darray_new();
* foo(&arr);
*
* The workaround:
*
* void foo(darray_int *arr);
* darray_int arr = darray_new();
* foo(&arr);
*/
typedef darray (char) darray_char;
typedef darray (signed char) darray_schar;
typedef darray (unsigned char) darray_uchar;
typedef darray (short) darray_short;
typedef darray (int) darray_int;
typedef darray (long) darray_long;
typedef darray (unsigned short) darray_ushort;
typedef darray (unsigned int) darray_uint;
typedef darray (unsigned long) darray_ulong;
/*** Access ***/
#define darray_item(arr, i) ((arr).item[i])
#define darray_size(arr) ((arr).size)
#define darray_empty(arr) ((arr).size == 0)
/*** Insertion (single item) ***/
#define darray_append(arr, ...) do { \
darray_resize(arr, (arr).size + 1); \
(arr).item[(arr).size - 1] = (__VA_ARGS__); \
} while (0)
/*** Insertion (multiple items) ***/
#define darray_append_items(arr, items, count) do { \
unsigned __count = (count), __oldSize = (arr).size; \
darray_resize(arr, __oldSize + __count); \
memcpy((arr).item + __oldSize, items, __count * sizeof(*(arr).item)); \
} while (0)
#define darray_from_items(arr, items, count) do { \
unsigned __count = (count); \
darray_resize(arr, __count); \
if (__count != 0) \
memcpy((arr).item, items, __count * sizeof(*(arr).item)); \
} while (0)
#define darray_copy(arr_to, arr_from) \
darray_from_items((arr_to), (arr_from).item, (arr_from).size)
#define darray_concat(arr_to, arr_from) \
darray_append_items((arr_to), (arr_from).item, (arr_from).size)
/*** String buffer ***/
#define darray_append_string(arr, str) do { \
const char *__str = (str); \
darray_append_items(arr, __str, strlen(__str) + 1); \
(arr).size--; \
} while (0)
#define darray_append_lit(arr, stringLiteral) do { \
darray_append_items(arr, stringLiteral, sizeof(stringLiteral)); \
(arr).size--; \
} while (0)
#define darray_appends_nullterminate(arr, items, count) do { \
unsigned __count = (count), __oldSize = (arr).size; \
darray_resize(arr, __oldSize + __count + 1); \
memcpy((arr).item + __oldSize, items, __count * sizeof(*(arr).item)); \
(arr).item[--(arr).size] = 0; \
} while (0)
#define darray_prepends_nullterminate(arr, items, count) do { \
unsigned __count = (count), __oldSize = (arr).size; \
darray_resize(arr, __count + __oldSize + 1); \
memmove((arr).item + __count, (arr).item, \
__oldSize * sizeof(*(arr).item)); \
memcpy((arr).item, items, __count * sizeof(*(arr).item)); \
(arr).item[--(arr).size] = 0; \
} while (0)
/*** Size management ***/
#define darray_resize(arr, newSize) \
darray_growalloc(arr, (arr).size = (newSize))
#define darray_resize0(arr, newSize) do { \
unsigned __oldSize = (arr).size, __newSize = (newSize); \
(arr).size = __newSize; \
if (__newSize > __oldSize) { \
darray_growalloc(arr, __newSize); \
memset(&(arr).item[__oldSize], 0, \
(__newSize - __oldSize) * sizeof(*(arr).item)); \
} \
} while (0)
#define darray_realloc(arr, newAlloc) do { \
(arr).item = realloc((arr).item, \
((arr).alloc = (newAlloc)) * sizeof(*(arr).item)); \
} while (0)
#define darray_growalloc(arr, need) do { \
unsigned __need = (need); \
if (__need > (arr).alloc) \
darray_realloc(arr, darray_next_alloc((arr).alloc, __need, \
sizeof(*(arr).item))); \
} while (0)
#define darray_shrink(arr) do { \
if ((arr).size > 0) \
(arr).item = realloc((arr).item, \
((arr).alloc = (arr).size) * sizeof(*(arr).item)); \
} while (0)
static inline unsigned
darray_next_alloc(unsigned alloc, unsigned need, unsigned itemSize)
{
assert(need < UINT_MAX / itemSize / 2); /* Overflow. */
if (alloc == 0)
alloc = 4;
while (alloc < need)
alloc *= 2;
return alloc;
}
/*** Traversal ***/
#define darray_foreach(i, arr) \
for ((i) = &(arr).item[0]; (i) < &(arr).item[(arr).size]; (i)++)
#define darray_foreach_from(i, arr, from) \
for ((i) = &(arr).item[from]; (i) < &(arr).item[(arr).size]; (i)++)
/* Iterate on index and value at the same time, like Python's enumerate. */
#define darray_enumerate(idx, val, arr) \
for ((idx) = 0, (val) = &(arr).item[0]; \
(idx) < (arr).size; \
(idx)++, (val)++)
#define darray_enumerate_from(idx, val, arr, from) \
for ((idx) = (from), (val) = &(arr).item[0]; \
(idx) < (arr).size; \
(idx)++, (val)++)
#endif /* CCAN_DARRAY_H */

View File

@ -1,150 +0,0 @@
/**
* Copyright © 2012 Intel Corporation
* Copyright © 2012 Ran Benita <ran234@gmail.com>
*
* 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 (including the next
* paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
*
* Author: Daniel Stone <daniel@fooishbar.org>
*/
#include "keymap.h"
static void
update_builtin_keymap_fields(struct xkb_keymap *keymap)
{
/* Predefined (AKA real, core, X11) modifiers. The order is important! */
static const char *const builtin_mods[] = {
[0] = "Shift",
[1] = "Lock",
[2] = "Control",
[3] = "Mod1",
[4] = "Mod2",
[5] = "Mod3",
[6] = "Mod4",
[7] = "Mod5"
};
for (unsigned i = 0; i < ARRAY_SIZE(builtin_mods); i++) {
keymap->mods.mods[i].name = xkb_atom_intern(keymap->ctx,
builtin_mods[i],
strlen(builtin_mods[i]));
keymap->mods.mods[i].type = MOD_REAL;
}
keymap->mods.num_mods = ARRAY_SIZE(builtin_mods);
}
struct xkb_keymap *
xkb_keymap_new(struct xkb_context *ctx,
enum xkb_keymap_format format,
enum xkb_keymap_compile_flags flags)
{
struct xkb_keymap *keymap;
keymap = calloc(1, sizeof(*keymap));
if (!keymap)
return NULL;
keymap->refcnt = 1;
keymap->ctx = xkb_context_ref(ctx);
keymap->format = format;
keymap->flags = flags;
update_builtin_keymap_fields(keymap);
return keymap;
}
struct xkb_key *
XkbKeyByName(struct xkb_keymap *keymap, xkb_atom_t name, bool use_aliases)
{
struct xkb_key *key;
xkb_keys_foreach(key, keymap)
if (key->name == name)
return key;
if (use_aliases) {
xkb_atom_t new_name = XkbResolveKeyAlias(keymap, name);
if (new_name != XKB_ATOM_NONE)
return XkbKeyByName(keymap, new_name, false);
}
return NULL;
}
xkb_atom_t
XkbResolveKeyAlias(const struct xkb_keymap *keymap, xkb_atom_t name)
{
for (unsigned i = 0; i < keymap->num_key_aliases; i++)
if (keymap->key_aliases[i].alias == name)
return keymap->key_aliases[i].real;
return XKB_ATOM_NONE;
}
void
XkbEscapeMapName(char *name)
{
/*
* All latin-1 alphanumerics, plus parens, slash, minus, underscore and
* wildcards.
*/
static const unsigned char legal[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0xa7, 0xff, 0x83,
0xfe, 0xff, 0xff, 0x87, 0xfe, 0xff, 0xff, 0x07,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff
};
if (!name)
return;
while (*name) {
unsigned char c = *name;
if (!(legal[c / 8] & (1 << (c % 8))))
*name = '_';
name++;
}
}
xkb_mod_index_t
XkbModNameToIndex(const struct xkb_mod_set *mods, xkb_atom_t name,
enum mod_type type)
{
xkb_mod_index_t i;
const struct xkb_mod *mod;
xkb_mods_enumerate(i, mod, mods)
if ((mod->type & type) && name == mod->name)
return i;
return XKB_MOD_INVALID;
}
bool
XkbLevelsSameSyms(const struct xkb_level *a, const struct xkb_level *b)
{
if (a->num_syms != b->num_syms)
return false;
if (a->num_syms <= 1)
return a->u.sym == b->u.sym;
return memcmp(a->u.syms, b->u.syms, sizeof(*a->u.syms) * a->num_syms) == 0;
}

View File

@ -1,519 +0,0 @@
/**
* Copyright © 2012 Intel Corporation
* Copyright © 2012 Ran Benita <ran234@gmail.com>
*
* 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 (including the next
* paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
*
* Author: Daniel Stone <daniel@fooishbar.org>
*/
/************************************************************
* Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting
* documentation, and that the name of Silicon Graphics not be
* used in advertising or publicity pertaining to distribution
* of the software without specific prior written permission.
* Silicon Graphics makes no representation about the suitability
* of this software for any purpose. It is provided "as is"
* without any express or implied warranty.
*
* SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
* GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* ********************************************************/
#include "keymap.h"
#include "text.h"
XKB_EXPORT struct xkb_keymap *
xkb_keymap_ref(struct xkb_keymap *keymap)
{
keymap->refcnt++;
return keymap;
}
XKB_EXPORT void
xkb_keymap_unref(struct xkb_keymap *keymap)
{
if (!keymap || --keymap->refcnt > 0)
return;
if (keymap->keys) {
struct xkb_key *key;
xkb_keys_foreach(key, keymap) {
if (key->groups) {
for (unsigned i = 0; i < key->num_groups; i++) {
if (key->groups[i].levels) {
for (unsigned j = 0; j < XkbKeyNumLevels(key, i); j++)
if (key->groups[i].levels[j].num_syms > 1)
free(key->groups[i].levels[j].u.syms);
free(key->groups[i].levels);
}
}
free(key->groups);
}
}
free(keymap->keys);
}
if (keymap->types) {
for (unsigned i = 0; i < keymap->num_types; i++) {
free(keymap->types[i].entries);
free(keymap->types[i].level_names);
}
free(keymap->types);
}
free(keymap->sym_interprets);
free(keymap->key_aliases);
free(keymap->group_names);
free(keymap->keycodes_section_name);
free(keymap->symbols_section_name);
free(keymap->types_section_name);
free(keymap->compat_section_name);
xkb_context_unref(keymap->ctx);
free(keymap);
}
static const struct xkb_keymap_format_ops *
get_keymap_format_ops(enum xkb_keymap_format format)
{
static const struct xkb_keymap_format_ops *keymap_format_ops[] = {
[XKB_KEYMAP_FORMAT_TEXT_V1] = &text_v1_keymap_format_ops,
};
if ((int) format < 0 || (int) format >= (int) ARRAY_SIZE(keymap_format_ops))
return NULL;
return keymap_format_ops[(int) format];
}
XKB_EXPORT struct xkb_keymap *
xkb_keymap_new_from_names(struct xkb_context *ctx,
const struct xkb_rule_names *rmlvo_in,
enum xkb_keymap_compile_flags flags)
{
struct xkb_keymap *keymap;
struct xkb_rule_names rmlvo;
const enum xkb_keymap_format format = XKB_KEYMAP_FORMAT_TEXT_V1;
const struct xkb_keymap_format_ops *ops;
ops = get_keymap_format_ops(format);
if (!ops || !ops->keymap_new_from_names) {
log_err_func(ctx, "unsupported keymap format: %d\n", format);
return NULL;
}
if (flags & ~(XKB_KEYMAP_COMPILE_NO_FLAGS)) {
log_err_func(ctx, "unrecognized flags: %#x\n", flags);
return NULL;
}
keymap = xkb_keymap_new(ctx, format, flags);
if (!keymap)
return NULL;
if (rmlvo_in)
rmlvo = *rmlvo_in;
else
memset(&rmlvo, 0, sizeof(rmlvo));
xkb_context_sanitize_rule_names(ctx, &rmlvo);
if (!ops->keymap_new_from_names(keymap, &rmlvo)) {
xkb_keymap_unref(keymap);
return NULL;
}
return keymap;
}
XKB_EXPORT struct xkb_keymap *
xkb_keymap_new_from_string(struct xkb_context *ctx,
const char *string,
enum xkb_keymap_format format,
enum xkb_keymap_compile_flags flags)
{
return xkb_keymap_new_from_buffer(ctx, string, strlen(string),
format, flags);
}
XKB_EXPORT struct xkb_keymap *
xkb_keymap_new_from_buffer(struct xkb_context *ctx,
const char *buffer, size_t length,
enum xkb_keymap_format format,
enum xkb_keymap_compile_flags flags)
{
struct xkb_keymap *keymap;
const struct xkb_keymap_format_ops *ops;
ops = get_keymap_format_ops(format);
if (!ops || !ops->keymap_new_from_string) {
log_err_func(ctx, "unsupported keymap format: %d\n", format);
return NULL;
}
if (flags & ~(XKB_KEYMAP_COMPILE_NO_FLAGS)) {
log_err_func(ctx, "unrecognized flags: %#x\n", flags);
return NULL;
}
if (!buffer) {
log_err_func1(ctx, "no buffer specified\n");
return NULL;
}
keymap = xkb_keymap_new(ctx, format, flags);
if (!keymap)
return NULL;
if (!ops->keymap_new_from_string(keymap, buffer, length)) {
xkb_keymap_unref(keymap);
return NULL;
}
return keymap;
}
XKB_EXPORT struct xkb_keymap *
xkb_keymap_new_from_file(struct xkb_context *ctx,
FILE *file,
enum xkb_keymap_format format,
enum xkb_keymap_compile_flags flags)
{
struct xkb_keymap *keymap;
const struct xkb_keymap_format_ops *ops;
ops = get_keymap_format_ops(format);
if (!ops || !ops->keymap_new_from_file) {
log_err_func(ctx, "unsupported keymap format: %d\n", format);
return NULL;
}
if (flags & ~(XKB_KEYMAP_COMPILE_NO_FLAGS)) {
log_err_func(ctx, "unrecognized flags: %#x\n", flags);
return NULL;
}
if (!file) {
log_err_func1(ctx, "no file specified\n");
return NULL;
}
keymap = xkb_keymap_new(ctx, format, flags);
if (!keymap)
return NULL;
if (!ops->keymap_new_from_file(keymap, file)) {
xkb_keymap_unref(keymap);
return NULL;
}
return keymap;
}
XKB_EXPORT char *
xkb_keymap_get_as_string(struct xkb_keymap *keymap,
enum xkb_keymap_format format)
{
const struct xkb_keymap_format_ops *ops;
if (format == XKB_KEYMAP_USE_ORIGINAL_FORMAT)
format = keymap->format;
ops = get_keymap_format_ops(format);
if (!ops || !ops->keymap_get_as_string) {
log_err_func(keymap->ctx, "unsupported keymap format: %d\n", format);
return NULL;
}
return ops->keymap_get_as_string(keymap);
}
/**
* Returns the total number of modifiers active in the keymap.
*/
XKB_EXPORT xkb_mod_index_t
xkb_keymap_num_mods(struct xkb_keymap *keymap)
{
return keymap->mods.num_mods;
}
/**
* Return the name for a given modifier.
*/
XKB_EXPORT const char *
xkb_keymap_mod_get_name(struct xkb_keymap *keymap, xkb_mod_index_t idx)
{
if (idx >= keymap->mods.num_mods)
return NULL;
return xkb_atom_text(keymap->ctx, keymap->mods.mods[idx].name);
}
/**
* Returns the index for a named modifier.
*/
XKB_EXPORT xkb_mod_index_t
xkb_keymap_mod_get_index(struct xkb_keymap *keymap, const char *name)
{
xkb_atom_t atom;
atom = xkb_atom_lookup(keymap->ctx, name);
if (atom == XKB_ATOM_NONE)
return XKB_MOD_INVALID;
return XkbModNameToIndex(&keymap->mods, atom, MOD_BOTH);
}
/**
* Return the total number of active groups in the keymap.
*/
XKB_EXPORT xkb_layout_index_t
xkb_keymap_num_layouts(struct xkb_keymap *keymap)
{
return keymap->num_groups;
}
/**
* Returns the name for a given group.
*/
XKB_EXPORT const char *
xkb_keymap_layout_get_name(struct xkb_keymap *keymap, xkb_layout_index_t idx)
{
if (idx >= keymap->num_group_names)
return NULL;
return xkb_atom_text(keymap->ctx, keymap->group_names[idx]);
}
/**
* Returns the index for a named layout.
*/
XKB_EXPORT xkb_layout_index_t
xkb_keymap_layout_get_index(struct xkb_keymap *keymap, const char *name)
{
xkb_atom_t atom = xkb_atom_lookup(keymap->ctx, name);
xkb_layout_index_t i;
if (atom == XKB_ATOM_NONE)
return XKB_LAYOUT_INVALID;
for (i = 0; i < keymap->num_group_names; i++)
if (keymap->group_names[i] == atom)
return i;
return XKB_LAYOUT_INVALID;
}
/**
* Returns the number of layouts active for a particular key.
*/
XKB_EXPORT xkb_layout_index_t
xkb_keymap_num_layouts_for_key(struct xkb_keymap *keymap, xkb_keycode_t kc)
{
const struct xkb_key *key = XkbKey(keymap, kc);
if (!key)
return 0;
return key->num_groups;
}
/**
* Returns the number of levels active for a particular key and layout.
*/
XKB_EXPORT xkb_level_index_t
xkb_keymap_num_levels_for_key(struct xkb_keymap *keymap, xkb_keycode_t kc,
xkb_layout_index_t layout)
{
const struct xkb_key *key = XkbKey(keymap, kc);
if (!key)
return 0;
layout = XkbWrapGroupIntoRange(layout, key->num_groups,
key->out_of_range_group_action,
key->out_of_range_group_number);
if (layout == XKB_LAYOUT_INVALID)
return 0;
return XkbKeyNumLevels(key, layout);
}
/**
* Return the total number of LEDs in the keymap.
*/
XKB_EXPORT xkb_led_index_t
xkb_keymap_num_leds(struct xkb_keymap *keymap)
{
return keymap->num_leds;
}
/**
* Returns the name for a given LED.
*/
XKB_EXPORT const char *
xkb_keymap_led_get_name(struct xkb_keymap *keymap, xkb_led_index_t idx)
{
if (idx >= keymap->num_leds)
return NULL;
return xkb_atom_text(keymap->ctx, keymap->leds[idx].name);
}
/**
* Returns the index for a named LED.
*/
XKB_EXPORT xkb_led_index_t
xkb_keymap_led_get_index(struct xkb_keymap *keymap, const char *name)
{
xkb_atom_t atom = xkb_atom_lookup(keymap->ctx, name);
xkb_led_index_t i;
const struct xkb_led *led;
if (atom == XKB_ATOM_NONE)
return XKB_LED_INVALID;
xkb_leds_enumerate(i, led, keymap)
if (led->name == atom)
return i;
return XKB_LED_INVALID;
}
/**
* As below, but takes an explicit layout/level rather than state.
*/
XKB_EXPORT int
xkb_keymap_key_get_syms_by_level(struct xkb_keymap *keymap,
xkb_keycode_t kc,
xkb_layout_index_t layout,
xkb_level_index_t level,
const xkb_keysym_t **syms_out)
{
const struct xkb_key *key = XkbKey(keymap, kc);
int num_syms;
if (!key)
goto err;
layout = XkbWrapGroupIntoRange(layout, key->num_groups,
key->out_of_range_group_action,
key->out_of_range_group_number);
if (layout == XKB_LAYOUT_INVALID)
goto err;
if (level >= XkbKeyNumLevels(key, layout))
goto err;
num_syms = key->groups[layout].levels[level].num_syms;
if (num_syms == 0)
goto err;
if (num_syms == 1)
*syms_out = &key->groups[layout].levels[level].u.sym;
else
*syms_out = key->groups[layout].levels[level].u.syms;
return num_syms;
err:
*syms_out = NULL;
return 0;
}
XKB_EXPORT xkb_keycode_t
xkb_keymap_min_keycode(struct xkb_keymap *keymap)
{
return keymap->min_key_code;
}
XKB_EXPORT xkb_keycode_t
xkb_keymap_max_keycode(struct xkb_keymap *keymap)
{
return keymap->max_key_code;
}
XKB_EXPORT void
xkb_keymap_key_for_each(struct xkb_keymap *keymap, xkb_keymap_key_iter_t iter,
void *data)
{
struct xkb_key *key;
xkb_keys_foreach(key, keymap)
iter(keymap, key->keycode, data);
}
XKB_EXPORT const char *
xkb_keymap_key_get_name(struct xkb_keymap *keymap, xkb_keycode_t kc)
{
const struct xkb_key *key = XkbKey(keymap, kc);
if (!key)
return NULL;
return xkb_atom_text(keymap->ctx, key->name);
}
XKB_EXPORT xkb_keycode_t
xkb_keymap_key_by_name(struct xkb_keymap *keymap, const char *name)
{
struct xkb_key *key;
xkb_atom_t atom;
atom = xkb_atom_lookup(keymap->ctx, name);
if (atom) {
xkb_atom_t ratom = XkbResolveKeyAlias(keymap, atom);
if (ratom)
atom = ratom;
}
if (!atom)
return XKB_KEYCODE_INVALID;
xkb_keys_foreach(key, keymap) {
if (key->name == atom)
return key->keycode;
}
return XKB_KEYCODE_INVALID;
}
/**
* Simple boolean specifying whether or not the key should repeat.
*/
XKB_EXPORT int
xkb_keymap_key_repeats(struct xkb_keymap *keymap, xkb_keycode_t kc)
{
const struct xkb_key *key = XkbKey(keymap, kc);
if (!key)
return 0;
return key->repeats;
}

View File

@ -1,482 +0,0 @@
/*
* Copyright 1985, 1987, 1990, 1998 The Open Group
*
* 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
* AUTHORS 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 names of the authors or their
* institutions 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 authors.
*/
/************************************************************
* Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting
* documentation, and that the name of Silicon Graphics not be
* used in advertising or publicity pertaining to distribution
* of the software without specific prior written permission.
* Silicon Graphics makes no representation about the suitability
* of this software for any purpose. It is provided "as is"
* without any express or implied warranty.
*
* SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
* GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
********************************************************/
/*
* Copyright © 2009 Dan Nicholson
* Copyright © 2012 Intel Corporation
* Copyright © 2012 Ran Benita
*
* 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 (including the next
* paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
*
* Author: Daniel Stone <daniel@fooishbar.org>
* Dan Nicholson <dbn.lists@gmail.com>
*/
#ifndef KEYMAP_H
#define KEYMAP_H
/* Don't use compat names in internal code. */
#define _XKBCOMMON_COMPAT_H
#include "xkbcommon/xkbcommon.h"
#include "utils.h"
#include "context.h"
/* This limit is artificially enforced, we do not depend on it any where.
* The reason it's still here is that the rules file format does not
* support multiple groups very well, and the rules shipped with
* xkeyboard-config (see rules/evdev) depend on this limit extensively.
* So just lifting this limit would cause problems for people who will use
* more than 4 layouts.
* TODO: Fix the group index syntax in the rules format, preferably in a
* backwards compatible way.
* See e.g. https://bugs.freedesktop.org/show_bug.cgi?id=14372
* Note: A limit on the number of groups we *do* depend on is imposed by
* the size of the xkb_layout_mask_t type (32). This is more than enough
* though.
*/
#define XKB_MAX_GROUPS 4
/* Don't allow more modifiers than we can hold in xkb_mod_mask_t. */
#define XKB_MAX_MODS ((xkb_mod_index_t) (sizeof(xkb_mod_mask_t) * 8))
/* Don't allow more leds than we can hold in xkb_led_mask_t. */
#define XKB_MAX_LEDS ((xkb_led_index_t) (sizeof(xkb_led_mask_t) * 8))
/* These should all go away. */
enum mod_type {
MOD_REAL = (1 << 0),
MOD_VIRT = (1 << 1),
MOD_BOTH = (MOD_REAL | MOD_VIRT),
};
#define MOD_REAL_MASK_ALL ((xkb_mod_mask_t) 0x000000ff)
enum xkb_action_type {
ACTION_TYPE_NONE = 0,
ACTION_TYPE_MOD_SET,
ACTION_TYPE_MOD_LATCH,
ACTION_TYPE_MOD_LOCK,
ACTION_TYPE_GROUP_SET,
ACTION_TYPE_GROUP_LATCH,
ACTION_TYPE_GROUP_LOCK,
ACTION_TYPE_PTR_MOVE,
ACTION_TYPE_PTR_BUTTON,
ACTION_TYPE_PTR_LOCK,
ACTION_TYPE_PTR_DEFAULT,
ACTION_TYPE_TERMINATE,
ACTION_TYPE_SWITCH_VT,
ACTION_TYPE_CTRL_SET,
ACTION_TYPE_CTRL_LOCK,
ACTION_TYPE_PRIVATE,
_ACTION_TYPE_NUM_ENTRIES
};
enum xkb_action_flags {
ACTION_LOCK_CLEAR = (1 << 0),
ACTION_LATCH_TO_LOCK = (1 << 1),
ACTION_LOCK_NO_LOCK = (1 << 2),
ACTION_LOCK_NO_UNLOCK = (1 << 3),
ACTION_MODS_LOOKUP_MODMAP = (1 << 4),
ACTION_ABSOLUTE_SWITCH = (1 << 5),
ACTION_ABSOLUTE_X = (1 << 6),
ACTION_ABSOLUTE_Y = (1 << 7),
ACTION_ACCEL = (1 << 8),
ACTION_SAME_SCREEN = (1 << 9),
};
enum xkb_action_controls {
CONTROL_REPEAT = (1 << 0),
CONTROL_SLOW = (1 << 1),
CONTROL_DEBOUNCE = (1 << 2),
CONTROL_STICKY = (1 << 3),
CONTROL_MOUSEKEYS = (1 << 4),
CONTROL_MOUSEKEYS_ACCEL = (1 << 5),
CONTROL_AX = (1 << 6),
CONTROL_AX_TIMEOUT = (1 << 7),
CONTROL_AX_FEEDBACK = (1 << 8),
CONTROL_BELL = (1 << 9),
CONTROL_IGNORE_GROUP_LOCK = (1 << 10),
CONTROL_ALL = \
(CONTROL_REPEAT | CONTROL_SLOW | CONTROL_DEBOUNCE | CONTROL_STICKY | \
CONTROL_MOUSEKEYS | CONTROL_MOUSEKEYS_ACCEL | CONTROL_AX | \
CONTROL_AX_TIMEOUT | CONTROL_AX_FEEDBACK | CONTROL_BELL | \
CONTROL_IGNORE_GROUP_LOCK)
};
enum xkb_match_operation {
MATCH_NONE,
MATCH_ANY_OR_NONE,
MATCH_ANY,
MATCH_ALL,
MATCH_EXACTLY,
};
struct xkb_mods {
xkb_mod_mask_t mods; /* original real+virtual mods in definition */
xkb_mod_mask_t mask; /* computed effective mask */
};
struct xkb_mod_action {
enum xkb_action_type type;
enum xkb_action_flags flags;
struct xkb_mods mods;
};
struct xkb_group_action {
enum xkb_action_type type;
enum xkb_action_flags flags;
int32_t group;
};
struct xkb_controls_action {
enum xkb_action_type type;
enum xkb_action_flags flags;
enum xkb_action_controls ctrls;
};
struct xkb_pointer_default_action {
enum xkb_action_type type;
enum xkb_action_flags flags;
int8_t value;
};
struct xkb_switch_screen_action {
enum xkb_action_type type;
enum xkb_action_flags flags;
int8_t screen;
};
struct xkb_pointer_action {
enum xkb_action_type type;
enum xkb_action_flags flags;
int16_t x;
int16_t y;
};
struct xkb_pointer_button_action {
enum xkb_action_type type;
enum xkb_action_flags flags;
uint8_t count;
uint8_t button;
};
struct xkb_private_action {
enum xkb_action_type type;
uint8_t data[7];
};
union xkb_action {
enum xkb_action_type type;
struct xkb_mod_action mods;
struct xkb_group_action group;
struct xkb_controls_action ctrls;
struct xkb_pointer_default_action dflt;
struct xkb_switch_screen_action screen;
struct xkb_pointer_action ptr;
struct xkb_pointer_button_action btn;
struct xkb_private_action priv;
};
struct xkb_key_type_entry {
xkb_level_index_t level;
struct xkb_mods mods;
struct xkb_mods preserve;
};
struct xkb_key_type {
xkb_atom_t name;
struct xkb_mods mods;
xkb_level_index_t num_levels;
unsigned int num_level_names;
xkb_atom_t *level_names;
unsigned int num_entries;
struct xkb_key_type_entry *entries;
};
struct xkb_sym_interpret {
xkb_keysym_t sym;
enum xkb_match_operation match;
xkb_mod_mask_t mods;
xkb_mod_index_t virtual_mod;
union xkb_action action;
bool level_one_only;
bool repeat;
};
struct xkb_led {
xkb_atom_t name;
enum xkb_state_component which_groups;
xkb_layout_mask_t groups;
enum xkb_state_component which_mods;
struct xkb_mods mods;
enum xkb_action_controls ctrls;
};
struct xkb_key_alias {
xkb_atom_t real;
xkb_atom_t alias;
};
struct xkb_controls {
unsigned char groups_wrap;
struct xkb_mods internal;
struct xkb_mods ignore_lock;
unsigned short repeat_delay;
unsigned short repeat_interval;
unsigned short slow_keys_delay;
unsigned short debounce_delay;
unsigned short ax_options;
unsigned short ax_timeout;
unsigned short axt_opts_mask;
unsigned short axt_opts_values;
unsigned int axt_ctrls_mask;
unsigned int axt_ctrls_values;
};
/* Such an awkward name. Oh well. */
enum xkb_range_exceed_type {
RANGE_WRAP = 0,
RANGE_SATURATE,
RANGE_REDIRECT,
};
enum xkb_explicit_components {
EXPLICIT_INTERP = (1 << 0),
EXPLICIT_VMODMAP = (1 << 1),
EXPLICIT_REPEAT = (1 << 2),
};
struct xkb_level {
union xkb_action action;
unsigned int num_syms;
union {
xkb_keysym_t sym; /* num_syms == 1 */
xkb_keysym_t *syms; /* num_syms > 1 */
} u;
};
struct xkb_group {
bool explicit_type;
/* Points to a type in keymap->types. */
const struct xkb_key_type *type;
/* Use XkbKeyNumLevels for the number of levels. */
struct xkb_level *levels;
};
struct xkb_key {
xkb_keycode_t keycode;
xkb_atom_t name;
enum xkb_explicit_components explicit;
xkb_mod_mask_t modmap;
xkb_mod_mask_t vmodmap;
bool repeats;
enum xkb_range_exceed_type out_of_range_group_action;
xkb_layout_index_t out_of_range_group_number;
xkb_layout_index_t num_groups;
struct xkb_group *groups;
};
struct xkb_mod {
xkb_atom_t name;
enum mod_type type;
xkb_mod_mask_t mapping; /* vmod -> real mod mapping */
};
struct xkb_mod_set {
struct xkb_mod mods[XKB_MAX_MODS];
unsigned int num_mods;
};
/* Common keyboard description structure */
struct xkb_keymap {
struct xkb_context *ctx;
int refcnt;
enum xkb_keymap_compile_flags flags;
enum xkb_keymap_format format;
enum xkb_action_controls enabled_ctrls;
xkb_keycode_t min_key_code;
xkb_keycode_t max_key_code;
struct xkb_key *keys;
/* aliases in no particular order */
unsigned int num_key_aliases;
struct xkb_key_alias *key_aliases;
struct xkb_key_type *types;
unsigned int num_types;
unsigned int num_sym_interprets;
struct xkb_sym_interpret *sym_interprets;
struct xkb_mod_set mods;
/* Number of groups in the key with the most groups. */
xkb_layout_index_t num_groups;
/* Not all groups must have names. */
xkb_layout_index_t num_group_names;
xkb_atom_t *group_names;
struct xkb_led leds[XKB_MAX_LEDS];
unsigned int num_leds;
char *keycodes_section_name;
char *symbols_section_name;
char *types_section_name;
char *compat_section_name;
};
#define xkb_keys_foreach(iter, keymap) \
for ((iter) = (keymap)->keys + (keymap)->min_key_code; \
(iter) <= (keymap)->keys + (keymap)->max_key_code; \
(iter)++)
#define xkb_mods_foreach(iter, mods_) \
for ((iter) = (mods_)->mods; \
(iter) < (mods_)->mods + (mods_)->num_mods; \
(iter)++)
#define xkb_mods_enumerate(idx, iter, mods_) \
for ((idx) = 0, (iter) = (mods_)->mods; \
(idx) < (mods_)->num_mods; \
(idx)++, (iter)++)
#define xkb_leds_foreach(iter, keymap) \
for ((iter) = (keymap)->leds; \
(iter) < (keymap)->leds + (keymap)->num_leds; \
(iter)++)
#define xkb_leds_enumerate(idx, iter, keymap) \
for ((idx) = 0, (iter) = (keymap)->leds; \
(idx) < (keymap)->num_leds; \
(idx)++, (iter)++)
static inline const struct xkb_key *
XkbKey(struct xkb_keymap *keymap, xkb_keycode_t kc)
{
if (kc < keymap->min_key_code || kc > keymap->max_key_code)
return NULL;
return &keymap->keys[kc];
}
static inline xkb_level_index_t
XkbKeyNumLevels(const struct xkb_key *key, xkb_layout_index_t layout)
{
return key->groups[layout].type->num_levels;
}
struct xkb_keymap *
xkb_keymap_new(struct xkb_context *ctx,
enum xkb_keymap_format format,
enum xkb_keymap_compile_flags flags);
struct xkb_key *
XkbKeyByName(struct xkb_keymap *keymap, xkb_atom_t name, bool use_aliases);
xkb_atom_t
XkbResolveKeyAlias(const struct xkb_keymap *keymap, xkb_atom_t name);
void
XkbEscapeMapName(char *name);
xkb_mod_index_t
XkbModNameToIndex(const struct xkb_mod_set *mods, xkb_atom_t name,
enum mod_type type);
bool
XkbLevelsSameSyms(const struct xkb_level *a, const struct xkb_level *b);
xkb_layout_index_t
XkbWrapGroupIntoRange(int32_t group,
xkb_layout_index_t num_groups,
enum xkb_range_exceed_type out_of_range_group_action,
xkb_layout_index_t out_of_range_group_number);
xkb_mod_mask_t
mod_mask_get_effective(struct xkb_keymap *keymap, xkb_mod_mask_t mods);
struct xkb_keymap_format_ops {
bool (*keymap_new_from_names)(struct xkb_keymap *keymap,
const struct xkb_rule_names *names);
bool (*keymap_new_from_string)(struct xkb_keymap *keymap,
const char *string, size_t length);
bool (*keymap_new_from_file)(struct xkb_keymap *keymap, FILE *file);
char *(*keymap_get_as_string)(struct xkb_keymap *keymap);
};
extern const struct xkb_keymap_format_ops text_v1_keymap_format_ops;
#endif

View File

@ -1,937 +0,0 @@
/* The table and comments below along with the function xkb_keysym_to_ucs4
* are under the public domain and are derived as described below.
*/
/* This module converts keysym values into the corresponding ISO 10646
* (UCS, Unicode) values.
*
* The array keysymtab[] contains pairs of X11 keysym values for graphical
* characters and the corresponding Unicode value. The function
* keysym2ucs() maps a keysym onto a Unicode value using a binary search,
* therefore keysymtab[] must remain SORTED by keysym value.
*
* The keysym -> UTF-8 conversion will hopefully one day be provided
* by Xlib via XmbLookupString() and should ideally not have to be
* done in X applications. But we are not there yet.
*
* We allow to represent any UCS character in the range U-00000000 to
* U-00FFFFFF by a keysym value in the range 0x01000000 to 0x01ffffff.
* This admittedly does not cover the entire 31-bit space of UCS, but
* it does cover all of the characters up to U-10FFFF, which can be
* represented by UTF-16, and more, and it is very unlikely that higher
* UCS codes will ever be assigned by ISO. So to get Unicode character
* U+ABCD you can directly use keysym 0x0100abcd.
*
* NOTE: The comments in the table below contain the actual character
* encoded in UTF-8, so for viewing and editing best use an editor in
* UTF-8 mode.
*
* Author: Markus G. Kuhn <http://www.cl.cam.ac.uk/~mgk25/>,
* University of Cambridge, April 2001
*
* Special thanks to Richard Verhoeven <river@win.tue.nl> for preparing
* an initial draft of the mapping table.
*
* This software is in the public domain. Share and enjoy!
*
*/
#include "xkbcommon/xkbcommon.h"
#include "utils.h"
#include "utf8.h"
/* We don't use the uint32_t types here, to save some space. */
struct codepair {
uint16_t keysym;
uint16_t ucs;
};
static const struct codepair keysymtab[] = {
{ 0x01a1, 0x0104 }, /* Aogonek Ą LATIN CAPITAL LETTER A WITH OGONEK */
{ 0x01a2, 0x02d8 }, /* breve ˘ BREVE */
{ 0x01a3, 0x0141 }, /* Lstroke Ł LATIN CAPITAL LETTER L WITH STROKE */
{ 0x01a5, 0x013d }, /* Lcaron Ľ LATIN CAPITAL LETTER L WITH CARON */
{ 0x01a6, 0x015a }, /* Sacute Ś LATIN CAPITAL LETTER S WITH ACUTE */
{ 0x01a9, 0x0160 }, /* Scaron Š LATIN CAPITAL LETTER S WITH CARON */
{ 0x01aa, 0x015e }, /* Scedilla Ş LATIN CAPITAL LETTER S WITH CEDILLA */
{ 0x01ab, 0x0164 }, /* Tcaron Ť LATIN CAPITAL LETTER T WITH CARON */
{ 0x01ac, 0x0179 }, /* Zacute Ź LATIN CAPITAL LETTER Z WITH ACUTE */
{ 0x01ae, 0x017d }, /* Zcaron Ž LATIN CAPITAL LETTER Z WITH CARON */
{ 0x01af, 0x017b }, /* Zabovedot Ż LATIN CAPITAL LETTER Z WITH DOT ABOVE */
{ 0x01b1, 0x0105 }, /* aogonek ą LATIN SMALL LETTER A WITH OGONEK */
{ 0x01b2, 0x02db }, /* ogonek ˛ OGONEK */
{ 0x01b3, 0x0142 }, /* lstroke ł LATIN SMALL LETTER L WITH STROKE */
{ 0x01b5, 0x013e }, /* lcaron ľ LATIN SMALL LETTER L WITH CARON */
{ 0x01b6, 0x015b }, /* sacute ś LATIN SMALL LETTER S WITH ACUTE */
{ 0x01b7, 0x02c7 }, /* caron ˇ CARON */
{ 0x01b9, 0x0161 }, /* scaron š LATIN SMALL LETTER S WITH CARON */
{ 0x01ba, 0x015f }, /* scedilla ş LATIN SMALL LETTER S WITH CEDILLA */
{ 0x01bb, 0x0165 }, /* tcaron ť LATIN SMALL LETTER T WITH CARON */
{ 0x01bc, 0x017a }, /* zacute ź LATIN SMALL LETTER Z WITH ACUTE */
{ 0x01bd, 0x02dd }, /* doubleacute ˝ DOUBLE ACUTE ACCENT */
{ 0x01be, 0x017e }, /* zcaron ž LATIN SMALL LETTER Z WITH CARON */
{ 0x01bf, 0x017c }, /* zabovedot ż LATIN SMALL LETTER Z WITH DOT ABOVE */
{ 0x01c0, 0x0154 }, /* Racute Ŕ LATIN CAPITAL LETTER R WITH ACUTE */
{ 0x01c3, 0x0102 }, /* Abreve Ă LATIN CAPITAL LETTER A WITH BREVE */
{ 0x01c5, 0x0139 }, /* Lacute Ĺ LATIN CAPITAL LETTER L WITH ACUTE */
{ 0x01c6, 0x0106 }, /* Cacute Ć LATIN CAPITAL LETTER C WITH ACUTE */
{ 0x01c8, 0x010c }, /* Ccaron Č LATIN CAPITAL LETTER C WITH CARON */
{ 0x01ca, 0x0118 }, /* Eogonek Ę LATIN CAPITAL LETTER E WITH OGONEK */
{ 0x01cc, 0x011a }, /* Ecaron Ě LATIN CAPITAL LETTER E WITH CARON */
{ 0x01cf, 0x010e }, /* Dcaron Ď LATIN CAPITAL LETTER D WITH CARON */
{ 0x01d0, 0x0110 }, /* Dstroke Đ LATIN CAPITAL LETTER D WITH STROKE */
{ 0x01d1, 0x0143 }, /* Nacute Ń LATIN CAPITAL LETTER N WITH ACUTE */
{ 0x01d2, 0x0147 }, /* Ncaron Ň LATIN CAPITAL LETTER N WITH CARON */
{ 0x01d5, 0x0150 }, /* Odoubleacute Ő LATIN CAPITAL LETTER O WITH DOUBLE ACUTE */
{ 0x01d8, 0x0158 }, /* Rcaron Ř LATIN CAPITAL LETTER R WITH CARON */
{ 0x01d9, 0x016e }, /* Uring Ů LATIN CAPITAL LETTER U WITH RING ABOVE */
{ 0x01db, 0x0170 }, /* Udoubleacute Ű LATIN CAPITAL LETTER U WITH DOUBLE ACUTE */
{ 0x01de, 0x0162 }, /* Tcedilla Ţ LATIN CAPITAL LETTER T WITH CEDILLA */
{ 0x01e0, 0x0155 }, /* racute ŕ LATIN SMALL LETTER R WITH ACUTE */
{ 0x01e3, 0x0103 }, /* abreve ă LATIN SMALL LETTER A WITH BREVE */
{ 0x01e5, 0x013a }, /* lacute ĺ LATIN SMALL LETTER L WITH ACUTE */
{ 0x01e6, 0x0107 }, /* cacute ć LATIN SMALL LETTER C WITH ACUTE */
{ 0x01e8, 0x010d }, /* ccaron č LATIN SMALL LETTER C WITH CARON */
{ 0x01ea, 0x0119 }, /* eogonek ę LATIN SMALL LETTER E WITH OGONEK */
{ 0x01ec, 0x011b }, /* ecaron ě LATIN SMALL LETTER E WITH CARON */
{ 0x01ef, 0x010f }, /* dcaron ď LATIN SMALL LETTER D WITH CARON */
{ 0x01f0, 0x0111 }, /* dstroke đ LATIN SMALL LETTER D WITH STROKE */
{ 0x01f1, 0x0144 }, /* nacute ń LATIN SMALL LETTER N WITH ACUTE */
{ 0x01f2, 0x0148 }, /* ncaron ň LATIN SMALL LETTER N WITH CARON */
{ 0x01f5, 0x0151 }, /* odoubleacute ő LATIN SMALL LETTER O WITH DOUBLE ACUTE */
{ 0x01f8, 0x0159 }, /* rcaron ř LATIN SMALL LETTER R WITH CARON */
{ 0x01f9, 0x016f }, /* uring ů LATIN SMALL LETTER U WITH RING ABOVE */
{ 0x01fb, 0x0171 }, /* udoubleacute ű LATIN SMALL LETTER U WITH DOUBLE ACUTE */
{ 0x01fe, 0x0163 }, /* tcedilla ţ LATIN SMALL LETTER T WITH CEDILLA */
{ 0x01ff, 0x02d9 }, /* abovedot ˙ DOT ABOVE */
{ 0x02a1, 0x0126 }, /* Hstroke Ħ LATIN CAPITAL LETTER H WITH STROKE */
{ 0x02a6, 0x0124 }, /* Hcircumflex Ĥ LATIN CAPITAL LETTER H WITH CIRCUMFLEX */
{ 0x02a9, 0x0130 }, /* Iabovedot İ LATIN CAPITAL LETTER I WITH DOT ABOVE */
{ 0x02ab, 0x011e }, /* Gbreve Ğ LATIN CAPITAL LETTER G WITH BREVE */
{ 0x02ac, 0x0134 }, /* Jcircumflex Ĵ LATIN CAPITAL LETTER J WITH CIRCUMFLEX */
{ 0x02b1, 0x0127 }, /* hstroke ħ LATIN SMALL LETTER H WITH STROKE */
{ 0x02b6, 0x0125 }, /* hcircumflex ĥ LATIN SMALL LETTER H WITH CIRCUMFLEX */
{ 0x02b9, 0x0131 }, /* idotless ı LATIN SMALL LETTER DOTLESS I */
{ 0x02bb, 0x011f }, /* gbreve ğ LATIN SMALL LETTER G WITH BREVE */
{ 0x02bc, 0x0135 }, /* jcircumflex ĵ LATIN SMALL LETTER J WITH CIRCUMFLEX */
{ 0x02c5, 0x010a }, /* Cabovedot Ċ LATIN CAPITAL LETTER C WITH DOT ABOVE */
{ 0x02c6, 0x0108 }, /* Ccircumflex Ĉ LATIN CAPITAL LETTER C WITH CIRCUMFLEX */
{ 0x02d5, 0x0120 }, /* Gabovedot Ġ LATIN CAPITAL LETTER G WITH DOT ABOVE */
{ 0x02d8, 0x011c }, /* Gcircumflex Ĝ LATIN CAPITAL LETTER G WITH CIRCUMFLEX */
{ 0x02dd, 0x016c }, /* Ubreve Ŭ LATIN CAPITAL LETTER U WITH BREVE */
{ 0x02de, 0x015c }, /* Scircumflex Ŝ LATIN CAPITAL LETTER S WITH CIRCUMFLEX */
{ 0x02e5, 0x010b }, /* cabovedot ċ LATIN SMALL LETTER C WITH DOT ABOVE */
{ 0x02e6, 0x0109 }, /* ccircumflex ĉ LATIN SMALL LETTER C WITH CIRCUMFLEX */
{ 0x02f5, 0x0121 }, /* gabovedot ġ LATIN SMALL LETTER G WITH DOT ABOVE */
{ 0x02f8, 0x011d }, /* gcircumflex ĝ LATIN SMALL LETTER G WITH CIRCUMFLEX */
{ 0x02fd, 0x016d }, /* ubreve ŭ LATIN SMALL LETTER U WITH BREVE */
{ 0x02fe, 0x015d }, /* scircumflex ŝ LATIN SMALL LETTER S WITH CIRCUMFLEX */
{ 0x03a2, 0x0138 }, /* kra ĸ LATIN SMALL LETTER KRA */
{ 0x03a3, 0x0156 }, /* Rcedilla Ŗ LATIN CAPITAL LETTER R WITH CEDILLA */
{ 0x03a5, 0x0128 }, /* Itilde Ĩ LATIN CAPITAL LETTER I WITH TILDE */
{ 0x03a6, 0x013b }, /* Lcedilla Ļ LATIN CAPITAL LETTER L WITH CEDILLA */
{ 0x03aa, 0x0112 }, /* Emacron Ē LATIN CAPITAL LETTER E WITH MACRON */
{ 0x03ab, 0x0122 }, /* Gcedilla Ģ LATIN CAPITAL LETTER G WITH CEDILLA */
{ 0x03ac, 0x0166 }, /* Tslash Ŧ LATIN CAPITAL LETTER T WITH STROKE */
{ 0x03b3, 0x0157 }, /* rcedilla ŗ LATIN SMALL LETTER R WITH CEDILLA */
{ 0x03b5, 0x0129 }, /* itilde ĩ LATIN SMALL LETTER I WITH TILDE */
{ 0x03b6, 0x013c }, /* lcedilla ļ LATIN SMALL LETTER L WITH CEDILLA */
{ 0x03ba, 0x0113 }, /* emacron ē LATIN SMALL LETTER E WITH MACRON */
{ 0x03bb, 0x0123 }, /* gcedilla ģ LATIN SMALL LETTER G WITH CEDILLA */
{ 0x03bc, 0x0167 }, /* tslash ŧ LATIN SMALL LETTER T WITH STROKE */
{ 0x03bd, 0x014a }, /* ENG Ŋ LATIN CAPITAL LETTER ENG */
{ 0x03bf, 0x014b }, /* eng ŋ LATIN SMALL LETTER ENG */
{ 0x03c0, 0x0100 }, /* Amacron Ā LATIN CAPITAL LETTER A WITH MACRON */
{ 0x03c7, 0x012e }, /* Iogonek Į LATIN CAPITAL LETTER I WITH OGONEK */
{ 0x03cc, 0x0116 }, /* Eabovedot Ė LATIN CAPITAL LETTER E WITH DOT ABOVE */
{ 0x03cf, 0x012a }, /* Imacron Ī LATIN CAPITAL LETTER I WITH MACRON */
{ 0x03d1, 0x0145 }, /* Ncedilla Ņ LATIN CAPITAL LETTER N WITH CEDILLA */
{ 0x03d2, 0x014c }, /* Omacron Ō LATIN CAPITAL LETTER O WITH MACRON */
{ 0x03d3, 0x0136 }, /* Kcedilla Ķ LATIN CAPITAL LETTER K WITH CEDILLA */
{ 0x03d9, 0x0172 }, /* Uogonek Ų LATIN CAPITAL LETTER U WITH OGONEK */
{ 0x03dd, 0x0168 }, /* Utilde Ũ LATIN CAPITAL LETTER U WITH TILDE */
{ 0x03de, 0x016a }, /* Umacron Ū LATIN CAPITAL LETTER U WITH MACRON */
{ 0x03e0, 0x0101 }, /* amacron ā LATIN SMALL LETTER A WITH MACRON */
{ 0x03e7, 0x012f }, /* iogonek į LATIN SMALL LETTER I WITH OGONEK */
{ 0x03ec, 0x0117 }, /* eabovedot ė LATIN SMALL LETTER E WITH DOT ABOVE */
{ 0x03ef, 0x012b }, /* imacron ī LATIN SMALL LETTER I WITH MACRON */
{ 0x03f1, 0x0146 }, /* ncedilla ņ LATIN SMALL LETTER N WITH CEDILLA */
{ 0x03f2, 0x014d }, /* omacron ō LATIN SMALL LETTER O WITH MACRON */
{ 0x03f3, 0x0137 }, /* kcedilla ķ LATIN SMALL LETTER K WITH CEDILLA */
{ 0x03f9, 0x0173 }, /* uogonek ų LATIN SMALL LETTER U WITH OGONEK */
{ 0x03fd, 0x0169 }, /* utilde ũ LATIN SMALL LETTER U WITH TILDE */
{ 0x03fe, 0x016b }, /* umacron ū LATIN SMALL LETTER U WITH MACRON */
{ 0x047e, 0x203e }, /* overline ‾ OVERLINE */
{ 0x04a1, 0x3002 }, /* kana_fullstop 。 IDEOGRAPHIC FULL STOP */
{ 0x04a2, 0x300c }, /* kana_openingbracket 「 LEFT CORNER BRACKET */
{ 0x04a3, 0x300d }, /* kana_closingbracket 」 RIGHT CORNER BRACKET */
{ 0x04a4, 0x3001 }, /* kana_comma 、 IDEOGRAPHIC COMMA */
{ 0x04a5, 0x30fb }, /* kana_conjunctive ・ KATAKANA MIDDLE DOT */
{ 0x04a6, 0x30f2 }, /* kana_WO ヲ KATAKANA LETTER WO */
{ 0x04a7, 0x30a1 }, /* kana_a ァ KATAKANA LETTER SMALL A */
{ 0x04a8, 0x30a3 }, /* kana_i ィ KATAKANA LETTER SMALL I */
{ 0x04a9, 0x30a5 }, /* kana_u ゥ KATAKANA LETTER SMALL U */
{ 0x04aa, 0x30a7 }, /* kana_e ェ KATAKANA LETTER SMALL E */
{ 0x04ab, 0x30a9 }, /* kana_o ォ KATAKANA LETTER SMALL O */
{ 0x04ac, 0x30e3 }, /* kana_ya ャ KATAKANA LETTER SMALL YA */
{ 0x04ad, 0x30e5 }, /* kana_yu ュ KATAKANA LETTER SMALL YU */
{ 0x04ae, 0x30e7 }, /* kana_yo ョ KATAKANA LETTER SMALL YO */
{ 0x04af, 0x30c3 }, /* kana_tsu ッ KATAKANA LETTER SMALL TU */
{ 0x04b0, 0x30fc }, /* prolongedsound ー KATAKANA-HIRAGANA PROLONGED SOUND MARK */
{ 0x04b1, 0x30a2 }, /* kana_A ア KATAKANA LETTER A */
{ 0x04b2, 0x30a4 }, /* kana_I イ KATAKANA LETTER I */
{ 0x04b3, 0x30a6 }, /* kana_U ウ KATAKANA LETTER U */
{ 0x04b4, 0x30a8 }, /* kana_E エ KATAKANA LETTER E */
{ 0x04b5, 0x30aa }, /* kana_O オ KATAKANA LETTER O */
{ 0x04b6, 0x30ab }, /* kana_KA カ KATAKANA LETTER KA */
{ 0x04b7, 0x30ad }, /* kana_KI キ KATAKANA LETTER KI */
{ 0x04b8, 0x30af }, /* kana_KU ク KATAKANA LETTER KU */
{ 0x04b9, 0x30b1 }, /* kana_KE ケ KATAKANA LETTER KE */
{ 0x04ba, 0x30b3 }, /* kana_KO コ KATAKANA LETTER KO */
{ 0x04bb, 0x30b5 }, /* kana_SA サ KATAKANA LETTER SA */
{ 0x04bc, 0x30b7 }, /* kana_SHI シ KATAKANA LETTER SI */
{ 0x04bd, 0x30b9 }, /* kana_SU ス KATAKANA LETTER SU */
{ 0x04be, 0x30bb }, /* kana_SE セ KATAKANA LETTER SE */
{ 0x04bf, 0x30bd }, /* kana_SO ソ KATAKANA LETTER SO */
{ 0x04c0, 0x30bf }, /* kana_TA タ KATAKANA LETTER TA */
{ 0x04c1, 0x30c1 }, /* kana_CHI チ KATAKANA LETTER TI */
{ 0x04c2, 0x30c4 }, /* kana_TSU ツ KATAKANA LETTER TU */
{ 0x04c3, 0x30c6 }, /* kana_TE テ KATAKANA LETTER TE */
{ 0x04c4, 0x30c8 }, /* kana_TO ト KATAKANA LETTER TO */
{ 0x04c5, 0x30ca }, /* kana_NA ナ KATAKANA LETTER NA */
{ 0x04c6, 0x30cb }, /* kana_NI ニ KATAKANA LETTER NI */
{ 0x04c7, 0x30cc }, /* kana_NU ヌ KATAKANA LETTER NU */
{ 0x04c8, 0x30cd }, /* kana_NE ネ KATAKANA LETTER NE */
{ 0x04c9, 0x30ce }, /* kana_NO KATAKANA LETTER NO */
{ 0x04ca, 0x30cf }, /* kana_HA ハ KATAKANA LETTER HA */
{ 0x04cb, 0x30d2 }, /* kana_HI ヒ KATAKANA LETTER HI */
{ 0x04cc, 0x30d5 }, /* kana_FU フ KATAKANA LETTER HU */
{ 0x04cd, 0x30d8 }, /* kana_HE ヘ KATAKANA LETTER HE */
{ 0x04ce, 0x30db }, /* kana_HO ホ KATAKANA LETTER HO */
{ 0x04cf, 0x30de }, /* kana_MA マ KATAKANA LETTER MA */
{ 0x04d0, 0x30df }, /* kana_MI ミ KATAKANA LETTER MI */
{ 0x04d1, 0x30e0 }, /* kana_MU ム KATAKANA LETTER MU */
{ 0x04d2, 0x30e1 }, /* kana_ME メ KATAKANA LETTER ME */
{ 0x04d3, 0x30e2 }, /* kana_MO モ KATAKANA LETTER MO */
{ 0x04d4, 0x30e4 }, /* kana_YA ヤ KATAKANA LETTER YA */
{ 0x04d5, 0x30e6 }, /* kana_YU ユ KATAKANA LETTER YU */
{ 0x04d6, 0x30e8 }, /* kana_YO ヨ KATAKANA LETTER YO */
{ 0x04d7, 0x30e9 }, /* kana_RA ラ KATAKANA LETTER RA */
{ 0x04d8, 0x30ea }, /* kana_RI リ KATAKANA LETTER RI */
{ 0x04d9, 0x30eb }, /* kana_RU ル KATAKANA LETTER RU */
{ 0x04da, 0x30ec }, /* kana_RE レ KATAKANA LETTER RE */
{ 0x04db, 0x30ed }, /* kana_RO ロ KATAKANA LETTER RO */
{ 0x04dc, 0x30ef }, /* kana_WA ワ KATAKANA LETTER WA */
{ 0x04dd, 0x30f3 }, /* kana_N ン KATAKANA LETTER N */
{ 0x04de, 0x309b }, /* voicedsound ゛ KATAKANA-HIRAGANA VOICED SOUND MARK */
{ 0x04df, 0x309c }, /* semivoicedsound ゜ KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */
{ 0x05ac, 0x060c }, /* Arabic_comma ، ARABIC COMMA */
{ 0x05bb, 0x061b }, /* Arabic_semicolon ؛ ARABIC SEMICOLON */
{ 0x05bf, 0x061f }, /* Arabic_question_mark ؟ ARABIC QUESTION MARK */
{ 0x05c1, 0x0621 }, /* Arabic_hamza ء ARABIC LETTER HAMZA */
{ 0x05c2, 0x0622 }, /* Arabic_maddaonalef آ ARABIC LETTER ALEF WITH MADDA ABOVE */
{ 0x05c3, 0x0623 }, /* Arabic_hamzaonalef أ ARABIC LETTER ALEF WITH HAMZA ABOVE */
{ 0x05c4, 0x0624 }, /* Arabic_hamzaonwaw ؤ ARABIC LETTER WAW WITH HAMZA ABOVE */
{ 0x05c5, 0x0625 }, /* Arabic_hamzaunderalef إ ARABIC LETTER ALEF WITH HAMZA BELOW */
{ 0x05c6, 0x0626 }, /* Arabic_hamzaonyeh ئ ARABIC LETTER YEH WITH HAMZA ABOVE */
{ 0x05c7, 0x0627 }, /* Arabic_alef ا ARABIC LETTER ALEF */
{ 0x05c8, 0x0628 }, /* Arabic_beh ب ARABIC LETTER BEH */
{ 0x05c9, 0x0629 }, /* Arabic_tehmarbuta ة ARABIC LETTER TEH MARBUTA */
{ 0x05ca, 0x062a }, /* Arabic_teh ت ARABIC LETTER TEH */
{ 0x05cb, 0x062b }, /* Arabic_theh ث ARABIC LETTER THEH */
{ 0x05cc, 0x062c }, /* Arabic_jeem ج ARABIC LETTER JEEM */
{ 0x05cd, 0x062d }, /* Arabic_hah ح ARABIC LETTER HAH */
{ 0x05ce, 0x062e }, /* Arabic_khah خ ARABIC LETTER KHAH */
{ 0x05cf, 0x062f }, /* Arabic_dal د ARABIC LETTER DAL */
{ 0x05d0, 0x0630 }, /* Arabic_thal ذ ARABIC LETTER THAL */
{ 0x05d1, 0x0631 }, /* Arabic_ra ر ARABIC LETTER REH */
{ 0x05d2, 0x0632 }, /* Arabic_zain ز ARABIC LETTER ZAIN */
{ 0x05d3, 0x0633 }, /* Arabic_seen س ARABIC LETTER SEEN */
{ 0x05d4, 0x0634 }, /* Arabic_sheen ش ARABIC LETTER SHEEN */
{ 0x05d5, 0x0635 }, /* Arabic_sad ص ARABIC LETTER SAD */
{ 0x05d6, 0x0636 }, /* Arabic_dad ض ARABIC LETTER DAD */
{ 0x05d7, 0x0637 }, /* Arabic_tah ط ARABIC LETTER TAH */
{ 0x05d8, 0x0638 }, /* Arabic_zah ظ ARABIC LETTER ZAH */
{ 0x05d9, 0x0639 }, /* Arabic_ain ع ARABIC LETTER AIN */
{ 0x05da, 0x063a }, /* Arabic_ghain غ ARABIC LETTER GHAIN */
{ 0x05e0, 0x0640 }, /* Arabic_tatweel ـ ARABIC TATWEEL */
{ 0x05e1, 0x0641 }, /* Arabic_feh ف ARABIC LETTER FEH */
{ 0x05e2, 0x0642 }, /* Arabic_qaf ق ARABIC LETTER QAF */
{ 0x05e3, 0x0643 }, /* Arabic_kaf ك ARABIC LETTER KAF */
{ 0x05e4, 0x0644 }, /* Arabic_lam ل ARABIC LETTER LAM */
{ 0x05e5, 0x0645 }, /* Arabic_meem م ARABIC LETTER MEEM */
{ 0x05e6, 0x0646 }, /* Arabic_noon ن ARABIC LETTER NOON */
{ 0x05e7, 0x0647 }, /* Arabic_ha ه ARABIC LETTER HEH */
{ 0x05e8, 0x0648 }, /* Arabic_waw و ARABIC LETTER WAW */
{ 0x05e9, 0x0649 }, /* Arabic_alefmaksura ى ARABIC LETTER ALEF MAKSURA */
{ 0x05ea, 0x064a }, /* Arabic_yeh ي ARABIC LETTER YEH */
{ 0x05eb, 0x064b }, /* Arabic_fathatan ً ARABIC FATHATAN */
{ 0x05ec, 0x064c }, /* Arabic_dammatan ٌ ARABIC DAMMATAN */
{ 0x05ed, 0x064d }, /* Arabic_kasratan ٍ ARABIC KASRATAN */
{ 0x05ee, 0x064e }, /* Arabic_fatha َ ARABIC FATHA */
{ 0x05ef, 0x064f }, /* Arabic_damma ُ ARABIC DAMMA */
{ 0x05f0, 0x0650 }, /* Arabic_kasra ِ ARABIC KASRA */
{ 0x05f1, 0x0651 }, /* Arabic_shadda ّ ARABIC SHADDA */
{ 0x05f2, 0x0652 }, /* Arabic_sukun ْ ARABIC SUKUN */
{ 0x06a1, 0x0452 }, /* Serbian_dje ђ CYRILLIC SMALL LETTER DJE */
{ 0x06a2, 0x0453 }, /* Macedonia_gje ѓ CYRILLIC SMALL LETTER GJE */
{ 0x06a3, 0x0451 }, /* Cyrillic_io ё CYRILLIC SMALL LETTER IO */
{ 0x06a4, 0x0454 }, /* Ukrainian_ie є CYRILLIC SMALL LETTER UKRAINIAN IE */
{ 0x06a5, 0x0455 }, /* Macedonia_dse ѕ CYRILLIC SMALL LETTER DZE */
{ 0x06a6, 0x0456 }, /* Ukrainian_i і CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I */
{ 0x06a7, 0x0457 }, /* Ukrainian_yi ї CYRILLIC SMALL LETTER YI */
{ 0x06a8, 0x0458 }, /* Cyrillic_je ј CYRILLIC SMALL LETTER JE */
{ 0x06a9, 0x0459 }, /* Cyrillic_lje љ CYRILLIC SMALL LETTER LJE */
{ 0x06aa, 0x045a }, /* Cyrillic_nje њ CYRILLIC SMALL LETTER NJE */
{ 0x06ab, 0x045b }, /* Serbian_tshe ћ CYRILLIC SMALL LETTER TSHE */
{ 0x06ac, 0x045c }, /* Macedonia_kje ќ CYRILLIC SMALL LETTER KJE */
{ 0x06ad, 0x0491 }, /* Ukrainian_ghe_with_upturn ґ CYRILLIC SMALL LETTER GHE WITH UPTURN */
{ 0x06ae, 0x045e }, /* Byelorussian_shortu ў CYRILLIC SMALL LETTER SHORT U */
{ 0x06af, 0x045f }, /* Cyrillic_dzhe џ CYRILLIC SMALL LETTER DZHE */
{ 0x06b0, 0x2116 }, /* numerosign № NUMERO SIGN */
{ 0x06b1, 0x0402 }, /* Serbian_DJE Ђ CYRILLIC CAPITAL LETTER DJE */
{ 0x06b2, 0x0403 }, /* Macedonia_GJE Ѓ CYRILLIC CAPITAL LETTER GJE */
{ 0x06b3, 0x0401 }, /* Cyrillic_IO Ё CYRILLIC CAPITAL LETTER IO */
{ 0x06b4, 0x0404 }, /* Ukrainian_IE Є CYRILLIC CAPITAL LETTER UKRAINIAN IE */
{ 0x06b5, 0x0405 }, /* Macedonia_DSE Ѕ CYRILLIC CAPITAL LETTER DZE */
{ 0x06b6, 0x0406 }, /* Ukrainian_I І CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I */
{ 0x06b7, 0x0407 }, /* Ukrainian_YI Ї CYRILLIC CAPITAL LETTER YI */
{ 0x06b8, 0x0408 }, /* Cyrillic_JE Ј CYRILLIC CAPITAL LETTER JE */
{ 0x06b9, 0x0409 }, /* Cyrillic_LJE Љ CYRILLIC CAPITAL LETTER LJE */
{ 0x06ba, 0x040a }, /* Cyrillic_NJE Њ CYRILLIC CAPITAL LETTER NJE */
{ 0x06bb, 0x040b }, /* Serbian_TSHE Ћ CYRILLIC CAPITAL LETTER TSHE */
{ 0x06bc, 0x040c }, /* Macedonia_KJE Ќ CYRILLIC CAPITAL LETTER KJE */
{ 0x06bd, 0x0490 }, /* Ukrainian_GHE_WITH_UPTURN Ґ CYRILLIC CAPITAL LETTER GHE WITH UPTURN */
{ 0x06be, 0x040e }, /* Byelorussian_SHORTU Ў CYRILLIC CAPITAL LETTER SHORT U */
{ 0x06bf, 0x040f }, /* Cyrillic_DZHE Џ CYRILLIC CAPITAL LETTER DZHE */
{ 0x06c0, 0x044e }, /* Cyrillic_yu ю CYRILLIC SMALL LETTER YU */
{ 0x06c1, 0x0430 }, /* Cyrillic_a а CYRILLIC SMALL LETTER A */
{ 0x06c2, 0x0431 }, /* Cyrillic_be б CYRILLIC SMALL LETTER BE */
{ 0x06c3, 0x0446 }, /* Cyrillic_tse ц CYRILLIC SMALL LETTER TSE */
{ 0x06c4, 0x0434 }, /* Cyrillic_de д CYRILLIC SMALL LETTER DE */
{ 0x06c5, 0x0435 }, /* Cyrillic_ie е CYRILLIC SMALL LETTER IE */
{ 0x06c6, 0x0444 }, /* Cyrillic_ef ф CYRILLIC SMALL LETTER EF */
{ 0x06c7, 0x0433 }, /* Cyrillic_ghe г CYRILLIC SMALL LETTER GHE */
{ 0x06c8, 0x0445 }, /* Cyrillic_ha х CYRILLIC SMALL LETTER HA */
{ 0x06c9, 0x0438 }, /* Cyrillic_i и CYRILLIC SMALL LETTER I */
{ 0x06ca, 0x0439 }, /* Cyrillic_shorti й CYRILLIC SMALL LETTER SHORT I */
{ 0x06cb, 0x043a }, /* Cyrillic_ka к CYRILLIC SMALL LETTER KA */
{ 0x06cc, 0x043b }, /* Cyrillic_el л CYRILLIC SMALL LETTER EL */
{ 0x06cd, 0x043c }, /* Cyrillic_em м CYRILLIC SMALL LETTER EM */
{ 0x06ce, 0x043d }, /* Cyrillic_en н CYRILLIC SMALL LETTER EN */
{ 0x06cf, 0x043e }, /* Cyrillic_o о CYRILLIC SMALL LETTER O */
{ 0x06d0, 0x043f }, /* Cyrillic_pe п CYRILLIC SMALL LETTER PE */
{ 0x06d1, 0x044f }, /* Cyrillic_ya я CYRILLIC SMALL LETTER YA */
{ 0x06d2, 0x0440 }, /* Cyrillic_er р CYRILLIC SMALL LETTER ER */
{ 0x06d3, 0x0441 }, /* Cyrillic_es с CYRILLIC SMALL LETTER ES */
{ 0x06d4, 0x0442 }, /* Cyrillic_te т CYRILLIC SMALL LETTER TE */
{ 0x06d5, 0x0443 }, /* Cyrillic_u у CYRILLIC SMALL LETTER U */
{ 0x06d6, 0x0436 }, /* Cyrillic_zhe ж CYRILLIC SMALL LETTER ZHE */
{ 0x06d7, 0x0432 }, /* Cyrillic_ve в CYRILLIC SMALL LETTER VE */
{ 0x06d8, 0x044c }, /* Cyrillic_softsign ь CYRILLIC SMALL LETTER SOFT SIGN */
{ 0x06d9, 0x044b }, /* Cyrillic_yeru ы CYRILLIC SMALL LETTER YERU */
{ 0x06da, 0x0437 }, /* Cyrillic_ze з CYRILLIC SMALL LETTER ZE */
{ 0x06db, 0x0448 }, /* Cyrillic_sha ш CYRILLIC SMALL LETTER SHA */
{ 0x06dc, 0x044d }, /* Cyrillic_e э CYRILLIC SMALL LETTER E */
{ 0x06dd, 0x0449 }, /* Cyrillic_shcha щ CYRILLIC SMALL LETTER SHCHA */
{ 0x06de, 0x0447 }, /* Cyrillic_che ч CYRILLIC SMALL LETTER CHE */
{ 0x06df, 0x044a }, /* Cyrillic_hardsign ъ CYRILLIC SMALL LETTER HARD SIGN */
{ 0x06e0, 0x042e }, /* Cyrillic_YU Ю CYRILLIC CAPITAL LETTER YU */
{ 0x06e1, 0x0410 }, /* Cyrillic_A А CYRILLIC CAPITAL LETTER A */
{ 0x06e2, 0x0411 }, /* Cyrillic_BE Б CYRILLIC CAPITAL LETTER BE */
{ 0x06e3, 0x0426 }, /* Cyrillic_TSE Ц CYRILLIC CAPITAL LETTER TSE */
{ 0x06e4, 0x0414 }, /* Cyrillic_DE Д CYRILLIC CAPITAL LETTER DE */
{ 0x06e5, 0x0415 }, /* Cyrillic_IE Е CYRILLIC CAPITAL LETTER IE */
{ 0x06e6, 0x0424 }, /* Cyrillic_EF Ф CYRILLIC CAPITAL LETTER EF */
{ 0x06e7, 0x0413 }, /* Cyrillic_GHE Г CYRILLIC CAPITAL LETTER GHE */
{ 0x06e8, 0x0425 }, /* Cyrillic_HA Х CYRILLIC CAPITAL LETTER HA */
{ 0x06e9, 0x0418 }, /* Cyrillic_I И CYRILLIC CAPITAL LETTER I */
{ 0x06ea, 0x0419 }, /* Cyrillic_SHORTI Й CYRILLIC CAPITAL LETTER SHORT I */
{ 0x06eb, 0x041a }, /* Cyrillic_KA К CYRILLIC CAPITAL LETTER KA */
{ 0x06ec, 0x041b }, /* Cyrillic_EL Л CYRILLIC CAPITAL LETTER EL */
{ 0x06ed, 0x041c }, /* Cyrillic_EM М CYRILLIC CAPITAL LETTER EM */
{ 0x06ee, 0x041d }, /* Cyrillic_EN Н CYRILLIC CAPITAL LETTER EN */
{ 0x06ef, 0x041e }, /* Cyrillic_O О CYRILLIC CAPITAL LETTER O */
{ 0x06f0, 0x041f }, /* Cyrillic_PE П CYRILLIC CAPITAL LETTER PE */
{ 0x06f1, 0x042f }, /* Cyrillic_YA Я CYRILLIC CAPITAL LETTER YA */
{ 0x06f2, 0x0420 }, /* Cyrillic_ER Р CYRILLIC CAPITAL LETTER ER */
{ 0x06f3, 0x0421 }, /* Cyrillic_ES С CYRILLIC CAPITAL LETTER ES */
{ 0x06f4, 0x0422 }, /* Cyrillic_TE Т CYRILLIC CAPITAL LETTER TE */
{ 0x06f5, 0x0423 }, /* Cyrillic_U У CYRILLIC CAPITAL LETTER U */
{ 0x06f6, 0x0416 }, /* Cyrillic_ZHE Ж CYRILLIC CAPITAL LETTER ZHE */
{ 0x06f7, 0x0412 }, /* Cyrillic_VE В CYRILLIC CAPITAL LETTER VE */
{ 0x06f8, 0x042c }, /* Cyrillic_SOFTSIGN Ь CYRILLIC CAPITAL LETTER SOFT SIGN */
{ 0x06f9, 0x042b }, /* Cyrillic_YERU Ы CYRILLIC CAPITAL LETTER YERU */
{ 0x06fa, 0x0417 }, /* Cyrillic_ZE З CYRILLIC CAPITAL LETTER ZE */
{ 0x06fb, 0x0428 }, /* Cyrillic_SHA Ш CYRILLIC CAPITAL LETTER SHA */
{ 0x06fc, 0x042d }, /* Cyrillic_E Э CYRILLIC CAPITAL LETTER E */
{ 0x06fd, 0x0429 }, /* Cyrillic_SHCHA Щ CYRILLIC CAPITAL LETTER SHCHA */
{ 0x06fe, 0x0427 }, /* Cyrillic_CHE Ч CYRILLIC CAPITAL LETTER CHE */
{ 0x06ff, 0x042a }, /* Cyrillic_HARDSIGN Ъ CYRILLIC CAPITAL LETTER HARD SIGN */
{ 0x07a1, 0x0386 }, /* Greek_ALPHAaccent Ά GREEK CAPITAL LETTER ALPHA WITH TONOS */
{ 0x07a2, 0x0388 }, /* Greek_EPSILONaccent Έ GREEK CAPITAL LETTER EPSILON WITH TONOS */
{ 0x07a3, 0x0389 }, /* Greek_ETAaccent Ή GREEK CAPITAL LETTER ETA WITH TONOS */
{ 0x07a4, 0x038a }, /* Greek_IOTAaccent Ί GREEK CAPITAL LETTER IOTA WITH TONOS */
{ 0x07a5, 0x03aa }, /* Greek_IOTAdiaeresis Ϊ GREEK CAPITAL LETTER IOTA WITH DIALYTIKA */
{ 0x07a7, 0x038c }, /* Greek_OMICRONaccent Ό GREEK CAPITAL LETTER OMICRON WITH TONOS */
{ 0x07a8, 0x038e }, /* Greek_UPSILONaccent Ύ GREEK CAPITAL LETTER UPSILON WITH TONOS */
{ 0x07a9, 0x03ab }, /* Greek_UPSILONdieresis Ϋ GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA */
{ 0x07ab, 0x038f }, /* Greek_OMEGAaccent Ώ GREEK CAPITAL LETTER OMEGA WITH TONOS */
{ 0x07ae, 0x0385 }, /* Greek_accentdieresis ΅ GREEK DIALYTIKA TONOS */
{ 0x07af, 0x2015 }, /* Greek_horizbar ― HORIZONTAL BAR */
{ 0x07b1, 0x03ac }, /* Greek_alphaaccent ά GREEK SMALL LETTER ALPHA WITH TONOS */
{ 0x07b2, 0x03ad }, /* Greek_epsilonaccent έ GREEK SMALL LETTER EPSILON WITH TONOS */
{ 0x07b3, 0x03ae }, /* Greek_etaaccent ή GREEK SMALL LETTER ETA WITH TONOS */
{ 0x07b4, 0x03af }, /* Greek_iotaaccent ί GREEK SMALL LETTER IOTA WITH TONOS */
{ 0x07b5, 0x03ca }, /* Greek_iotadieresis ϊ GREEK SMALL LETTER IOTA WITH DIALYTIKA */
{ 0x07b6, 0x0390 }, /* Greek_iotaaccentdieresis ΐ GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS */
{ 0x07b7, 0x03cc }, /* Greek_omicronaccent ό GREEK SMALL LETTER OMICRON WITH TONOS */
{ 0x07b8, 0x03cd }, /* Greek_upsilonaccent ύ GREEK SMALL LETTER UPSILON WITH TONOS */
{ 0x07b9, 0x03cb }, /* Greek_upsilondieresis ϋ GREEK SMALL LETTER UPSILON WITH DIALYTIKA */
{ 0x07ba, 0x03b0 }, /* Greek_upsilonaccentdieresis ΰ GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS */
{ 0x07bb, 0x03ce }, /* Greek_omegaaccent ώ GREEK SMALL LETTER OMEGA WITH TONOS */
{ 0x07c1, 0x0391 }, /* Greek_ALPHA Α GREEK CAPITAL LETTER ALPHA */
{ 0x07c2, 0x0392 }, /* Greek_BETA Β GREEK CAPITAL LETTER BETA */
{ 0x07c3, 0x0393 }, /* Greek_GAMMA Γ GREEK CAPITAL LETTER GAMMA */
{ 0x07c4, 0x0394 }, /* Greek_DELTA Δ GREEK CAPITAL LETTER DELTA */
{ 0x07c5, 0x0395 }, /* Greek_EPSILON Ε GREEK CAPITAL LETTER EPSILON */
{ 0x07c6, 0x0396 }, /* Greek_ZETA Ζ GREEK CAPITAL LETTER ZETA */
{ 0x07c7, 0x0397 }, /* Greek_ETA Η GREEK CAPITAL LETTER ETA */
{ 0x07c8, 0x0398 }, /* Greek_THETA Θ GREEK CAPITAL LETTER THETA */
{ 0x07c9, 0x0399 }, /* Greek_IOTA Ι GREEK CAPITAL LETTER IOTA */
{ 0x07ca, 0x039a }, /* Greek_KAPPA Κ GREEK CAPITAL LETTER KAPPA */
{ 0x07cb, 0x039b }, /* Greek_LAMBDA Λ GREEK CAPITAL LETTER LAMDA */
{ 0x07cc, 0x039c }, /* Greek_MU Μ GREEK CAPITAL LETTER MU */
{ 0x07cd, 0x039d }, /* Greek_NU Ν GREEK CAPITAL LETTER NU */
{ 0x07ce, 0x039e }, /* Greek_XI Ξ GREEK CAPITAL LETTER XI */
{ 0x07cf, 0x039f }, /* Greek_OMICRON Ο GREEK CAPITAL LETTER OMICRON */
{ 0x07d0, 0x03a0 }, /* Greek_PI Π GREEK CAPITAL LETTER PI */
{ 0x07d1, 0x03a1 }, /* Greek_RHO Ρ GREEK CAPITAL LETTER RHO */
{ 0x07d2, 0x03a3 }, /* Greek_SIGMA Σ GREEK CAPITAL LETTER SIGMA */
{ 0x07d4, 0x03a4 }, /* Greek_TAU Τ GREEK CAPITAL LETTER TAU */
{ 0x07d5, 0x03a5 }, /* Greek_UPSILON Υ GREEK CAPITAL LETTER UPSILON */
{ 0x07d6, 0x03a6 }, /* Greek_PHI Φ GREEK CAPITAL LETTER PHI */
{ 0x07d7, 0x03a7 }, /* Greek_CHI Χ GREEK CAPITAL LETTER CHI */
{ 0x07d8, 0x03a8 }, /* Greek_PSI Ψ GREEK CAPITAL LETTER PSI */
{ 0x07d9, 0x03a9 }, /* Greek_OMEGA Ω GREEK CAPITAL LETTER OMEGA */
{ 0x07e1, 0x03b1 }, /* Greek_alpha α GREEK SMALL LETTER ALPHA */
{ 0x07e2, 0x03b2 }, /* Greek_beta β GREEK SMALL LETTER BETA */
{ 0x07e3, 0x03b3 }, /* Greek_gamma γ GREEK SMALL LETTER GAMMA */
{ 0x07e4, 0x03b4 }, /* Greek_delta δ GREEK SMALL LETTER DELTA */
{ 0x07e5, 0x03b5 }, /* Greek_epsilon ε GREEK SMALL LETTER EPSILON */
{ 0x07e6, 0x03b6 }, /* Greek_zeta ζ GREEK SMALL LETTER ZETA */
{ 0x07e7, 0x03b7 }, /* Greek_eta η GREEK SMALL LETTER ETA */
{ 0x07e8, 0x03b8 }, /* Greek_theta θ GREEK SMALL LETTER THETA */
{ 0x07e9, 0x03b9 }, /* Greek_iota ι GREEK SMALL LETTER IOTA */
{ 0x07ea, 0x03ba }, /* Greek_kappa κ GREEK SMALL LETTER KAPPA */
{ 0x07eb, 0x03bb }, /* Greek_lambda λ GREEK SMALL LETTER LAMDA */
{ 0x07ec, 0x03bc }, /* Greek_mu μ GREEK SMALL LETTER MU */
{ 0x07ed, 0x03bd }, /* Greek_nu ν GREEK SMALL LETTER NU */
{ 0x07ee, 0x03be }, /* Greek_xi ξ GREEK SMALL LETTER XI */
{ 0x07ef, 0x03bf }, /* Greek_omicron ο GREEK SMALL LETTER OMICRON */
{ 0x07f0, 0x03c0 }, /* Greek_pi π GREEK SMALL LETTER PI */
{ 0x07f1, 0x03c1 }, /* Greek_rho ρ GREEK SMALL LETTER RHO */
{ 0x07f2, 0x03c3 }, /* Greek_sigma σ GREEK SMALL LETTER SIGMA */
{ 0x07f3, 0x03c2 }, /* Greek_finalsmallsigma ς GREEK SMALL LETTER FINAL SIGMA */
{ 0x07f4, 0x03c4 }, /* Greek_tau τ GREEK SMALL LETTER TAU */
{ 0x07f5, 0x03c5 }, /* Greek_upsilon υ GREEK SMALL LETTER UPSILON */
{ 0x07f6, 0x03c6 }, /* Greek_phi φ GREEK SMALL LETTER PHI */
{ 0x07f7, 0x03c7 }, /* Greek_chi χ GREEK SMALL LETTER CHI */
{ 0x07f8, 0x03c8 }, /* Greek_psi ψ GREEK SMALL LETTER PSI */
{ 0x07f9, 0x03c9 }, /* Greek_omega ω GREEK SMALL LETTER OMEGA */
{ 0x08a1, 0x23b7 }, /* leftradical ⎷ ??? */
{ 0x08a2, 0x250c }, /* topleftradical ┌ BOX DRAWINGS LIGHT DOWN AND RIGHT */
{ 0x08a3, 0x2500 }, /* horizconnector ─ BOX DRAWINGS LIGHT HORIZONTAL */
{ 0x08a4, 0x2320 }, /* topintegral ⌠ TOP HALF INTEGRAL */
{ 0x08a5, 0x2321 }, /* botintegral ⌡ BOTTOM HALF INTEGRAL */
{ 0x08a6, 0x2502 }, /* vertconnector │ BOX DRAWINGS LIGHT VERTICAL */
{ 0x08a7, 0x23a1 }, /* topleftsqbracket ⎡ ??? */
{ 0x08a8, 0x23a3 }, /* botleftsqbracket ⎣ ??? */
{ 0x08a9, 0x23a4 }, /* toprightsqbracket ⎤ ??? */
{ 0x08aa, 0x23a6 }, /* botrightsqbracket ⎦ ??? */
{ 0x08ab, 0x239b }, /* topleftparens ⎛ ??? */
{ 0x08ac, 0x239d }, /* botleftparens ⎝ ??? */
{ 0x08ad, 0x239e }, /* toprightparens ⎞ ??? */
{ 0x08ae, 0x23a0 }, /* botrightparens ⎠ ??? */
{ 0x08af, 0x23a8 }, /* leftmiddlecurlybrace ⎨ ??? */
{ 0x08b0, 0x23ac }, /* rightmiddlecurlybrace ⎬ ??? */
/* 0x08b1 topleftsummation ? ??? */
/* 0x08b2 botleftsummation ? ??? */
/* 0x08b3 topvertsummationconnector ? ??? */
/* 0x08b4 botvertsummationconnector ? ??? */
/* 0x08b5 toprightsummation ? ??? */
/* 0x08b6 botrightsummation ? ??? */
/* 0x08b7 rightmiddlesummation ? ??? */
{ 0x08bc, 0x2264 }, /* lessthanequal ≤ LESS-THAN OR EQUAL TO */
{ 0x08bd, 0x2260 }, /* notequal ≠ NOT EQUAL TO */
{ 0x08be, 0x2265 }, /* greaterthanequal ≥ GREATER-THAN OR EQUAL TO */
{ 0x08bf, 0x222b }, /* integral ∫ INTEGRAL */
{ 0x08c0, 0x2234 }, /* therefore ∴ THEREFORE */
{ 0x08c1, 0x221d }, /* variation ∝ PROPORTIONAL TO */
{ 0x08c2, 0x221e }, /* infinity ∞ INFINITY */
{ 0x08c5, 0x2207 }, /* nabla ∇ NABLA */
{ 0x08c8, 0x223c }, /* approximate TILDE OPERATOR */
{ 0x08c9, 0x2243 }, /* similarequal ≃ ASYMPTOTICALLY EQUAL TO */
{ 0x08cd, 0x21d4 }, /* ifonlyif ⇔ LEFT RIGHT DOUBLE ARROW */
{ 0x08ce, 0x21d2 }, /* implies ⇒ RIGHTWARDS DOUBLE ARROW */
{ 0x08cf, 0x2261 }, /* identical ≡ IDENTICAL TO */
{ 0x08d6, 0x221a }, /* radical √ SQUARE ROOT */
{ 0x08da, 0x2282 }, /* includedin ⊂ SUBSET OF */
{ 0x08db, 0x2283 }, /* includes ⊃ SUPERSET OF */
{ 0x08dc, 0x2229 }, /* intersection ∩ INTERSECTION */
{ 0x08dd, 0x222a }, /* union UNION */
{ 0x08de, 0x2227 }, /* logicaland ∧ LOGICAL AND */
{ 0x08df, 0x2228 }, /* logicalor LOGICAL OR */
{ 0x08ef, 0x2202 }, /* partialderivative ∂ PARTIAL DIFFERENTIAL */
{ 0x08f6, 0x0192 }, /* function ƒ LATIN SMALL LETTER F WITH HOOK */
{ 0x08fb, 0x2190 }, /* leftarrow ← LEFTWARDS ARROW */
{ 0x08fc, 0x2191 }, /* uparrow ↑ UPWARDS ARROW */
{ 0x08fd, 0x2192 }, /* rightarrow → RIGHTWARDS ARROW */
{ 0x08fe, 0x2193 }, /* downarrow ↓ DOWNWARDS ARROW */
/* 0x09df blank ? ??? */
{ 0x09e0, 0x25c6 }, /* soliddiamond ◆ BLACK DIAMOND */
{ 0x09e1, 0x2592 }, /* checkerboard ▒ MEDIUM SHADE */
{ 0x09e2, 0x2409 }, /* ht ␉ SYMBOL FOR HORIZONTAL TABULATION */
{ 0x09e3, 0x240c }, /* ff ␌ SYMBOL FOR FORM FEED */
{ 0x09e4, 0x240d }, /* cr ␍ SYMBOL FOR CARRIAGE RETURN */
{ 0x09e5, 0x240a }, /* lf ␊ SYMBOL FOR LINE FEED */
{ 0x09e8, 0x2424 }, /* nl ␤ SYMBOL FOR NEWLINE */
{ 0x09e9, 0x240b }, /* vt ␋ SYMBOL FOR VERTICAL TABULATION */
{ 0x09ea, 0x2518 }, /* lowrightcorner ┘ BOX DRAWINGS LIGHT UP AND LEFT */
{ 0x09eb, 0x2510 }, /* uprightcorner ┐ BOX DRAWINGS LIGHT DOWN AND LEFT */
{ 0x09ec, 0x250c }, /* upleftcorner ┌ BOX DRAWINGS LIGHT DOWN AND RIGHT */
{ 0x09ed, 0x2514 }, /* lowleftcorner └ BOX DRAWINGS LIGHT UP AND RIGHT */
{ 0x09ee, 0x253c }, /* crossinglines ┼ BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */
{ 0x09ef, 0x23ba }, /* horizlinescan1 ⎺ HORIZONTAL SCAN LINE-1 (Unicode 3.2 draft) */
{ 0x09f0, 0x23bb }, /* horizlinescan3 ⎻ HORIZONTAL SCAN LINE-3 (Unicode 3.2 draft) */
{ 0x09f1, 0x2500 }, /* horizlinescan5 ─ BOX DRAWINGS LIGHT HORIZONTAL */
{ 0x09f2, 0x23bc }, /* horizlinescan7 ⎼ HORIZONTAL SCAN LINE-7 (Unicode 3.2 draft) */
{ 0x09f3, 0x23bd }, /* horizlinescan9 ⎽ HORIZONTAL SCAN LINE-9 (Unicode 3.2 draft) */
{ 0x09f4, 0x251c }, /* leftt ├ BOX DRAWINGS LIGHT VERTICAL AND RIGHT */
{ 0x09f5, 0x2524 }, /* rightt ┤ BOX DRAWINGS LIGHT VERTICAL AND LEFT */
{ 0x09f6, 0x2534 }, /* bott ┴ BOX DRAWINGS LIGHT UP AND HORIZONTAL */
{ 0x09f7, 0x252c }, /* topt ┬ BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */
{ 0x09f8, 0x2502 }, /* vertbar │ BOX DRAWINGS LIGHT VERTICAL */
{ 0x0aa1, 0x2003 }, /* emspace EM SPACE */
{ 0x0aa2, 0x2002 }, /* enspace EN SPACE */
{ 0x0aa3, 0x2004 }, /* em3space THREE-PER-EM SPACE */
{ 0x0aa4, 0x2005 }, /* em4space FOUR-PER-EM SPACE */
{ 0x0aa5, 0x2007 }, /* digitspace FIGURE SPACE */
{ 0x0aa6, 0x2008 }, /* punctspace PUNCTUATION SPACE */
{ 0x0aa7, 0x2009 }, /* thinspace THIN SPACE */
{ 0x0aa8, 0x200a }, /* hairspace HAIR SPACE */
{ 0x0aa9, 0x2014 }, /* emdash — EM DASH */
{ 0x0aaa, 0x2013 }, /* endash EN DASH */
{ 0x0aac, 0x2423 }, /* signifblank ␣ OPEN BOX */
{ 0x0aae, 0x2026 }, /* ellipsis … HORIZONTAL ELLIPSIS */
{ 0x0aaf, 0x2025 }, /* doubbaselinedot ‥ TWO DOT LEADER */
{ 0x0ab0, 0x2153 }, /* onethird ⅓ VULGAR FRACTION ONE THIRD */
{ 0x0ab1, 0x2154 }, /* twothirds ⅔ VULGAR FRACTION TWO THIRDS */
{ 0x0ab2, 0x2155 }, /* onefifth ⅕ VULGAR FRACTION ONE FIFTH */
{ 0x0ab3, 0x2156 }, /* twofifths ⅖ VULGAR FRACTION TWO FIFTHS */
{ 0x0ab4, 0x2157 }, /* threefifths ⅗ VULGAR FRACTION THREE FIFTHS */
{ 0x0ab5, 0x2158 }, /* fourfifths ⅘ VULGAR FRACTION FOUR FIFTHS */
{ 0x0ab6, 0x2159 }, /* onesixth ⅙ VULGAR FRACTION ONE SIXTH */
{ 0x0ab7, 0x215a }, /* fivesixths ⅚ VULGAR FRACTION FIVE SIXTHS */
{ 0x0ab8, 0x2105 }, /* careof ℅ CARE OF */
{ 0x0abb, 0x2012 }, /* figdash FIGURE DASH */
{ 0x0abc, 0x27e8 }, /* leftanglebracket ⟨ MATHEMATICAL LEFT ANGLE BRACKET */
{ 0x0abd, 0x002e }, /* decimalpoint . FULL STOP */
{ 0x0abe, 0x27e9 }, /* rightanglebracket ⟩ MATHEMATICAL RIGHT ANGLE BRACKET */
/* 0x0abf marker ? ??? */
{ 0x0ac3, 0x215b }, /* oneeighth ⅛ VULGAR FRACTION ONE EIGHTH */
{ 0x0ac4, 0x215c }, /* threeeighths ⅜ VULGAR FRACTION THREE EIGHTHS */
{ 0x0ac5, 0x215d }, /* fiveeighths ⅝ VULGAR FRACTION FIVE EIGHTHS */
{ 0x0ac6, 0x215e }, /* seveneighths ⅞ VULGAR FRACTION SEVEN EIGHTHS */
{ 0x0ac9, 0x2122 }, /* trademark ™ TRADE MARK SIGN */
{ 0x0aca, 0x2613 }, /* signaturemark ☓ SALTIRE */
/* 0x0acb trademarkincircle ? ??? */
{ 0x0acc, 0x25c1 }, /* leftopentriangle ◁ WHITE LEFT-POINTING TRIANGLE */
{ 0x0acd, 0x25b7 }, /* rightopentriangle ▷ WHITE RIGHT-POINTING TRIANGLE */
{ 0x0ace, 0x25cb }, /* emopencircle ○ WHITE CIRCLE */
{ 0x0acf, 0x25af }, /* emopenrectangle ▯ WHITE VERTICAL RECTANGLE */
{ 0x0ad0, 0x2018 }, /* leftsinglequotemark LEFT SINGLE QUOTATION MARK */
{ 0x0ad1, 0x2019 }, /* rightsinglequotemark RIGHT SINGLE QUOTATION MARK */
{ 0x0ad2, 0x201c }, /* leftdoublequotemark “ LEFT DOUBLE QUOTATION MARK */
{ 0x0ad3, 0x201d }, /* rightdoublequotemark ” RIGHT DOUBLE QUOTATION MARK */
{ 0x0ad4, 0x211e }, /* prescription ℞ PRESCRIPTION TAKE */
{ 0x0ad5, 0x2030 }, /* permille ‰ PER MILLE SIGN */
{ 0x0ad6, 0x2032 }, /* minutes PRIME */
{ 0x0ad7, 0x2033 }, /* seconds ″ DOUBLE PRIME */
{ 0x0ad9, 0x271d }, /* latincross ✝ LATIN CROSS */
/* 0x0ada hexagram ? ??? */
{ 0x0adb, 0x25ac }, /* filledrectbullet ▬ BLACK RECTANGLE */
{ 0x0adc, 0x25c0 }, /* filledlefttribullet ◀ BLACK LEFT-POINTING TRIANGLE */
{ 0x0add, 0x25b6 }, /* filledrighttribullet ▶ BLACK RIGHT-POINTING TRIANGLE */
{ 0x0ade, 0x25cf }, /* emfilledcircle ● BLACK CIRCLE */
{ 0x0adf, 0x25ae }, /* emfilledrect ▮ BLACK VERTICAL RECTANGLE */
{ 0x0ae0, 0x25e6 }, /* enopencircbullet ◦ WHITE BULLET */
{ 0x0ae1, 0x25ab }, /* enopensquarebullet ▫ WHITE SMALL SQUARE */
{ 0x0ae2, 0x25ad }, /* openrectbullet ▭ WHITE RECTANGLE */
{ 0x0ae3, 0x25b3 }, /* opentribulletup △ WHITE UP-POINTING TRIANGLE */
{ 0x0ae4, 0x25bd }, /* opentribulletdown ▽ WHITE DOWN-POINTING TRIANGLE */
{ 0x0ae5, 0x2606 }, /* openstar ☆ WHITE STAR */
{ 0x0ae6, 0x2022 }, /* enfilledcircbullet • BULLET */
{ 0x0ae7, 0x25aa }, /* enfilledsqbullet ▪ BLACK SMALL SQUARE */
{ 0x0ae8, 0x25b2 }, /* filledtribulletup ▲ BLACK UP-POINTING TRIANGLE */
{ 0x0ae9, 0x25bc }, /* filledtribulletdown ▼ BLACK DOWN-POINTING TRIANGLE */
{ 0x0aea, 0x261c }, /* leftpointer ☜ WHITE LEFT POINTING INDEX */
{ 0x0aeb, 0x261e }, /* rightpointer ☞ WHITE RIGHT POINTING INDEX */
{ 0x0aec, 0x2663 }, /* club ♣ BLACK CLUB SUIT */
{ 0x0aed, 0x2666 }, /* diamond ♦ BLACK DIAMOND SUIT */
{ 0x0aee, 0x2665 }, /* heart ♥ BLACK HEART SUIT */
{ 0x0af0, 0x2720 }, /* maltesecross ✠ MALTESE CROSS */
{ 0x0af1, 0x2020 }, /* dagger † DAGGER */
{ 0x0af2, 0x2021 }, /* doubledagger ‡ DOUBLE DAGGER */
{ 0x0af3, 0x2713 }, /* checkmark ✓ CHECK MARK */
{ 0x0af4, 0x2717 }, /* ballotcross ✗ BALLOT X */
{ 0x0af5, 0x266f }, /* musicalsharp ♯ MUSIC SHARP SIGN */
{ 0x0af6, 0x266d }, /* musicalflat ♭ MUSIC FLAT SIGN */
{ 0x0af7, 0x2642 }, /* malesymbol ♂ MALE SIGN */
{ 0x0af8, 0x2640 }, /* femalesymbol ♀ FEMALE SIGN */
{ 0x0af9, 0x260e }, /* telephone ☎ BLACK TELEPHONE */
{ 0x0afa, 0x2315 }, /* telephonerecorder ⌕ TELEPHONE RECORDER */
{ 0x0afb, 0x2117 }, /* phonographcopyright ℗ SOUND RECORDING COPYRIGHT */
{ 0x0afc, 0x2038 }, /* caret ‸ CARET */
{ 0x0afd, 0x201a }, /* singlelowquotemark SINGLE LOW-9 QUOTATION MARK */
{ 0x0afe, 0x201e }, /* doublelowquotemark „ DOUBLE LOW-9 QUOTATION MARK */
/* 0x0aff cursor ? ??? */
{ 0x0ba3, 0x003c }, /* leftcaret < LESS-THAN SIGN */
{ 0x0ba6, 0x003e }, /* rightcaret > GREATER-THAN SIGN */
{ 0x0ba8, 0x2228 }, /* downcaret LOGICAL OR */
{ 0x0ba9, 0x2227 }, /* upcaret ∧ LOGICAL AND */
{ 0x0bc0, 0x00af }, /* overbar ¯ MACRON */
{ 0x0bc2, 0x22a4 }, /* downtack DOWN TACK */
{ 0x0bc3, 0x2229 }, /* upshoe ∩ INTERSECTION */
{ 0x0bc4, 0x230a }, /* downstile ⌊ LEFT FLOOR */
{ 0x0bc6, 0x005f }, /* underbar _ LOW LINE */
{ 0x0bca, 0x2218 }, /* jot ∘ RING OPERATOR */
{ 0x0bcc, 0x2395 }, /* quad ⎕ APL FUNCTIONAL SYMBOL QUAD (Unicode 3.0) */
{ 0x0bce, 0x22a5 }, /* uptack ⊥ UP TACK */
{ 0x0bcf, 0x25cb }, /* circle ○ WHITE CIRCLE */
{ 0x0bd3, 0x2308 }, /* upstile ⌈ LEFT CEILING */
{ 0x0bd6, 0x222a }, /* downshoe UNION */
{ 0x0bd8, 0x2283 }, /* rightshoe ⊃ SUPERSET OF */
{ 0x0bda, 0x2282 }, /* leftshoe ⊂ SUBSET OF */
{ 0x0bdc, 0x22a2 }, /* lefttack ⊢ RIGHT TACK */
{ 0x0bfc, 0x22a3 }, /* righttack ⊣ LEFT TACK */
{ 0x0cdf, 0x2017 }, /* hebrew_doublelowline ‗ DOUBLE LOW LINE */
{ 0x0ce0, 0x05d0 }, /* hebrew_aleph א HEBREW LETTER ALEF */
{ 0x0ce1, 0x05d1 }, /* hebrew_bet ב HEBREW LETTER BET */
{ 0x0ce2, 0x05d2 }, /* hebrew_gimel ג HEBREW LETTER GIMEL */
{ 0x0ce3, 0x05d3 }, /* hebrew_dalet ד HEBREW LETTER DALET */
{ 0x0ce4, 0x05d4 }, /* hebrew_he ה HEBREW LETTER HE */
{ 0x0ce5, 0x05d5 }, /* hebrew_waw ו HEBREW LETTER VAV */
{ 0x0ce6, 0x05d6 }, /* hebrew_zain ז HEBREW LETTER ZAYIN */
{ 0x0ce7, 0x05d7 }, /* hebrew_chet ח HEBREW LETTER HET */
{ 0x0ce8, 0x05d8 }, /* hebrew_tet ט HEBREW LETTER TET */
{ 0x0ce9, 0x05d9 }, /* hebrew_yod י HEBREW LETTER YOD */
{ 0x0cea, 0x05da }, /* hebrew_finalkaph ך HEBREW LETTER FINAL KAF */
{ 0x0ceb, 0x05db }, /* hebrew_kaph כ HEBREW LETTER KAF */
{ 0x0cec, 0x05dc }, /* hebrew_lamed ל HEBREW LETTER LAMED */
{ 0x0ced, 0x05dd }, /* hebrew_finalmem ם HEBREW LETTER FINAL MEM */
{ 0x0cee, 0x05de }, /* hebrew_mem מ HEBREW LETTER MEM */
{ 0x0cef, 0x05df }, /* hebrew_finalnun ן HEBREW LETTER FINAL NUN */
{ 0x0cf0, 0x05e0 }, /* hebrew_nun נ HEBREW LETTER NUN */
{ 0x0cf1, 0x05e1 }, /* hebrew_samech ס HEBREW LETTER SAMEKH */
{ 0x0cf2, 0x05e2 }, /* hebrew_ayin ע HEBREW LETTER AYIN */
{ 0x0cf3, 0x05e3 }, /* hebrew_finalpe ף HEBREW LETTER FINAL PE */
{ 0x0cf4, 0x05e4 }, /* hebrew_pe פ HEBREW LETTER PE */
{ 0x0cf5, 0x05e5 }, /* hebrew_finalzade ץ HEBREW LETTER FINAL TSADI */
{ 0x0cf6, 0x05e6 }, /* hebrew_zade צ HEBREW LETTER TSADI */
{ 0x0cf7, 0x05e7 }, /* hebrew_qoph ק HEBREW LETTER QOF */
{ 0x0cf8, 0x05e8 }, /* hebrew_resh ר HEBREW LETTER RESH */
{ 0x0cf9, 0x05e9 }, /* hebrew_shin ש HEBREW LETTER SHIN */
{ 0x0cfa, 0x05ea }, /* hebrew_taw ת HEBREW LETTER TAV */
{ 0x0da1, 0x0e01 }, /* Thai_kokai ก THAI CHARACTER KO KAI */
{ 0x0da2, 0x0e02 }, /* Thai_khokhai ข THAI CHARACTER KHO KHAI */
{ 0x0da3, 0x0e03 }, /* Thai_khokhuat ฃ THAI CHARACTER KHO KHUAT */
{ 0x0da4, 0x0e04 }, /* Thai_khokhwai ค THAI CHARACTER KHO KHWAI */
{ 0x0da5, 0x0e05 }, /* Thai_khokhon ฅ THAI CHARACTER KHO KHON */
{ 0x0da6, 0x0e06 }, /* Thai_khorakhang ฆ THAI CHARACTER KHO RAKHANG */
{ 0x0da7, 0x0e07 }, /* Thai_ngongu ง THAI CHARACTER NGO NGU */
{ 0x0da8, 0x0e08 }, /* Thai_chochan จ THAI CHARACTER CHO CHAN */
{ 0x0da9, 0x0e09 }, /* Thai_choching ฉ THAI CHARACTER CHO CHING */
{ 0x0daa, 0x0e0a }, /* Thai_chochang ช THAI CHARACTER CHO CHANG */
{ 0x0dab, 0x0e0b }, /* Thai_soso ซ THAI CHARACTER SO SO */
{ 0x0dac, 0x0e0c }, /* Thai_chochoe ฌ THAI CHARACTER CHO CHOE */
{ 0x0dad, 0x0e0d }, /* Thai_yoying ญ THAI CHARACTER YO YING */
{ 0x0dae, 0x0e0e }, /* Thai_dochada ฎ THAI CHARACTER DO CHADA */
{ 0x0daf, 0x0e0f }, /* Thai_topatak ฏ THAI CHARACTER TO PATAK */
{ 0x0db0, 0x0e10 }, /* Thai_thothan ฐ THAI CHARACTER THO THAN */
{ 0x0db1, 0x0e11 }, /* Thai_thonangmontho ฑ THAI CHARACTER THO NANGMONTHO */
{ 0x0db2, 0x0e12 }, /* Thai_thophuthao ฒ THAI CHARACTER THO PHUTHAO */
{ 0x0db3, 0x0e13 }, /* Thai_nonen ณ THAI CHARACTER NO NEN */
{ 0x0db4, 0x0e14 }, /* Thai_dodek ด THAI CHARACTER DO DEK */
{ 0x0db5, 0x0e15 }, /* Thai_totao ต THAI CHARACTER TO TAO */
{ 0x0db6, 0x0e16 }, /* Thai_thothung ถ THAI CHARACTER THO THUNG */
{ 0x0db7, 0x0e17 }, /* Thai_thothahan ท THAI CHARACTER THO THAHAN */
{ 0x0db8, 0x0e18 }, /* Thai_thothong ธ THAI CHARACTER THO THONG */
{ 0x0db9, 0x0e19 }, /* Thai_nonu น THAI CHARACTER NO NU */
{ 0x0dba, 0x0e1a }, /* Thai_bobaimai บ THAI CHARACTER BO BAIMAI */
{ 0x0dbb, 0x0e1b }, /* Thai_popla ป THAI CHARACTER PO PLA */
{ 0x0dbc, 0x0e1c }, /* Thai_phophung ผ THAI CHARACTER PHO PHUNG */
{ 0x0dbd, 0x0e1d }, /* Thai_fofa ฝ THAI CHARACTER FO FA */
{ 0x0dbe, 0x0e1e }, /* Thai_phophan พ THAI CHARACTER PHO PHAN */
{ 0x0dbf, 0x0e1f }, /* Thai_fofan ฟ THAI CHARACTER FO FAN */
{ 0x0dc0, 0x0e20 }, /* Thai_phosamphao ภ THAI CHARACTER PHO SAMPHAO */
{ 0x0dc1, 0x0e21 }, /* Thai_moma ม THAI CHARACTER MO MA */
{ 0x0dc2, 0x0e22 }, /* Thai_yoyak ย THAI CHARACTER YO YAK */
{ 0x0dc3, 0x0e23 }, /* Thai_rorua ร THAI CHARACTER RO RUA */
{ 0x0dc4, 0x0e24 }, /* Thai_ru ฤ THAI CHARACTER RU */
{ 0x0dc5, 0x0e25 }, /* Thai_loling ล THAI CHARACTER LO LING */
{ 0x0dc6, 0x0e26 }, /* Thai_lu ฦ THAI CHARACTER LU */
{ 0x0dc7, 0x0e27 }, /* Thai_wowaen ว THAI CHARACTER WO WAEN */
{ 0x0dc8, 0x0e28 }, /* Thai_sosala ศ THAI CHARACTER SO SALA */
{ 0x0dc9, 0x0e29 }, /* Thai_sorusi ษ THAI CHARACTER SO RUSI */
{ 0x0dca, 0x0e2a }, /* Thai_sosua ส THAI CHARACTER SO SUA */
{ 0x0dcb, 0x0e2b }, /* Thai_hohip ห THAI CHARACTER HO HIP */
{ 0x0dcc, 0x0e2c }, /* Thai_lochula ฬ THAI CHARACTER LO CHULA */
{ 0x0dcd, 0x0e2d }, /* Thai_oang อ THAI CHARACTER O ANG */
{ 0x0dce, 0x0e2e }, /* Thai_honokhuk ฮ THAI CHARACTER HO NOKHUK */
{ 0x0dcf, 0x0e2f }, /* Thai_paiyannoi ฯ THAI CHARACTER PAIYANNOI */
{ 0x0dd0, 0x0e30 }, /* Thai_saraa ะ THAI CHARACTER SARA A */
{ 0x0dd1, 0x0e31 }, /* Thai_maihanakat ั THAI CHARACTER MAI HAN-AKAT */
{ 0x0dd2, 0x0e32 }, /* Thai_saraaa า THAI CHARACTER SARA AA */
{ 0x0dd3, 0x0e33 }, /* Thai_saraam ำ THAI CHARACTER SARA AM */
{ 0x0dd4, 0x0e34 }, /* Thai_sarai ิ THAI CHARACTER SARA I */
{ 0x0dd5, 0x0e35 }, /* Thai_saraii ี THAI CHARACTER SARA II */
{ 0x0dd6, 0x0e36 }, /* Thai_saraue ึ THAI CHARACTER SARA UE */
{ 0x0dd7, 0x0e37 }, /* Thai_sarauee ื THAI CHARACTER SARA UEE */
{ 0x0dd8, 0x0e38 }, /* Thai_sarau ุ THAI CHARACTER SARA U */
{ 0x0dd9, 0x0e39 }, /* Thai_sarauu ู THAI CHARACTER SARA UU */
{ 0x0dda, 0x0e3a }, /* Thai_phinthu ฺ THAI CHARACTER PHINTHU */
{ 0x0dde, 0x0e3e }, /* Thai_maihanakat_maitho ฾ ??? */
{ 0x0ddf, 0x0e3f }, /* Thai_baht ฿ THAI CURRENCY SYMBOL BAHT */
{ 0x0de0, 0x0e40 }, /* Thai_sarae เ THAI CHARACTER SARA E */
{ 0x0de1, 0x0e41 }, /* Thai_saraae แ THAI CHARACTER SARA AE */
{ 0x0de2, 0x0e42 }, /* Thai_sarao โ THAI CHARACTER SARA O */
{ 0x0de3, 0x0e43 }, /* Thai_saraaimaimuan ใ THAI CHARACTER SARA AI MAIMUAN */
{ 0x0de4, 0x0e44 }, /* Thai_saraaimaimalai ไ THAI CHARACTER SARA AI MAIMALAI */
{ 0x0de5, 0x0e45 }, /* Thai_lakkhangyao ๅ THAI CHARACTER LAKKHANGYAO */
{ 0x0de6, 0x0e46 }, /* Thai_maiyamok ๆ THAI CHARACTER MAIYAMOK */
{ 0x0de7, 0x0e47 }, /* Thai_maitaikhu ็ THAI CHARACTER MAITAIKHU */
{ 0x0de8, 0x0e48 }, /* Thai_maiek ่ THAI CHARACTER MAI EK */
{ 0x0de9, 0x0e49 }, /* Thai_maitho ้ THAI CHARACTER MAI THO */
{ 0x0dea, 0x0e4a }, /* Thai_maitri ๊ THAI CHARACTER MAI TRI */
{ 0x0deb, 0x0e4b }, /* Thai_maichattawa ๋ THAI CHARACTER MAI CHATTAWA */
{ 0x0dec, 0x0e4c }, /* Thai_thanthakhat ์ THAI CHARACTER THANTHAKHAT */
{ 0x0ded, 0x0e4d }, /* Thai_nikhahit ํ THAI CHARACTER NIKHAHIT */
{ 0x0df0, 0x0e50 }, /* Thai_leksun THAI DIGIT ZERO */
{ 0x0df1, 0x0e51 }, /* Thai_leknung ๑ THAI DIGIT ONE */
{ 0x0df2, 0x0e52 }, /* Thai_leksong ๒ THAI DIGIT TWO */
{ 0x0df3, 0x0e53 }, /* Thai_leksam ๓ THAI DIGIT THREE */
{ 0x0df4, 0x0e54 }, /* Thai_leksi ๔ THAI DIGIT FOUR */
{ 0x0df5, 0x0e55 }, /* Thai_lekha ๕ THAI DIGIT FIVE */
{ 0x0df6, 0x0e56 }, /* Thai_lekhok ๖ THAI DIGIT SIX */
{ 0x0df7, 0x0e57 }, /* Thai_lekchet ๗ THAI DIGIT SEVEN */
{ 0x0df8, 0x0e58 }, /* Thai_lekpaet ๘ THAI DIGIT EIGHT */
{ 0x0df9, 0x0e59 }, /* Thai_lekkao ๙ THAI DIGIT NINE */
{ 0x0ea1, 0x3131 }, /* Hangul_Kiyeog ㄱ HANGUL LETTER KIYEOK */
{ 0x0ea2, 0x3132 }, /* Hangul_SsangKiyeog ㄲ HANGUL LETTER SSANGKIYEOK */
{ 0x0ea3, 0x3133 }, /* Hangul_KiyeogSios ㄳ HANGUL LETTER KIYEOK-SIOS */
{ 0x0ea4, 0x3134 }, /* Hangul_Nieun ㄴ HANGUL LETTER NIEUN */
{ 0x0ea5, 0x3135 }, /* Hangul_NieunJieuj ㄵ HANGUL LETTER NIEUN-CIEUC */
{ 0x0ea6, 0x3136 }, /* Hangul_NieunHieuh ㄶ HANGUL LETTER NIEUN-HIEUH */
{ 0x0ea7, 0x3137 }, /* Hangul_Dikeud ㄷ HANGUL LETTER TIKEUT */
{ 0x0ea8, 0x3138 }, /* Hangul_SsangDikeud ㄸ HANGUL LETTER SSANGTIKEUT */
{ 0x0ea9, 0x3139 }, /* Hangul_Rieul ㄹ HANGUL LETTER RIEUL */
{ 0x0eaa, 0x313a }, /* Hangul_RieulKiyeog ㄺ HANGUL LETTER RIEUL-KIYEOK */
{ 0x0eab, 0x313b }, /* Hangul_RieulMieum ㄻ HANGUL LETTER RIEUL-MIEUM */
{ 0x0eac, 0x313c }, /* Hangul_RieulPieub ㄼ HANGUL LETTER RIEUL-PIEUP */
{ 0x0ead, 0x313d }, /* Hangul_RieulSios ㄽ HANGUL LETTER RIEUL-SIOS */
{ 0x0eae, 0x313e }, /* Hangul_RieulTieut ㄾ HANGUL LETTER RIEUL-THIEUTH */
{ 0x0eaf, 0x313f }, /* Hangul_RieulPhieuf ㄿ HANGUL LETTER RIEUL-PHIEUPH */
{ 0x0eb0, 0x3140 }, /* Hangul_RieulHieuh ㅀ HANGUL LETTER RIEUL-HIEUH */
{ 0x0eb1, 0x3141 }, /* Hangul_Mieum ㅁ HANGUL LETTER MIEUM */
{ 0x0eb2, 0x3142 }, /* Hangul_Pieub ㅂ HANGUL LETTER PIEUP */
{ 0x0eb3, 0x3143 }, /* Hangul_SsangPieub ㅃ HANGUL LETTER SSANGPIEUP */
{ 0x0eb4, 0x3144 }, /* Hangul_PieubSios ㅄ HANGUL LETTER PIEUP-SIOS */
{ 0x0eb5, 0x3145 }, /* Hangul_Sios ㅅ HANGUL LETTER SIOS */
{ 0x0eb6, 0x3146 }, /* Hangul_SsangSios ㅆ HANGUL LETTER SSANGSIOS */
{ 0x0eb7, 0x3147 }, /* Hangul_Ieung ㅇ HANGUL LETTER IEUNG */
{ 0x0eb8, 0x3148 }, /* Hangul_Jieuj ㅈ HANGUL LETTER CIEUC */
{ 0x0eb9, 0x3149 }, /* Hangul_SsangJieuj ㅉ HANGUL LETTER SSANGCIEUC */
{ 0x0eba, 0x314a }, /* Hangul_Cieuc ㅊ HANGUL LETTER CHIEUCH */
{ 0x0ebb, 0x314b }, /* Hangul_Khieuq ㅋ HANGUL LETTER KHIEUKH */
{ 0x0ebc, 0x314c }, /* Hangul_Tieut ㅌ HANGUL LETTER THIEUTH */
{ 0x0ebd, 0x314d }, /* Hangul_Phieuf ㅍ HANGUL LETTER PHIEUPH */
{ 0x0ebe, 0x314e }, /* Hangul_Hieuh ㅎ HANGUL LETTER HIEUH */
{ 0x0ebf, 0x314f }, /* Hangul_A ㅏ HANGUL LETTER A */
{ 0x0ec0, 0x3150 }, /* Hangul_AE ㅐ HANGUL LETTER AE */
{ 0x0ec1, 0x3151 }, /* Hangul_YA ㅑ HANGUL LETTER YA */
{ 0x0ec2, 0x3152 }, /* Hangul_YAE ㅒ HANGUL LETTER YAE */
{ 0x0ec3, 0x3153 }, /* Hangul_EO ㅓ HANGUL LETTER EO */
{ 0x0ec4, 0x3154 }, /* Hangul_E ㅔ HANGUL LETTER E */
{ 0x0ec5, 0x3155 }, /* Hangul_YEO ㅕ HANGUL LETTER YEO */
{ 0x0ec6, 0x3156 }, /* Hangul_YE ㅖ HANGUL LETTER YE */
{ 0x0ec7, 0x3157 }, /* Hangul_O ㅗ HANGUL LETTER O */
{ 0x0ec8, 0x3158 }, /* Hangul_WA ㅘ HANGUL LETTER WA */
{ 0x0ec9, 0x3159 }, /* Hangul_WAE ㅙ HANGUL LETTER WAE */
{ 0x0eca, 0x315a }, /* Hangul_OE ㅚ HANGUL LETTER OE */
{ 0x0ecb, 0x315b }, /* Hangul_YO ㅛ HANGUL LETTER YO */
{ 0x0ecc, 0x315c }, /* Hangul_U ㅜ HANGUL LETTER U */
{ 0x0ecd, 0x315d }, /* Hangul_WEO ㅝ HANGUL LETTER WEO */
{ 0x0ece, 0x315e }, /* Hangul_WE ㅞ HANGUL LETTER WE */
{ 0x0ecf, 0x315f }, /* Hangul_WI ㅟ HANGUL LETTER WI */
{ 0x0ed0, 0x3160 }, /* Hangul_YU ㅠ HANGUL LETTER YU */
{ 0x0ed1, 0x3161 }, /* Hangul_EU ㅡ HANGUL LETTER EU */
{ 0x0ed2, 0x3162 }, /* Hangul_YI ㅢ HANGUL LETTER YI */
{ 0x0ed3, 0x3163 }, /* Hangul_I ㅣ HANGUL LETTER I */
{ 0x0ed4, 0x11a8 }, /* Hangul_J_Kiyeog ᆨ HANGUL JONGSEONG KIYEOK */
{ 0x0ed5, 0x11a9 }, /* Hangul_J_SsangKiyeog ᆩ HANGUL JONGSEONG SSANGKIYEOK */
{ 0x0ed6, 0x11aa }, /* Hangul_J_KiyeogSios ᆪ HANGUL JONGSEONG KIYEOK-SIOS */
{ 0x0ed7, 0x11ab }, /* Hangul_J_Nieun ᆫ HANGUL JONGSEONG NIEUN */
{ 0x0ed8, 0x11ac }, /* Hangul_J_NieunJieuj ᆬ HANGUL JONGSEONG NIEUN-CIEUC */
{ 0x0ed9, 0x11ad }, /* Hangul_J_NieunHieuh ᆭ HANGUL JONGSEONG NIEUN-HIEUH */
{ 0x0eda, 0x11ae }, /* Hangul_J_Dikeud ᆮ HANGUL JONGSEONG TIKEUT */
{ 0x0edb, 0x11af }, /* Hangul_J_Rieul ᆯ HANGUL JONGSEONG RIEUL */
{ 0x0edc, 0x11b0 }, /* Hangul_J_RieulKiyeog ᆰ HANGUL JONGSEONG RIEUL-KIYEOK */
{ 0x0edd, 0x11b1 }, /* Hangul_J_RieulMieum ᆱ HANGUL JONGSEONG RIEUL-MIEUM */
{ 0x0ede, 0x11b2 }, /* Hangul_J_RieulPieub ᆲ HANGUL JONGSEONG RIEUL-PIEUP */
{ 0x0edf, 0x11b3 }, /* Hangul_J_RieulSios ᆳ HANGUL JONGSEONG RIEUL-SIOS */
{ 0x0ee0, 0x11b4 }, /* Hangul_J_RieulTieut ᆴ HANGUL JONGSEONG RIEUL-THIEUTH */
{ 0x0ee1, 0x11b5 }, /* Hangul_J_RieulPhieuf ᆵ HANGUL JONGSEONG RIEUL-PHIEUPH */
{ 0x0ee2, 0x11b6 }, /* Hangul_J_RieulHieuh ᆶ HANGUL JONGSEONG RIEUL-HIEUH */
{ 0x0ee3, 0x11b7 }, /* Hangul_J_Mieum ᆷ HANGUL JONGSEONG MIEUM */
{ 0x0ee4, 0x11b8 }, /* Hangul_J_Pieub ᆸ HANGUL JONGSEONG PIEUP */
{ 0x0ee5, 0x11b9 }, /* Hangul_J_PieubSios ᆹ HANGUL JONGSEONG PIEUP-SIOS */
{ 0x0ee6, 0x11ba }, /* Hangul_J_Sios ᆺ HANGUL JONGSEONG SIOS */
{ 0x0ee7, 0x11bb }, /* Hangul_J_SsangSios ᆻ HANGUL JONGSEONG SSANGSIOS */
{ 0x0ee8, 0x11bc }, /* Hangul_J_Ieung ᆼ HANGUL JONGSEONG IEUNG */
{ 0x0ee9, 0x11bd }, /* Hangul_J_Jieuj ᆽ HANGUL JONGSEONG CIEUC */
{ 0x0eea, 0x11be }, /* Hangul_J_Cieuc ᆾ HANGUL JONGSEONG CHIEUCH */
{ 0x0eeb, 0x11bf }, /* Hangul_J_Khieuq ᆿ HANGUL JONGSEONG KHIEUKH */
{ 0x0eec, 0x11c0 }, /* Hangul_J_Tieut ᇀ HANGUL JONGSEONG THIEUTH */
{ 0x0eed, 0x11c1 }, /* Hangul_J_Phieuf ᇁ HANGUL JONGSEONG PHIEUPH */
{ 0x0eee, 0x11c2 }, /* Hangul_J_Hieuh ᇂ HANGUL JONGSEONG HIEUH */
{ 0x0eef, 0x316d }, /* Hangul_RieulYeorinHieuh ㅭ HANGUL LETTER RIEUL-YEORINHIEUH */
{ 0x0ef0, 0x3171 }, /* Hangul_SunkyeongeumMieum ㅱ HANGUL LETTER KAPYEOUNMIEUM */
{ 0x0ef1, 0x3178 }, /* Hangul_SunkyeongeumPieub ㅸ HANGUL LETTER KAPYEOUNPIEUP */
{ 0x0ef2, 0x317f }, /* Hangul_PanSios ㅿ HANGUL LETTER PANSIOS */
/* 0x0ef3 Hangul_KkogjiDalrinIeung ? ??? */
{ 0x0ef4, 0x3184 }, /* Hangul_SunkyeongeumPhieuf ㆄ HANGUL LETTER KAPYEOUNPHIEUPH */
{ 0x0ef5, 0x3186 }, /* Hangul_YeorinHieuh ㆆ HANGUL LETTER YEORINHIEUH */
{ 0x0ef6, 0x318d }, /* Hangul_AraeA ㆍ HANGUL LETTER ARAEA */
{ 0x0ef7, 0x318e }, /* Hangul_AraeAE ㆎ HANGUL LETTER ARAEAE */
{ 0x0ef8, 0x11eb }, /* Hangul_J_PanSios ᇫ HANGUL JONGSEONG PANSIOS */
{ 0x0ef9, 0x11f0 }, /* Hangul_J_KkogjiDalrinIeung ᇰ HANGUL JONGSEONG YESIEUNG */
{ 0x0efa, 0x11f9 }, /* Hangul_J_YeorinHieuh ᇹ HANGUL JONGSEONG YEORINHIEUH */
{ 0x0eff, 0x20a9 }, /* Korean_Won ₩ WON SIGN */
{ 0x13a4, 0x20ac }, /* Euro € EURO SIGN */
{ 0x13bc, 0x0152 }, /* OE Œ LATIN CAPITAL LIGATURE OE */
{ 0x13bd, 0x0153 }, /* oe œ LATIN SMALL LIGATURE OE */
{ 0x13be, 0x0178 }, /* Ydiaeresis Ÿ LATIN CAPITAL LETTER Y WITH DIAERESIS */
{ 0x20a0, 0x20a0 }, /* EcuSign ₠ EURO-CURRENCY SIGN */
{ 0x20a1, 0x20a1 }, /* ColonSign ₡ COLON SIGN */
{ 0x20a2, 0x20a2 }, /* CruzeiroSign ₢ CRUZEIRO SIGN */
{ 0x20a3, 0x20a3 }, /* FFrancSign ₣ FRENCH FRANC SIGN */
{ 0x20a4, 0x20a4 }, /* LiraSign ₤ LIRA SIGN */
{ 0x20a5, 0x20a5 }, /* MillSign ₥ MILL SIGN */
{ 0x20a6, 0x20a6 }, /* NairaSign ₦ NAIRA SIGN */
{ 0x20a7, 0x20a7 }, /* PesetaSign ₧ PESETA SIGN */
{ 0x20a8, 0x20a8 }, /* RupeeSign ₨ RUPEE SIGN */
{ 0x20a9, 0x20a9 }, /* WonSign ₩ WON SIGN */
{ 0x20aa, 0x20aa }, /* NewSheqelSign ₪ NEW SHEQEL SIGN */
{ 0x20ab, 0x20ab }, /* DongSign ₫ DONG SIGN */
{ 0x20ac, 0x20ac }, /* EuroSign € EURO SIGN */
};
/* binary search with range check */
static uint32_t
bin_search(const struct codepair *table, size_t length, xkb_keysym_t keysym)
{
size_t first = 0;
size_t last = length;
if (keysym < table[0].keysym || keysym > table[length].keysym)
return 0;
/* binary search in table */
while (last >= first) {
size_t mid = (first + last) / 2;
if (table[mid].keysym < keysym)
first = mid + 1;
else if (table[mid].keysym > keysym)
last = mid - 1;
else /* found it */
return table[mid].ucs;
}
/* no matching Unicode value found in table */
return 0;
}
XKB_EXPORT uint32_t
xkb_keysym_to_utf32(xkb_keysym_t keysym)
{
/* first check for Latin-1 characters (1:1 mapping) */
if ((keysym >= 0x0020 && keysym <= 0x007e) ||
(keysym >= 0x00a0 && keysym <= 0x00ff))
return keysym;
/* patch encoding botch */
if (keysym == XKB_KEY_KP_Space)
return XKB_KEY_space & 0x7f;
/* special keysyms */
if ((keysym >= XKB_KEY_BackSpace && keysym <= XKB_KEY_Clear) ||
(keysym >= XKB_KEY_KP_Multiply && keysym <= XKB_KEY_KP_9) ||
keysym == XKB_KEY_Return || keysym == XKB_KEY_Escape ||
keysym == XKB_KEY_Delete || keysym == XKB_KEY_KP_Tab ||
keysym == XKB_KEY_KP_Enter || keysym == XKB_KEY_KP_Equal)
return keysym & 0x7f;
/* also check for directly encoded Unicode codepoints */
/*
* In theory, this is supposed to start from 0x100100, such that the ASCII
* range, which is already covered by 0x00-0xff, can't be encoded in two
* ways. However, changing this after a couple of decades probably won't
* go well, so it stays as it is.
*/
if (0x01000000 <= keysym && keysym <= 0x0110ffff)
return keysym - 0x01000000;
/* search main table */
return bin_search(keysymtab, ARRAY_SIZE(keysymtab) - 1, keysym);
}
/*
* Copyright © 2012 Intel Corporation
*
* 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 (including the next
* paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
*
* Author: Rob Bradford <rob@linux.intel.com>
*/
XKB_EXPORT int
xkb_keysym_to_utf8(xkb_keysym_t keysym, char *buffer, size_t size)
{
uint32_t codepoint;
if (size < 7)
return -1;
codepoint = xkb_keysym_to_utf32(keysym);
if (codepoint == 0)
return 0;
return utf32_to_utf8(codepoint, buffer);
}

View File

@ -1,762 +0,0 @@
/*
* Copyright 1985, 1987, 1990, 1998 The Open Group
*
* 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
* AUTHORS 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 names of the authors or their
* institutions 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 authors.
*/
/*
* Copyright © 2009 Dan Nicholson
*
* 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 (including the next
* paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
*/
#include <stdlib.h>
#include "xkbcommon/xkbcommon.h"
#include "utils.h"
#include "keysym.h"
#include "ks_tables.h"
static inline const char *
get_name(const struct name_keysym *entry)
{
return keysym_names + entry->offset;
}
static int
compare_by_keysym(const void *a, const void *b)
{
const xkb_keysym_t *key = a;
const struct name_keysym *entry = b;
if (*key < entry->keysym)
return -1;
if (*key > entry->keysym)
return 1;
return 0;
}
static int
compare_by_name(const void *a, const void *b)
{
const char *key = a;
const struct name_keysym *entry = b;
return istrcmp(key, get_name(entry));
}
XKB_EXPORT int
xkb_keysym_get_name(xkb_keysym_t ks, char *buffer, size_t size)
{
const struct name_keysym *entry;
if ((ks & ((unsigned long) ~0x1fffffff)) != 0) {
snprintf(buffer, size, "Invalid");
return -1;
}
entry = bsearch(&ks, keysym_to_name,
ARRAY_SIZE(keysym_to_name),
sizeof(*keysym_to_name),
compare_by_keysym);
if (entry)
return snprintf(buffer, size, "%s", get_name(entry));
/* Unnamed Unicode codepoint. */
if (ks >= 0x01000100 && ks <= 0x0110ffff) {
const int width = (ks & 0xff0000UL) ? 8 : 4;
return snprintf(buffer, size, "U%0*lX", width, ks & 0xffffffUL);
}
/* Unnamed, non-Unicode, symbol (shouldn't generally happen). */
return snprintf(buffer, size, "0x%08x", ks);
}
/*
* Find the correct keysym if one case-insensitive match is given.
*
* The name_to_keysym table is sorted by istrcmp(). So bsearch() may return
* _any_ of all possible case-insensitive duplicates. This function searches the
* returned entry @entry, all previous and all next entries that match by
* case-insensitive comparison and returns the exact match to @name. If @icase
* is true, then this returns the best case-insensitive match instead of a
* correct match.
* The "best" case-insensitive match is the lower-case keysym which we find with
* the help of xkb_keysym_is_lower().
* The only keysyms that only differ by letter-case are keysyms that are
* available as lower-case and upper-case variant (like KEY_a and KEY_A). So
* returning the first lower-case match is enough in this case.
*/
static const struct name_keysym *
find_sym(const struct name_keysym *entry, const char *name, bool icase)
{
const struct name_keysym *iter, *last;
size_t len = ARRAY_SIZE(name_to_keysym);
if (!entry)
return NULL;
if (!icase && strcmp(get_name(entry), name) == 0)
return entry;
if (icase && xkb_keysym_is_lower(entry->keysym))
return entry;
for (iter = entry - 1; iter >= name_to_keysym; --iter) {
if (!icase && strcmp(get_name(iter), name) == 0)
return iter;
if (istrcmp(get_name(iter), get_name(entry)) != 0)
break;
if (icase && xkb_keysym_is_lower(iter->keysym))
return iter;
}
last = name_to_keysym + len;
for (iter = entry + 1; iter < last; ++iter) {
if (!icase && strcmp(get_name(iter), name) == 0)
return iter;
if (istrcmp(get_name(iter), get_name(entry)) != 0)
break;
if (icase && xkb_keysym_is_lower(iter->keysym))
return iter;
}
if (icase)
return entry;
return NULL;
}
XKB_EXPORT xkb_keysym_t
xkb_keysym_from_name(const char *s, enum xkb_keysym_flags flags)
{
const struct name_keysym *entry;
char *tmp;
xkb_keysym_t val;
bool icase = (flags & XKB_KEYSYM_CASE_INSENSITIVE);
if (flags & ~XKB_KEYSYM_CASE_INSENSITIVE)
return XKB_KEY_NoSymbol;
entry = bsearch(s, name_to_keysym,
ARRAY_SIZE(name_to_keysym),
sizeof(*name_to_keysym),
compare_by_name);
entry = find_sym(entry, s, icase);
if (entry)
return entry->keysym;
if (*s == 'U' || (icase && *s == 'u')) {
val = strtoul(&s[1], &tmp, 16);
if (tmp && *tmp != '\0')
return XKB_KEY_NoSymbol;
if (val < 0x20 || (val > 0x7e && val < 0xa0))
return XKB_KEY_NoSymbol;
if (val < 0x100)
return val;
if (val > 0x10ffff)
return XKB_KEY_NoSymbol;
return val | 0x01000000;
}
else if (s[0] == '0' && (s[1] == 'x' || (icase && s[1] == 'X'))) {
val = strtoul(&s[2], &tmp, 16);
if (tmp && *tmp != '\0')
return XKB_KEY_NoSymbol;
return val;
}
/* Stupid inconsistency between the headers and XKeysymDB: the former has
* no separating underscore, while some XF86* syms in the latter did.
* As a last ditch effort, try without. */
if (strncmp(s, "XF86_", 5) == 0 ||
(icase && strncasecmp(s, "XF86_", 5) == 0)) {
xkb_keysym_t ret;
tmp = strdup(s);
if (!tmp)
return XKB_KEY_NoSymbol;
memmove(&tmp[4], &tmp[5], strlen(s) - 5 + 1);
ret = xkb_keysym_from_name(tmp, flags);
free(tmp);
return ret;
}
return XKB_KEY_NoSymbol;
}
bool
xkb_keysym_is_keypad(xkb_keysym_t keysym)
{
return keysym >= XKB_KEY_KP_Space && keysym <= XKB_KEY_KP_Equal;
}
bool
xkb_keysym_is_modifier(xkb_keysym_t keysym)
{
return
(keysym >= XKB_KEY_Shift_L && keysym <= XKB_KEY_Hyper_R) ||
/* libX11 only goes upto XKB_KEY_ISO_Level5_Lock. */
(keysym >= XKB_KEY_ISO_Lock && keysym <= XKB_KEY_ISO_Last_Group_Lock) ||
keysym == XKB_KEY_Mode_switch ||
keysym == XKB_KEY_Num_Lock;
}
static void
XConvertCase(xkb_keysym_t sym, xkb_keysym_t *lower, xkb_keysym_t *upper);
bool
xkb_keysym_is_lower(xkb_keysym_t ks)
{
xkb_keysym_t lower, upper;
XConvertCase(ks, &lower, &upper);
if (lower == upper)
return false;
return (ks == lower ? true : false);
}
bool
xkb_keysym_is_upper(xkb_keysym_t ks)
{
xkb_keysym_t lower, upper;
XConvertCase(ks, &lower, &upper);
if (lower == upper)
return false;
return (ks == upper ? true : false);
}
XKB_EXPORT xkb_keysym_t
xkb_keysym_to_lower(xkb_keysym_t ks)
{
xkb_keysym_t lower, upper;
XConvertCase(ks, &lower, &upper);
return lower;
}
XKB_EXPORT xkb_keysym_t
xkb_keysym_to_upper(xkb_keysym_t ks)
{
xkb_keysym_t lower, upper;
XConvertCase(ks, &lower, &upper);
return upper;
}
/*
* The following is copied verbatim from libX11:src/KeyBind.c, commit
* d45b3fc19fbe95c41afc4e51d768df6d42332010, with the following changes:
* - unsigned -> uint32_t
* - unsigend short -> uint16_t
* - s/XK_/XKB_KEY_
*
* XXX: If newlocale() and iswlower_l()/iswupper_l() interface ever
* become portable, we should use that in conjunction with
* xkb_keysym_to_utf32(), instead of all this stuff. We should
* be sure to give the same results as libX11, though, and be
* locale independent; this information is used by xkbcomp to
* find the automatic type to assign to key groups.
*/
static void
UCSConvertCase(uint32_t code, xkb_keysym_t *lower, xkb_keysym_t *upper)
{
/* Case conversion for UCS, as in Unicode Data version 4.0.0 */
/* NB: Only converts simple one-to-one mappings. */
/* Tables are used where they take less space than */
/* the code to work out the mappings. Zero values mean */
/* undefined code points. */
static uint16_t const IPAExt_upper_mapping[] = { /* part only */
0x0181, 0x0186, 0x0255, 0x0189, 0x018A,
0x0258, 0x018F, 0x025A, 0x0190, 0x025C, 0x025D, 0x025E, 0x025F,
0x0193, 0x0261, 0x0262, 0x0194, 0x0264, 0x0265, 0x0266, 0x0267,
0x0197, 0x0196, 0x026A, 0x026B, 0x026C, 0x026D, 0x026E, 0x019C,
0x0270, 0x0271, 0x019D, 0x0273, 0x0274, 0x019F, 0x0276, 0x0277,
0x0278, 0x0279, 0x027A, 0x027B, 0x027C, 0x027D, 0x027E, 0x027F,
0x01A6, 0x0281, 0x0282, 0x01A9, 0x0284, 0x0285, 0x0286, 0x0287,
0x01AE, 0x0289, 0x01B1, 0x01B2, 0x028C, 0x028D, 0x028E, 0x028F,
0x0290, 0x0291, 0x01B7
};
static uint16_t const LatinExtB_upper_mapping[] = { /* first part only */
0x0180, 0x0181, 0x0182, 0x0182, 0x0184, 0x0184, 0x0186, 0x0187,
0x0187, 0x0189, 0x018A, 0x018B, 0x018B, 0x018D, 0x018E, 0x018F,
0x0190, 0x0191, 0x0191, 0x0193, 0x0194, 0x01F6, 0x0196, 0x0197,
0x0198, 0x0198, 0x019A, 0x019B, 0x019C, 0x019D, 0x0220, 0x019F,
0x01A0, 0x01A0, 0x01A2, 0x01A2, 0x01A4, 0x01A4, 0x01A6, 0x01A7,
0x01A7, 0x01A9, 0x01AA, 0x01AB, 0x01AC, 0x01AC, 0x01AE, 0x01AF,
0x01AF, 0x01B1, 0x01B2, 0x01B3, 0x01B3, 0x01B5, 0x01B5, 0x01B7,
0x01B8, 0x01B8, 0x01BA, 0x01BB, 0x01BC, 0x01BC, 0x01BE, 0x01F7,
0x01C0, 0x01C1, 0x01C2, 0x01C3, 0x01C4, 0x01C4, 0x01C4, 0x01C7,
0x01C7, 0x01C7, 0x01CA, 0x01CA, 0x01CA
};
static uint16_t const LatinExtB_lower_mapping[] = { /* first part only */
0x0180, 0x0253, 0x0183, 0x0183, 0x0185, 0x0185, 0x0254, 0x0188,
0x0188, 0x0256, 0x0257, 0x018C, 0x018C, 0x018D, 0x01DD, 0x0259,
0x025B, 0x0192, 0x0192, 0x0260, 0x0263, 0x0195, 0x0269, 0x0268,
0x0199, 0x0199, 0x019A, 0x019B, 0x026F, 0x0272, 0x019E, 0x0275,
0x01A1, 0x01A1, 0x01A3, 0x01A3, 0x01A5, 0x01A5, 0x0280, 0x01A8,
0x01A8, 0x0283, 0x01AA, 0x01AB, 0x01AD, 0x01AD, 0x0288, 0x01B0,
0x01B0, 0x028A, 0x028B, 0x01B4, 0x01B4, 0x01B6, 0x01B6, 0x0292,
0x01B9, 0x01B9, 0x01BA, 0x01BB, 0x01BD, 0x01BD, 0x01BE, 0x01BF,
0x01C0, 0x01C1, 0x01C2, 0x01C3, 0x01C6, 0x01C6, 0x01C6, 0x01C9,
0x01C9, 0x01C9, 0x01CC, 0x01CC, 0x01CC
};
static uint16_t const Greek_upper_mapping[] = {
0x0000, 0x0000, 0x0000, 0x0000, 0x0374, 0x0375, 0x0000, 0x0000,
0x0000, 0x0000, 0x037A, 0x0000, 0x0000, 0x0000, 0x037E, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0384, 0x0385, 0x0386, 0x0387,
0x0388, 0x0389, 0x038A, 0x0000, 0x038C, 0x0000, 0x038E, 0x038F,
0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397,
0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F,
0x03A0, 0x03A1, 0x0000, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7,
0x03A8, 0x03A9, 0x03AA, 0x03AB, 0x0386, 0x0388, 0x0389, 0x038A,
0x03B0, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397,
0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F,
0x03A0, 0x03A1, 0x03A3, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7,
0x03A8, 0x03A9, 0x03AA, 0x03AB, 0x038C, 0x038E, 0x038F, 0x0000,
0x0392, 0x0398, 0x03D2, 0x03D3, 0x03D4, 0x03A6, 0x03A0, 0x03D7,
0x03D8, 0x03D8, 0x03DA, 0x03DA, 0x03DC, 0x03DC, 0x03DE, 0x03DE,
0x03E0, 0x03E0, 0x03E2, 0x03E2, 0x03E4, 0x03E4, 0x03E6, 0x03E6,
0x03E8, 0x03E8, 0x03EA, 0x03EA, 0x03EC, 0x03EC, 0x03EE, 0x03EE,
0x039A, 0x03A1, 0x03F9, 0x03F3, 0x03F4, 0x0395, 0x03F6, 0x03F7,
0x03F7, 0x03F9, 0x03FA, 0x03FA, 0x0000, 0x0000, 0x0000, 0x0000
};
static uint16_t const Greek_lower_mapping[] = {
0x0000, 0x0000, 0x0000, 0x0000, 0x0374, 0x0375, 0x0000, 0x0000,
0x0000, 0x0000, 0x037A, 0x0000, 0x0000, 0x0000, 0x037E, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0384, 0x0385, 0x03AC, 0x0387,
0x03AD, 0x03AE, 0x03AF, 0x0000, 0x03CC, 0x0000, 0x03CD, 0x03CE,
0x0390, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7,
0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
0x03C0, 0x03C1, 0x0000, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7,
0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03AC, 0x03AD, 0x03AE, 0x03AF,
0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7,
0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7,
0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0x0000,
0x03D0, 0x03D1, 0x03D2, 0x03D3, 0x03D4, 0x03D5, 0x03D6, 0x03D7,
0x03D9, 0x03D9, 0x03DB, 0x03DB, 0x03DD, 0x03DD, 0x03DF, 0x03DF,
0x03E1, 0x03E1, 0x03E3, 0x03E3, 0x03E5, 0x03E5, 0x03E7, 0x03E7,
0x03E9, 0x03E9, 0x03EB, 0x03EB, 0x03ED, 0x03ED, 0x03EF, 0x03EF,
0x03F0, 0x03F1, 0x03F2, 0x03F3, 0x03B8, 0x03F5, 0x03F6, 0x03F8,
0x03F8, 0x03F2, 0x03FB, 0x03FB, 0x0000, 0x0000, 0x0000, 0x0000
};
static uint16_t const GreekExt_lower_mapping[] = {
0x1F00, 0x1F01, 0x1F02, 0x1F03, 0x1F04, 0x1F05, 0x1F06, 0x1F07,
0x1F00, 0x1F01, 0x1F02, 0x1F03, 0x1F04, 0x1F05, 0x1F06, 0x1F07,
0x1F10, 0x1F11, 0x1F12, 0x1F13, 0x1F14, 0x1F15, 0x0000, 0x0000,
0x1F10, 0x1F11, 0x1F12, 0x1F13, 0x1F14, 0x1F15, 0x0000, 0x0000,
0x1F20, 0x1F21, 0x1F22, 0x1F23, 0x1F24, 0x1F25, 0x1F26, 0x1F27,
0x1F20, 0x1F21, 0x1F22, 0x1F23, 0x1F24, 0x1F25, 0x1F26, 0x1F27,
0x1F30, 0x1F31, 0x1F32, 0x1F33, 0x1F34, 0x1F35, 0x1F36, 0x1F37,
0x1F30, 0x1F31, 0x1F32, 0x1F33, 0x1F34, 0x1F35, 0x1F36, 0x1F37,
0x1F40, 0x1F41, 0x1F42, 0x1F43, 0x1F44, 0x1F45, 0x0000, 0x0000,
0x1F40, 0x1F41, 0x1F42, 0x1F43, 0x1F44, 0x1F45, 0x0000, 0x0000,
0x1F50, 0x1F51, 0x1F52, 0x1F53, 0x1F54, 0x1F55, 0x1F56, 0x1F57,
0x0000, 0x1F51, 0x0000, 0x1F53, 0x0000, 0x1F55, 0x0000, 0x1F57,
0x1F60, 0x1F61, 0x1F62, 0x1F63, 0x1F64, 0x1F65, 0x1F66, 0x1F67,
0x1F60, 0x1F61, 0x1F62, 0x1F63, 0x1F64, 0x1F65, 0x1F66, 0x1F67,
0x1F70, 0x1F71, 0x1F72, 0x1F73, 0x1F74, 0x1F75, 0x1F76, 0x1F77,
0x1F78, 0x1F79, 0x1F7A, 0x1F7B, 0x1F7C, 0x1F7D, 0x0000, 0x0000,
0x1F80, 0x1F81, 0x1F82, 0x1F83, 0x1F84, 0x1F85, 0x1F86, 0x1F87,
0x1F80, 0x1F81, 0x1F82, 0x1F83, 0x1F84, 0x1F85, 0x1F86, 0x1F87,
0x1F90, 0x1F91, 0x1F92, 0x1F93, 0x1F94, 0x1F95, 0x1F96, 0x1F97,
0x1F90, 0x1F91, 0x1F92, 0x1F93, 0x1F94, 0x1F95, 0x1F96, 0x1F97,
0x1FA0, 0x1FA1, 0x1FA2, 0x1FA3, 0x1FA4, 0x1FA5, 0x1FA6, 0x1FA7,
0x1FA0, 0x1FA1, 0x1FA2, 0x1FA3, 0x1FA4, 0x1FA5, 0x1FA6, 0x1FA7,
0x1FB0, 0x1FB1, 0x1FB2, 0x1FB3, 0x1FB4, 0x0000, 0x1FB6, 0x1FB7,
0x1FB0, 0x1FB1, 0x1F70, 0x1F71, 0x1FB3, 0x1FBD, 0x1FBE, 0x1FBF,
0x1FC0, 0x1FC1, 0x1FC2, 0x1FC3, 0x1FC4, 0x0000, 0x1FC6, 0x1FC7,
0x1F72, 0x1F73, 0x1F74, 0x1F75, 0x1FC3, 0x1FCD, 0x1FCE, 0x1FCF,
0x1FD0, 0x1FD1, 0x1FD2, 0x1FD3, 0x0000, 0x0000, 0x1FD6, 0x1FD7,
0x1FD0, 0x1FD1, 0x1F76, 0x1F77, 0x0000, 0x1FDD, 0x1FDE, 0x1FDF,
0x1FE0, 0x1FE1, 0x1FE2, 0x1FE3, 0x1FE4, 0x1FE5, 0x1FE6, 0x1FE7,
0x1FE0, 0x1FE1, 0x1F7A, 0x1F7B, 0x1FE5, 0x1FED, 0x1FEE, 0x1FEF,
0x0000, 0x0000, 0x1FF2, 0x1FF3, 0x1FF4, 0x0000, 0x1FF6, 0x1FF7,
0x1F78, 0x1F79, 0x1F7C, 0x1F7D, 0x1FF3, 0x1FFD, 0x1FFE, 0x0000
};
static uint16_t const GreekExt_upper_mapping[] = {
0x1F08, 0x1F09, 0x1F0A, 0x1F0B, 0x1F0C, 0x1F0D, 0x1F0E, 0x1F0F,
0x1F08, 0x1F09, 0x1F0A, 0x1F0B, 0x1F0C, 0x1F0D, 0x1F0E, 0x1F0F,
0x1F18, 0x1F19, 0x1F1A, 0x1F1B, 0x1F1C, 0x1F1D, 0x0000, 0x0000,
0x1F18, 0x1F19, 0x1F1A, 0x1F1B, 0x1F1C, 0x1F1D, 0x0000, 0x0000,
0x1F28, 0x1F29, 0x1F2A, 0x1F2B, 0x1F2C, 0x1F2D, 0x1F2E, 0x1F2F,
0x1F28, 0x1F29, 0x1F2A, 0x1F2B, 0x1F2C, 0x1F2D, 0x1F2E, 0x1F2F,
0x1F38, 0x1F39, 0x1F3A, 0x1F3B, 0x1F3C, 0x1F3D, 0x1F3E, 0x1F3F,
0x1F38, 0x1F39, 0x1F3A, 0x1F3B, 0x1F3C, 0x1F3D, 0x1F3E, 0x1F3F,
0x1F48, 0x1F49, 0x1F4A, 0x1F4B, 0x1F4C, 0x1F4D, 0x0000, 0x0000,
0x1F48, 0x1F49, 0x1F4A, 0x1F4B, 0x1F4C, 0x1F4D, 0x0000, 0x0000,
0x1F50, 0x1F59, 0x1F52, 0x1F5B, 0x1F54, 0x1F5D, 0x1F56, 0x1F5F,
0x0000, 0x1F59, 0x0000, 0x1F5B, 0x0000, 0x1F5D, 0x0000, 0x1F5F,
0x1F68, 0x1F69, 0x1F6A, 0x1F6B, 0x1F6C, 0x1F6D, 0x1F6E, 0x1F6F,
0x1F68, 0x1F69, 0x1F6A, 0x1F6B, 0x1F6C, 0x1F6D, 0x1F6E, 0x1F6F,
0x1FBA, 0x1FBB, 0x1FC8, 0x1FC9, 0x1FCA, 0x1FCB, 0x1FDA, 0x1FDB,
0x1FF8, 0x1FF9, 0x1FEA, 0x1FEB, 0x1FFA, 0x1FFB, 0x0000, 0x0000,
0x1F88, 0x1F89, 0x1F8A, 0x1F8B, 0x1F8C, 0x1F8D, 0x1F8E, 0x1F8F,
0x1F88, 0x1F89, 0x1F8A, 0x1F8B, 0x1F8C, 0x1F8D, 0x1F8E, 0x1F8F,
0x1F98, 0x1F99, 0x1F9A, 0x1F9B, 0x1F9C, 0x1F9D, 0x1F9E, 0x1F9F,
0x1F98, 0x1F99, 0x1F9A, 0x1F9B, 0x1F9C, 0x1F9D, 0x1F9E, 0x1F9F,
0x1FA8, 0x1FA9, 0x1FAA, 0x1FAB, 0x1FAC, 0x1FAD, 0x1FAE, 0x1FAF,
0x1FA8, 0x1FA9, 0x1FAA, 0x1FAB, 0x1FAC, 0x1FAD, 0x1FAE, 0x1FAF,
0x1FB8, 0x1FB9, 0x1FB2, 0x1FBC, 0x1FB4, 0x0000, 0x1FB6, 0x1FB7,
0x1FB8, 0x1FB9, 0x1FBA, 0x1FBB, 0x1FBC, 0x1FBD, 0x0399, 0x1FBF,
0x1FC0, 0x1FC1, 0x1FC2, 0x1FCC, 0x1FC4, 0x0000, 0x1FC6, 0x1FC7,
0x1FC8, 0x1FC9, 0x1FCA, 0x1FCB, 0x1FCC, 0x1FCD, 0x1FCE, 0x1FCF,
0x1FD8, 0x1FD9, 0x1FD2, 0x1FD3, 0x0000, 0x0000, 0x1FD6, 0x1FD7,
0x1FD8, 0x1FD9, 0x1FDA, 0x1FDB, 0x0000, 0x1FDD, 0x1FDE, 0x1FDF,
0x1FE8, 0x1FE9, 0x1FE2, 0x1FE3, 0x1FE4, 0x1FEC, 0x1FE6, 0x1FE7,
0x1FE8, 0x1FE9, 0x1FEA, 0x1FEB, 0x1FEC, 0x1FED, 0x1FEE, 0x1FEF,
0x0000, 0x0000, 0x1FF2, 0x1FFC, 0x1FF4, 0x0000, 0x1FF6, 0x1FF7,
0x1FF8, 0x1FF9, 0x1FFA, 0x1FFB, 0x1FFC, 0x1FFD, 0x1FFE, 0x0000
};
*lower = code;
*upper = code;
/* Basic Latin and Latin-1 Supplement, U+0000 to U+00FF */
if (code <= 0x00ff) {
if (code >= 0x0041 && code <= 0x005a) /* A-Z */
*lower += 0x20;
else if (code >= 0x0061 && code <= 0x007a) /* a-z */
*upper -= 0x20;
else if ( (code >= 0x00c0 && code <= 0x00d6) ||
(code >= 0x00d8 && code <= 0x00de) )
*lower += 0x20;
else if ( (code >= 0x00e0 && code <= 0x00f6) ||
(code >= 0x00f8 && code <= 0x00fe) )
*upper -= 0x20;
else if (code == 0x00ff) /* y with diaeresis */
*upper = 0x0178;
else if (code == 0x00b5) /* micro sign */
*upper = 0x039c;
return;
}
/* Latin Extended-A, U+0100 to U+017F */
if (code >= 0x0100 && code <= 0x017f) {
if ( (code >= 0x0100 && code <= 0x012f) ||
(code >= 0x0132 && code <= 0x0137) ||
(code >= 0x014a && code <= 0x0177) ) {
*upper = code & ~1;
*lower = code | 1;
}
else if ( (code >= 0x0139 && code <= 0x0148) ||
(code >= 0x0179 && code <= 0x017e) ) {
if (code & 1)
*lower += 1;
else
*upper -= 1;
}
else if (code == 0x0130)
*lower = 0x0069;
else if (code == 0x0131)
*upper = 0x0049;
else if (code == 0x0178)
*lower = 0x00ff;
else if (code == 0x017f)
*upper = 0x0053;
return;
}
/* Latin Extended-B, U+0180 to U+024F */
if (code >= 0x0180 && code <= 0x024f) {
if (code >= 0x01cd && code <= 0x01dc) {
if (code & 1)
*lower += 1;
else
*upper -= 1;
}
else if ( (code >= 0x01de && code <= 0x01ef) ||
(code >= 0x01f4 && code <= 0x01f5) ||
(code >= 0x01f8 && code <= 0x021f) ||
(code >= 0x0222 && code <= 0x0233) ) {
*lower |= 1;
*upper &= ~1;
}
else if (code >= 0x0180 && code <= 0x01cc) {
*lower = LatinExtB_lower_mapping[code - 0x0180];
*upper = LatinExtB_upper_mapping[code - 0x0180];
}
else if (code == 0x01dd)
*upper = 0x018e;
else if (code == 0x01f1 || code == 0x01f2) {
*lower = 0x01f3;
*upper = 0x01f1;
}
else if (code == 0x01f3)
*upper = 0x01f1;
else if (code == 0x01f6)
*lower = 0x0195;
else if (code == 0x01f7)
*lower = 0x01bf;
else if (code == 0x0220)
*lower = 0x019e;
return;
}
/* IPA Extensions, U+0250 to U+02AF */
if (code >= 0x0253 && code <= 0x0292) {
*upper = IPAExt_upper_mapping[code - 0x0253];
}
/* Combining Diacritical Marks, U+0300 to U+036F */
if (code == 0x0345) {
*upper = 0x0399;
}
/* Greek and Coptic, U+0370 to U+03FF */
if (code >= 0x0370 && code <= 0x03ff) {
*lower = Greek_lower_mapping[code - 0x0370];
*upper = Greek_upper_mapping[code - 0x0370];
if (*upper == 0)
*upper = code;
if (*lower == 0)
*lower = code;
}
/* Cyrillic and Cyrillic Supplementary, U+0400 to U+052F */
if ( (code >= 0x0400 && code <= 0x04ff) ||
(code >= 0x0500 && code <= 0x052f) ) {
if (code >= 0x0400 && code <= 0x040f)
*lower += 0x50;
else if (code >= 0x0410 && code <= 0x042f)
*lower += 0x20;
else if (code >= 0x0430 && code <= 0x044f)
*upper -= 0x20;
else if (code >= 0x0450 && code <= 0x045f)
*upper -= 0x50;
else if ( (code >= 0x0460 && code <= 0x0481) ||
(code >= 0x048a && code <= 0x04bf) ||
(code >= 0x04d0 && code <= 0x04f5) ||
(code >= 0x04f8 && code <= 0x04f9) ||
(code >= 0x0500 && code <= 0x050f) ) {
*upper &= ~1;
*lower |= 1;
}
else if (code >= 0x04c1 && code <= 0x04ce) {
if (code & 1)
*lower += 1;
else
*upper -= 1;
}
}
/* Armenian, U+0530 to U+058F */
if (code >= 0x0530 && code <= 0x058f) {
if (code >= 0x0531 && code <= 0x0556)
*lower += 0x30;
else if (code >=0x0561 && code <= 0x0586)
*upper -= 0x30;
}
/* Latin Extended Additional, U+1E00 to U+1EFF */
if (code >= 0x1e00 && code <= 0x1eff) {
if ( (code >= 0x1e00 && code <= 0x1e95) ||
(code >= 0x1ea0 && code <= 0x1ef9) ) {
*upper &= ~1;
*lower |= 1;
}
else if (code == 0x1e9b)
*upper = 0x1e60;
}
/* Greek Extended, U+1F00 to U+1FFF */
if (code >= 0x1f00 && code <= 0x1fff) {
*lower = GreekExt_lower_mapping[code - 0x1f00];
*upper = GreekExt_upper_mapping[code - 0x1f00];
if (*upper == 0)
*upper = code;
if (*lower == 0)
*lower = code;
}
/* Letterlike Symbols, U+2100 to U+214F */
if (code >= 0x2100 && code <= 0x214f) {
switch (code) {
case 0x2126: *lower = 0x03c9; break;
case 0x212a: *lower = 0x006b; break;
case 0x212b: *lower = 0x00e5; break;
}
}
/* Number Forms, U+2150 to U+218F */
else if (code >= 0x2160 && code <= 0x216f)
*lower += 0x10;
else if (code >= 0x2170 && code <= 0x217f)
*upper -= 0x10;
/* Enclosed Alphanumerics, U+2460 to U+24FF */
else if (code >= 0x24b6 && code <= 0x24cf)
*lower += 0x1a;
else if (code >= 0x24d0 && code <= 0x24e9)
*upper -= 0x1a;
/* Halfwidth and Fullwidth Forms, U+FF00 to U+FFEF */
else if (code >= 0xff21 && code <= 0xff3a)
*lower += 0x20;
else if (code >= 0xff41 && code <= 0xff5a)
*upper -= 0x20;
/* Deseret, U+10400 to U+104FF */
else if (code >= 0x10400 && code <= 0x10427)
*lower += 0x28;
else if (code >= 0x10428 && code <= 0x1044f)
*upper -= 0x28;
}
static void
XConvertCase(xkb_keysym_t sym, xkb_keysym_t *lower, xkb_keysym_t *upper)
{
/* Latin 1 keysym */
if (sym < 0x100) {
UCSConvertCase(sym, lower, upper);
return;
}
/* Unicode keysym */
if ((sym & 0xff000000) == 0x01000000) {
UCSConvertCase((sym & 0x00ffffff), lower, upper);
*upper |= 0x01000000;
*lower |= 0x01000000;
return;
}
/* Legacy keysym */
*lower = sym;
*upper = sym;
switch(sym >> 8) {
case 1: /* Latin 2 */
/* Assume the KeySym is a legal value (ignore discontinuities) */
if (sym == XKB_KEY_Aogonek)
*lower = XKB_KEY_aogonek;
else if (sym >= XKB_KEY_Lstroke && sym <= XKB_KEY_Sacute)
*lower += (XKB_KEY_lstroke - XKB_KEY_Lstroke);
else if (sym >= XKB_KEY_Scaron && sym <= XKB_KEY_Zacute)
*lower += (XKB_KEY_scaron - XKB_KEY_Scaron);
else if (sym >= XKB_KEY_Zcaron && sym <= XKB_KEY_Zabovedot)
*lower += (XKB_KEY_zcaron - XKB_KEY_Zcaron);
else if (sym == XKB_KEY_aogonek)
*upper = XKB_KEY_Aogonek;
else if (sym >= XKB_KEY_lstroke && sym <= XKB_KEY_sacute)
*upper -= (XKB_KEY_lstroke - XKB_KEY_Lstroke);
else if (sym >= XKB_KEY_scaron && sym <= XKB_KEY_zacute)
*upper -= (XKB_KEY_scaron - XKB_KEY_Scaron);
else if (sym >= XKB_KEY_zcaron && sym <= XKB_KEY_zabovedot)
*upper -= (XKB_KEY_zcaron - XKB_KEY_Zcaron);
else if (sym >= XKB_KEY_Racute && sym <= XKB_KEY_Tcedilla)
*lower += (XKB_KEY_racute - XKB_KEY_Racute);
else if (sym >= XKB_KEY_racute && sym <= XKB_KEY_tcedilla)
*upper -= (XKB_KEY_racute - XKB_KEY_Racute);
break;
case 2: /* Latin 3 */
/* Assume the KeySym is a legal value (ignore discontinuities) */
if (sym >= XKB_KEY_Hstroke && sym <= XKB_KEY_Hcircumflex)
*lower += (XKB_KEY_hstroke - XKB_KEY_Hstroke);
else if (sym >= XKB_KEY_Gbreve && sym <= XKB_KEY_Jcircumflex)
*lower += (XKB_KEY_gbreve - XKB_KEY_Gbreve);
else if (sym >= XKB_KEY_hstroke && sym <= XKB_KEY_hcircumflex)
*upper -= (XKB_KEY_hstroke - XKB_KEY_Hstroke);
else if (sym >= XKB_KEY_gbreve && sym <= XKB_KEY_jcircumflex)
*upper -= (XKB_KEY_gbreve - XKB_KEY_Gbreve);
else if (sym >= XKB_KEY_Cabovedot && sym <= XKB_KEY_Scircumflex)
*lower += (XKB_KEY_cabovedot - XKB_KEY_Cabovedot);
else if (sym >= XKB_KEY_cabovedot && sym <= XKB_KEY_scircumflex)
*upper -= (XKB_KEY_cabovedot - XKB_KEY_Cabovedot);
break;
case 3: /* Latin 4 */
/* Assume the KeySym is a legal value (ignore discontinuities) */
if (sym >= XKB_KEY_Rcedilla && sym <= XKB_KEY_Tslash)
*lower += (XKB_KEY_rcedilla - XKB_KEY_Rcedilla);
else if (sym >= XKB_KEY_rcedilla && sym <= XKB_KEY_tslash)
*upper -= (XKB_KEY_rcedilla - XKB_KEY_Rcedilla);
else if (sym == XKB_KEY_ENG)
*lower = XKB_KEY_eng;
else if (sym == XKB_KEY_eng)
*upper = XKB_KEY_ENG;
else if (sym >= XKB_KEY_Amacron && sym <= XKB_KEY_Umacron)
*lower += (XKB_KEY_amacron - XKB_KEY_Amacron);
else if (sym >= XKB_KEY_amacron && sym <= XKB_KEY_umacron)
*upper -= (XKB_KEY_amacron - XKB_KEY_Amacron);
break;
case 6: /* Cyrillic */
/* Assume the KeySym is a legal value (ignore discontinuities) */
if (sym >= XKB_KEY_Serbian_DJE && sym <= XKB_KEY_Serbian_DZE)
*lower -= (XKB_KEY_Serbian_DJE - XKB_KEY_Serbian_dje);
else if (sym >= XKB_KEY_Serbian_dje && sym <= XKB_KEY_Serbian_dze)
*upper += (XKB_KEY_Serbian_DJE - XKB_KEY_Serbian_dje);
else if (sym >= XKB_KEY_Cyrillic_YU && sym <= XKB_KEY_Cyrillic_HARDSIGN)
*lower -= (XKB_KEY_Cyrillic_YU - XKB_KEY_Cyrillic_yu);
else if (sym >= XKB_KEY_Cyrillic_yu && sym <= XKB_KEY_Cyrillic_hardsign)
*upper += (XKB_KEY_Cyrillic_YU - XKB_KEY_Cyrillic_yu);
break;
case 7: /* Greek */
/* Assume the KeySym is a legal value (ignore discontinuities) */
if (sym >= XKB_KEY_Greek_ALPHAaccent && sym <= XKB_KEY_Greek_OMEGAaccent)
*lower += (XKB_KEY_Greek_alphaaccent - XKB_KEY_Greek_ALPHAaccent);
else if (sym >= XKB_KEY_Greek_alphaaccent && sym <= XKB_KEY_Greek_omegaaccent &&
sym != XKB_KEY_Greek_iotaaccentdieresis &&
sym != XKB_KEY_Greek_upsilonaccentdieresis)
*upper -= (XKB_KEY_Greek_alphaaccent - XKB_KEY_Greek_ALPHAaccent);
else if (sym >= XKB_KEY_Greek_ALPHA && sym <= XKB_KEY_Greek_OMEGA)
*lower += (XKB_KEY_Greek_alpha - XKB_KEY_Greek_ALPHA);
else if (sym >= XKB_KEY_Greek_alpha && sym <= XKB_KEY_Greek_omega &&
sym != XKB_KEY_Greek_finalsmallsigma)
*upper -= (XKB_KEY_Greek_alpha - XKB_KEY_Greek_ALPHA);
break;
case 0x13: /* Latin 9 */
if (sym == XKB_KEY_OE)
*lower = XKB_KEY_oe;
else if (sym == XKB_KEY_oe)
*upper = XKB_KEY_OE;
else if (sym == XKB_KEY_Ydiaeresis)
*lower = XKB_KEY_ydiaeresis;
break;
}
}

View File

@ -1,65 +0,0 @@
/*
* Copyright 1985, 1987, 1990, 1998 The Open Group
*
* 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
* AUTHORS 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 names of the authors or their
* institutions 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 authors.
*/
/*
* Copyright © 2009 Dan Nicholson
*
* 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 (including the next
* paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
*/
#ifndef KEYSYM_H
#define KEYSYM_H
bool
xkb_keysym_is_lower(xkb_keysym_t keysym);
bool
xkb_keysym_is_upper(xkb_keysym_t keysym);
bool
xkb_keysym_is_keypad(xkb_keysym_t keysym);
bool
xkb_keysym_is_modifier(xkb_keysym_t keysym);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,195 +0,0 @@
/*
* Copyright © 2012 Ran Benita <ran234@gmail.com>
*
* 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 (including the next
* paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
*/
#ifndef XKBCOMP_SCANNER_UTILS_H
#define XKBCOMP_SCANNER_UTILS_H
/* Point to some substring in the file; used to avoid copying. */
struct sval {
const char *start;
unsigned int len;
};
typedef darray(struct sval) darray_sval;
static inline bool
svaleq(struct sval s1, struct sval s2)
{
return s1.len == s2.len && memcmp(s1.start, s2.start, s1.len) == 0;
}
static inline bool
svaleq_prefix(struct sval s1, struct sval s2)
{
return s1.len <= s2.len && memcmp(s1.start, s2.start, s1.len) == 0;
}
struct scanner {
const char *s;
size_t pos;
size_t len;
char buf[1024];
size_t buf_pos;
unsigned line, column;
/* The line/column of the start of the current token. */
unsigned token_line, token_column;
const char *file_name;
struct xkb_context *ctx;
void *priv;
};
#define scanner_log(scanner, level, fmt, ...) \
xkb_log((scanner)->ctx, (level), 0, \
"%s:%u:%u: " fmt "\n", \
(scanner)->file_name, \
(scanner)->token_line, (scanner)->token_column, ##__VA_ARGS__)
#define scanner_err(scanner, fmt, ...) \
scanner_log(scanner, XKB_LOG_LEVEL_ERROR, fmt, ##__VA_ARGS__)
#define scanner_warn(scanner, fmt, ...) \
scanner_log(scanner, XKB_LOG_LEVEL_WARNING, fmt, ##__VA_ARGS__)
static inline void
scanner_init(struct scanner *s, struct xkb_context *ctx,
const char *string, size_t len, const char *file_name,
void *priv)
{
s->s = string;
s->len = len;
s->pos = 0;
s->line = s->column = 1;
s->token_line = s->token_column = 1;
s->file_name = file_name;
s->ctx = ctx;
s->priv = priv;
}
static inline char
peek(struct scanner *s)
{
if (unlikely(s->pos >= s->len))
return '\0';
return s->s[s->pos];
}
static inline bool
eof(struct scanner *s)
{
return s->pos >= s->len;
}
static inline bool
eol(struct scanner *s)
{
return peek(s) == '\n';
}
static inline void
skip_to_eol(struct scanner *s)
{
const char *nl = memchr(s->s + s->pos, '\n', s->len - s->pos);
const size_t new_pos = nl ? (size_t) (nl - s->s) : s->len;
s->column += new_pos - s->pos;
s->pos = new_pos;
}
static inline char
next(struct scanner *s)
{
if (unlikely(eof(s)))
return '\0';
if (unlikely(eol(s))) {
s->line++;
s->column = 1;
}
else {
s->column++;
}
return s->s[s->pos++];
}
static inline bool
chr(struct scanner *s, char ch)
{
if (likely(peek(s) != ch))
return false;
s->pos++; s->column++;
return true;
}
static inline bool
str(struct scanner *s, const char *string, size_t len)
{
if (s->len - s->pos < len)
return false;
if (memcmp(s->s + s->pos, string, len) != 0)
return false;
s->pos += len; s->column += len;
return true;
}
#define lit(s, literal) str(s, literal, sizeof(literal) - 1)
static inline bool
buf_append(struct scanner *s, char ch)
{
if (s->buf_pos + 1 >= sizeof(s->buf))
return false;
s->buf[s->buf_pos++] = ch;
return true;
}
static inline bool
buf_appends(struct scanner *s, const char *str)
{
int ret;
ret = snprintf(s->buf + s->buf_pos, sizeof(s->buf) - s->buf_pos, "%s", str);
if (ret < 0 || (size_t) ret >= sizeof(s->buf) - s->buf_pos)
return false;
s->buf_pos += ret;
return true;
}
static inline bool
oct(struct scanner *s, uint8_t *out)
{
int i;
for (i = 0, *out = 0; peek(s) >= '0' && peek(s) <= '7' && i < 3; i++)
*out = *out * 8 + next(s) - '0';
return i > 0;
}
static inline bool
hex(struct scanner *s, uint8_t *out)
{
int i;
for (i = 0, *out = 0; is_xdigit(peek(s)) && i < 2; i++) {
const char c = next(s);
const char offset = (c >= '0' && c <= '9' ? '0' :
c >= 'a' && c <= 'f' ? 'a' - 10 : 'A' - 10);
*out = *out * 16 + c - offset;
}
return i > 0;
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,346 +0,0 @@
/************************************************************
* Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting
* documentation, and that the name of Silicon Graphics not be
* used in advertising or publicity pertaining to distribution
* of the software without specific prior written permission.
* Silicon Graphics makes no representation about the suitability
* of this software for any purpose. It is provided "as is"
* without any express or implied warranty.
*
* SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
* GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
********************************************************/
#include "keymap.h"
#include "text.h"
bool
LookupString(const LookupEntry tab[], const char *string,
unsigned int *value_rtrn)
{
if (!string)
return false;
for (const LookupEntry *entry = tab; entry->name; entry++) {
if (istreq(entry->name, string)) {
*value_rtrn = entry->value;
return true;
}
}
return false;
}
const char *
LookupValue(const LookupEntry tab[], unsigned int value)
{
for (const LookupEntry *entry = tab; entry->name; entry++)
if (entry->value == value)
return entry->name;
return NULL;
}
const LookupEntry ctrlMaskNames[] = {
{ "RepeatKeys", CONTROL_REPEAT },
{ "Repeat", CONTROL_REPEAT },
{ "AutoRepeat", CONTROL_REPEAT },
{ "SlowKeys", CONTROL_SLOW },
{ "BounceKeys", CONTROL_DEBOUNCE },
{ "StickyKeys", CONTROL_STICKY },
{ "MouseKeys", CONTROL_MOUSEKEYS },
{ "MouseKeysAccel", CONTROL_MOUSEKEYS_ACCEL },
{ "AccessXKeys", CONTROL_AX },
{ "AccessXTimeout", CONTROL_AX_TIMEOUT },
{ "AccessXFeedback", CONTROL_AX_FEEDBACK },
{ "AudibleBell", CONTROL_BELL },
{ "IgnoreGroupLock", CONTROL_IGNORE_GROUP_LOCK },
{ "all", CONTROL_ALL },
{ "none", 0 },
{ "Overlay1", 0 },
{ "Overlay2", 0 },
{ NULL, 0 }
};
const LookupEntry modComponentMaskNames[] = {
{ "base", XKB_STATE_MODS_DEPRESSED },
{ "latched", XKB_STATE_MODS_LATCHED },
{ "locked", XKB_STATE_MODS_LOCKED },
{ "effective", XKB_STATE_MODS_EFFECTIVE },
{ "compat", XKB_STATE_MODS_EFFECTIVE },
{ "any", XKB_STATE_MODS_EFFECTIVE },
{ "none", 0 },
{ NULL, 0 }
};
const LookupEntry groupComponentMaskNames[] = {
{ "base", XKB_STATE_LAYOUT_DEPRESSED },
{ "latched", XKB_STATE_LAYOUT_LATCHED },
{ "locked", XKB_STATE_LAYOUT_LOCKED },
{ "effective", XKB_STATE_LAYOUT_EFFECTIVE },
{ "any", XKB_STATE_LAYOUT_EFFECTIVE },
{ "none", 0 },
{ NULL, 0 }
};
const LookupEntry groupMaskNames[] = {
{ "Group1", 0x01 },
{ "Group2", 0x02 },
{ "Group3", 0x04 },
{ "Group4", 0x08 },
{ "Group5", 0x10 },
{ "Group6", 0x20 },
{ "Group7", 0x40 },
{ "Group8", 0x80 },
{ "none", 0x00 },
{ "all", 0xff },
{ NULL, 0 }
};
const LookupEntry groupNames[] = {
{ "Group1", 1 },
{ "Group2", 2 },
{ "Group3", 3 },
{ "Group4", 4 },
{ "Group5", 5 },
{ "Group6", 6 },
{ "Group7", 7 },
{ "Group8", 8 },
{ NULL, 0 }
};
const LookupEntry levelNames[] = {
{ "Level1", 1 },
{ "Level2", 2 },
{ "Level3", 3 },
{ "Level4", 4 },
{ "Level5", 5 },
{ "Level6", 6 },
{ "Level7", 7 },
{ "Level8", 8 },
{ NULL, 0 }
};
const LookupEntry buttonNames[] = {
{ "Button1", 1 },
{ "Button2", 2 },
{ "Button3", 3 },
{ "Button4", 4 },
{ "Button5", 5 },
{ "default", 0 },
{ NULL, 0 }
};
const LookupEntry useModMapValueNames[] = {
{ "LevelOne", 1 },
{ "Level1", 1 },
{ "AnyLevel", 0 },
{ "any", 0 },
{ NULL, 0 }
};
const LookupEntry actionTypeNames[] = {
{ "NoAction", ACTION_TYPE_NONE },
{ "SetMods", ACTION_TYPE_MOD_SET },
{ "LatchMods", ACTION_TYPE_MOD_LATCH },
{ "LockMods", ACTION_TYPE_MOD_LOCK },
{ "SetGroup", ACTION_TYPE_GROUP_SET },
{ "LatchGroup", ACTION_TYPE_GROUP_LATCH },
{ "LockGroup", ACTION_TYPE_GROUP_LOCK },
{ "MovePtr", ACTION_TYPE_PTR_MOVE },
{ "MovePointer", ACTION_TYPE_PTR_MOVE },
{ "PtrBtn", ACTION_TYPE_PTR_BUTTON },
{ "PointerButton", ACTION_TYPE_PTR_BUTTON },
{ "LockPtrBtn", ACTION_TYPE_PTR_LOCK },
{ "LockPtrButton", ACTION_TYPE_PTR_LOCK },
{ "LockPointerButton", ACTION_TYPE_PTR_LOCK },
{ "LockPointerBtn", ACTION_TYPE_PTR_LOCK },
{ "SetPtrDflt", ACTION_TYPE_PTR_DEFAULT },
{ "SetPointerDefault", ACTION_TYPE_PTR_DEFAULT },
{ "Terminate", ACTION_TYPE_TERMINATE },
{ "TerminateServer", ACTION_TYPE_TERMINATE },
{ "SwitchScreen", ACTION_TYPE_SWITCH_VT },
{ "SetControls", ACTION_TYPE_CTRL_SET },
{ "LockControls", ACTION_TYPE_CTRL_LOCK },
{ "Private", ACTION_TYPE_PRIVATE },
/* deprecated actions below here - unused */
{ "RedirectKey", ACTION_TYPE_NONE },
{ "Redirect", ACTION_TYPE_NONE },
{ "ISOLock", ACTION_TYPE_NONE },
{ "ActionMessage", ACTION_TYPE_NONE },
{ "MessageAction", ACTION_TYPE_NONE },
{ "Message", ACTION_TYPE_NONE },
{ "DeviceBtn", ACTION_TYPE_NONE },
{ "DevBtn", ACTION_TYPE_NONE },
{ "DevButton", ACTION_TYPE_NONE },
{ "DeviceButton", ACTION_TYPE_NONE },
{ "LockDeviceBtn", ACTION_TYPE_NONE },
{ "LockDevBtn", ACTION_TYPE_NONE },
{ "LockDevButton", ACTION_TYPE_NONE },
{ "LockDeviceButton", ACTION_TYPE_NONE },
{ "DeviceValuator", ACTION_TYPE_NONE },
{ "DevVal", ACTION_TYPE_NONE },
{ "DeviceVal", ACTION_TYPE_NONE },
{ "DevValuator", ACTION_TYPE_NONE },
{ NULL, 0 },
};
const LookupEntry symInterpretMatchMaskNames[] = {
{ "NoneOf", MATCH_NONE },
{ "AnyOfOrNone", MATCH_ANY_OR_NONE },
{ "AnyOf", MATCH_ANY },
{ "AllOf", MATCH_ALL },
{ "Exactly", MATCH_EXACTLY },
{ NULL, 0 },
};
const char *
ModIndexText(struct xkb_context *ctx, const struct xkb_mod_set *mods,
xkb_mod_index_t ndx)
{
if (ndx == XKB_MOD_INVALID)
return "none";
if (ndx >= mods->num_mods)
return NULL;
return xkb_atom_text(ctx, mods->mods[ndx].name);
}
const char *
ActionTypeText(enum xkb_action_type type)
{
const char *name = LookupValue(actionTypeNames, type);
return name ? name : "Private";
}
const char *
KeysymText(struct xkb_context *ctx, xkb_keysym_t sym)
{
char *buffer = xkb_context_get_buffer(ctx, 64);
xkb_keysym_get_name(sym, buffer, 64);
return buffer;
}
const char *
KeyNameText(struct xkb_context *ctx, xkb_atom_t name)
{
const char *sname = xkb_atom_text(ctx, name);
size_t len = strlen_safe(sname) + 3;
char *buf = xkb_context_get_buffer(ctx, len);
snprintf(buf, len, "<%s>", strempty(sname));
return buf;
}
const char *
SIMatchText(enum xkb_match_operation type)
{
return LookupValue(symInterpretMatchMaskNames, type);
}
const char *
ModMaskText(struct xkb_context *ctx, const struct xkb_mod_set *mods,
xkb_mod_mask_t mask)
{
char buf[1024] = {0};
size_t pos = 0;
xkb_mod_index_t i;
const struct xkb_mod *mod;
if (mask == 0)
return "none";
if (mask == MOD_REAL_MASK_ALL)
return "all";
xkb_mods_enumerate(i, mod, mods) {
int ret;
if (!(mask & (1u << i)))
continue;
ret = snprintf(buf + pos, sizeof(buf) - pos, "%s%s",
pos == 0 ? "" : "+",
xkb_atom_text(ctx, mod->name));
if (ret <= 0 || pos + ret >= sizeof(buf))
break;
else
pos += ret;
}
return strcpy(xkb_context_get_buffer(ctx, pos + 1), buf);
}
const char *
LedStateMaskText(struct xkb_context *ctx, enum xkb_state_component mask)
{
char buf[1024];
size_t pos = 0;
if (mask == 0)
return "0";
for (unsigned i = 0; mask; i++) {
int ret;
if (!(mask & (1u << i)))
continue;
mask &= ~(1u << i);
ret = snprintf(buf + pos, sizeof(buf) - pos, "%s%s",
pos == 0 ? "" : "+",
LookupValue(modComponentMaskNames, 1u << i));
if (ret <= 0 || pos + ret >= sizeof(buf))
break;
else
pos += ret;
}
return strcpy(xkb_context_get_buffer(ctx, pos + 1), buf);
}
const char *
ControlMaskText(struct xkb_context *ctx, enum xkb_action_controls mask)
{
char buf[1024];
size_t pos = 0;
if (mask == 0)
return "none";
if (mask == CONTROL_ALL)
return "all";
for (unsigned i = 0; mask; i++) {
int ret;
if (!(mask & (1u << i)))
continue;
mask &= ~(1u << i);
ret = snprintf(buf + pos, sizeof(buf) - pos, "%s%s",
pos == 0 ? "" : "+",
LookupValue(ctrlMaskNames, 1u << i));
if (ret <= 0 || pos + ret >= sizeof(buf))
break;
else
pos += ret;
}
return strcpy(xkb_context_get_buffer(ctx, pos + 1), buf);
}

View File

@ -1,76 +0,0 @@
/*
* Copyright © 2009 Dan Nicholson
*
* 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 (including the next
* paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
*/
#ifndef TEXT_H
#define TEXT_H
typedef struct {
const char *name;
unsigned int value;
} LookupEntry;
bool
LookupString(const LookupEntry tab[], const char *string,
unsigned int *value_rtrn);
const char *
LookupValue(const LookupEntry tab[], unsigned int value);
extern const LookupEntry ctrlMaskNames[];
extern const LookupEntry modComponentMaskNames[];
extern const LookupEntry groupComponentMaskNames[];
extern const LookupEntry groupMaskNames[];
extern const LookupEntry groupNames[];
extern const LookupEntry levelNames[];
extern const LookupEntry buttonNames[];
extern const LookupEntry useModMapValueNames[];
extern const LookupEntry actionTypeNames[];
extern const LookupEntry symInterpretMatchMaskNames[];
const char *
ModMaskText(struct xkb_context *ctx, const struct xkb_mod_set *mods,
xkb_mod_mask_t mask);
const char *
ModIndexText(struct xkb_context *ctx, const struct xkb_mod_set *mods,
xkb_mod_index_t ndx);
const char *
ActionTypeText(enum xkb_action_type type);
const char *
KeysymText(struct xkb_context *ctx, xkb_keysym_t sym);
const char *
KeyNameText(struct xkb_context *ctx, xkb_atom_t name);
const char *
SIMatchText(enum xkb_match_operation type);
const char *
LedStateMaskText(struct xkb_context *ctx, enum xkb_state_component mask);
const char *
ControlMaskText(struct xkb_context *ctx, enum xkb_action_controls mask);
#endif /* TEXT_H */

View File

@ -1,138 +0,0 @@
/*
* Copyright © 2012 Intel Corporation
* Copyright © 2014 Ran Benita <ran234@gmail.com>
*
* 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 (including the next
* paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
*
* Author: Rob Bradford <rob@linux.intel.com>
*/
#include <stddef.h>
#include <stdbool.h>
#include <inttypes.h>
#include "utf8.h"
int
utf32_to_utf8(uint32_t unichar, char *buffer)
{
int count, shift, length;
uint8_t head;
if (unichar <= 0x007f) {
buffer[0] = unichar;
buffer[1] = '\0';
return 2;
}
else if (unichar <= 0x07FF) {
length = 2;
head = 0xc0;
}
else if (unichar <= 0xffff) {
length = 3;
head = 0xe0;
}
else if (unichar <= 0x10ffff) {
length = 4;
head = 0xf0;
}
else {
buffer[0] = '\0';
return 0;
}
for (count = length - 1, shift = 0; count > 0; count--, shift += 6)
buffer[count] = 0x80 | ((unichar >> shift) & 0x3f);
buffer[0] = head | ((unichar >> shift) & 0x3f);
buffer[length] = '\0';
return length + 1;
}
bool
is_valid_utf8(const char *ss, size_t len)
{
size_t i = 0;
size_t tail_bytes = 0;
const uint8_t *s = (const uint8_t *) ss;
/* This beauty is from:
* The Unicode Standard Version 6.2 - Core Specification, Table 3.7
* https://www.unicode.org/versions/Unicode6.2.0/ch03.pdf#G7404
* We can optimize if needed. */
while (i < len)
{
if (s[i] <= 0x7F) {
tail_bytes = 0;
}
else if (s[i] >= 0xC2 && s[i] <= 0xDF) {
tail_bytes = 1;
}
else if (s[i] == 0xE0) {
i++;
if (i >= len || !(s[i] >= 0xA0 && s[i] <= 0xBF))
return false;
tail_bytes = 1;
}
else if (s[i] >= 0xE1 && s[i] <= 0xEC) {
tail_bytes = 2;
}
else if (s[i] == 0xED) {
i++;
if (i >= len || !(s[i] >= 0x80 && s[i] <= 0x9F))
return false;
tail_bytes = 1;
}
else if (s[i] >= 0xEE && s[i] <= 0xEF) {
tail_bytes = 2;
}
else if (s[i] == 0xF0) {
i++;
if (i >= len || !(s[i] >= 0x90 && s[i] <= 0xBF))
return false;
tail_bytes = 2;
}
else if (s[i] >= 0xF1 && s[i] <= 0xF3) {
tail_bytes = 3;
}
else if (s[i] == 0xF4) {
i++;
if (i >= len || !(s[i] >= 0x80 && s[i] <= 0x8F))
return false;
tail_bytes = 2;
}
else {
return false;
}
i++;
while (i < len && tail_bytes > 0 && s[i] >= 0x80 && s[i] <= 0xBF) {
i++;
tail_bytes--;
}
if (tail_bytes != 0)
return false;
}
return true;
}

View File

@ -1,36 +0,0 @@
/*
* Copyright © 2012 Intel Corporation
* Copyright © 2014 Ran Benita <ran234@gmail.com>
*
* 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 (including the next
* paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
*
* Author: Rob Bradford <rob@linux.intel.com>
*/
#ifndef XKBCOMMON_UTF8_H
#define XKBCOMMON_UTF8_H
int
utf32_to_utf8(uint32_t unichar, char *buffer);
bool
is_valid_utf8(const char *ss, size_t len);
#endif

View File

@ -1,163 +0,0 @@
/*
* Copyright © 2013 Ran Benita <ran234@gmail.com>
*
* 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 (including the next
* paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
*/
#include "utils.h"
#ifdef HAVE_MMAP
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
bool
map_file(FILE *file, char **string_out, size_t *size_out)
{
struct stat stat_buf;
int fd;
char *string;
/* Make sure to keep the errno on failure! */
fd = fileno(file);
if (fd < 0)
return false;
if (fstat(fd, &stat_buf) != 0)
return false;
string = mmap(NULL, stat_buf.st_size, PROT_READ, MAP_SHARED, fd, 0);
if (string == MAP_FAILED)
return false;
*string_out = string;
*size_out = stat_buf.st_size;
return true;
}
void
unmap_file(char *str, size_t size)
{
munmap(str, size);
}
#else
bool
map_file(FILE *file, char **string_out, size_t *size_out)
{
long ret;
size_t ret_s;
char *string;
size_t size;
/* Make sure to keep the errno on failure! */
ret = fseek(file, 0, SEEK_END);
if (ret != 0)
return false;
ret = ftell(file);
if (ret < 0)
return false;
size = (size_t) ret;
ret = fseek(file, 0, SEEK_SET);
if (ret < 0)
return false;
string = malloc(size);
if (!string)
return false;
ret_s = fread(string, 1, size, file);
if (ret_s < size) {
free(string);
return false;
}
*string_out = string;
*size_out = size;
return true;
}
void
unmap_file(char *str, size_t size)
{
free(str);
}
#endif
// ASCII lower-case map.
static const unsigned char lower_map[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
59, 60, 61, 62, 63, 64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122,
91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122,
123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137,
138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152,
153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167,
168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182,
183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197,
198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212,
213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227,
228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242,
243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
};
// ASCII tolower (to avoid locale issues).
char
to_lower(char c)
{
return (char) lower_map[(unsigned char) c];
}
// ASCII strcasecmp (to avoid locale issues).
int
istrcmp(const char *a, const char *b)
{
for (size_t i = 0; ; i++) {
if (to_lower(a[i]) != to_lower(b[i]))
return (int) to_lower(a[i]) - (int) to_lower(b[i]);
if (!a[i])
break;
}
return 0;
}
// ASCII strncasecmp (to avoid locale issues).
int
istrncmp(const char *a, const char *b, size_t n)
{
for (size_t i = 0; i < n; i++) {
if (to_lower(a[i]) != to_lower(b[i]))
return (int) to_lower(a[i]) - (int) to_lower(b[i]);
if (!a[i])
break;
}
return 0;
}

View File

@ -1,276 +0,0 @@
/*
* Copyright © 2012 Ran Benita <ran234@gmail.com>
*
* 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 (including the next
* paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
*/
#ifndef UTILS_H
#define UTILS_H 1
#include <errno.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include "darray.h"
/*
* We sometimes malloc strings and then expose them as const char*'s. This
* macro is used when we free these strings in order to avoid -Wcast-qual
* errors.
*/
#define UNCONSTIFY(const_ptr) ((void *) (uintptr_t) (const_ptr))
#define STATIC_ASSERT(expr, message) do { \
switch (0) { case 0: case (expr): ; } \
} while (0)
char
to_lower(char c);
int
istrcmp(const char *a, const char *b);
int
istrncmp(const char *a, const char *b, size_t n);
static inline bool
streq(const char *s1, const char *s2)
{
return strcmp(s1, s2) == 0;
}
static inline bool
streq_not_null(const char *s1, const char *s2)
{
if (!s1 || !s2)
return false;
return streq(s1, s2);
}
static inline bool
istreq(const char *s1, const char *s2)
{
return istrcmp(s1, s2) == 0;
}
static inline bool
istreq_prefix(const char *s1, const char *s2)
{
return istrncmp(s1, s2, strlen(s1)) == 0;
}
static inline char *
strdup_safe(const char *s)
{
return s ? strdup(s) : NULL;
}
static inline size_t
strlen_safe(const char *s)
{
return s ? strlen(s) : 0;
}
static inline bool
isempty(const char *s)
{
return s == NULL || s[0] == '\0';
}
static inline const char *
strnull(const char *s)
{
return s ? s : "(null)";
}
static inline const char *
strempty(const char *s)
{
return s ? s : "";
}
static inline void *
memdup(const void *mem, size_t nmemb, size_t size)
{
void *p = calloc(nmemb, size);
if (p)
memcpy(p, mem, nmemb * size);
return p;
}
static inline int
min(int misc, int other)
{
return (misc < other) ? misc : other;
}
static inline int
max(int misc, int other)
{
return (misc > other) ? misc : other;
}
/* ctype.h is locale-dependent and has other oddities. */
static inline bool
is_space(char ch)
{
return ch == ' ' || (ch >= '\t' && ch <= '\r');
}
static inline bool
is_alpha(char ch)
{
return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z');
}
static inline bool
is_digit(char ch)
{
return ch >= '0' && ch <= '9';
}
static inline bool
is_alnum(char ch)
{
return is_alpha(ch) || is_digit(ch);
}
static inline bool
is_xdigit(char ch)
{
return
(ch >= '0' && ch <= '9') ||
(ch >= 'a' && ch <= 'f') ||
(ch >= 'A' && ch <= 'F');
}
static inline bool
is_graph(char ch)
{
/* See table in ascii(7). */
return ch >= '!' && ch <= '~';
}
/*
* Return the bit position of the most significant bit.
* Note: this is 1-based! It's more useful this way, and returns 0 when
* mask is all 0s.
*/
static inline unsigned
msb_pos(uint32_t mask)
{
unsigned pos = 0;
while (mask) {
pos++;
mask >>= 1u;
}
return pos;
}
// Avoid conflict with other popcount()s.
static inline int
my_popcount(uint32_t x)
{
int count;
#if defined(HAVE___BUILTIN_POPCOUNT)
count = __builtin_popcount(x);
#else
for (count = 0; x; count++)
x &= x - 1;
#endif
return count;
}
bool
map_file(FILE *file, char **string_out, size_t *size_out);
void
unmap_file(char *string, size_t size);
#define ARRAY_SIZE(arr) ((sizeof(arr) / sizeof(*(arr))))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MIN3(a, b, c) MIN(MIN((a), (b)), (c))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MAX3(a, b, c) MAX(MAX((a), (b)), (c))
/* Round up @a so it's divisible by @b. */
#define ROUNDUP(a, b) (((a) + (b) - 1) / (b) * (b))
#if defined(HAVE_SECURE_GETENV)
# define secure_getenv secure_getenv
#elif defined(HAVE___SECURE_GETENV)
# define secure_getenv __secure_getenv
#else
# define secure_getenv getenv
#endif
#if defined(HAVE___BUILTIN_EXPECT)
# define likely(x) __builtin_expect(!!(x), 1)
# define unlikely(x) __builtin_expect(!!(x), 0)
#else
# define likely(x) (x)
# define unlikely(x) (x)
#endif
/* Compiler Attributes */
#if defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__CYGWIN__)
# define XKB_EXPORT __attribute__((visibility("default")))
#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550)
# define XKB_EXPORT __global
#else /* not gcc >= 4 and not Sun Studio >= 8 */
# define XKB_EXPORT
#endif
#if defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 203)
# define ATTR_PRINTF(x,y) __attribute__((__format__(__printf__, x, y)))
#else /* not gcc >= 2.3 */
# define ATTR_PRINTF(x,y)
#endif
#if (defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 205)) \
|| (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590))
# define ATTR_NORETURN __attribute__((__noreturn__))
#else
# define ATTR_NORETURN
#endif /* GNUC */
#if (defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 296)
#define ATTR_MALLOC __attribute__((__malloc__))
#else
#define ATTR_MALLOC
#endif
#if defined(__GNUC__) && (__GNUC__ >= 4)
# define ATTR_NULL_SENTINEL __attribute__((__sentinel__))
#else
# define ATTR_NULL_SENTINEL
#endif /* GNUC >= 4 */
#if (defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 295)
#define ATTR_PACKED __attribute__((__packed__))
#else
#define ATTR_PACKED
#endif
#endif /* UTILS_H */

View File

@ -1,217 +0,0 @@
/*
* Copyright © 2013 Ran Benita
*
* 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 (including the next
* paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
*/
#include "x11-priv.h"
XKB_EXPORT int
xkb_x11_setup_xkb_extension(xcb_connection_t *conn,
uint16_t major_xkb_version,
uint16_t minor_xkb_version,
enum xkb_x11_setup_xkb_extension_flags flags,
uint16_t *major_xkb_version_out,
uint16_t *minor_xkb_version_out,
uint8_t *base_event_out,
uint8_t *base_error_out)
{
uint8_t base_event, base_error;
uint16_t server_major, server_minor;
if (flags & ~(XKB_X11_SETUP_XKB_EXTENSION_NO_FLAGS)) {
/* log_err_func(ctx, "unrecognized flags: %#x\n", flags); */
return 0;
}
{
const xcb_query_extension_reply_t *reply =
xcb_get_extension_data(conn, &xcb_xkb_id);
if (!reply) {
/* log_err_func(ctx, "failed to query for XKB extension\n"); */
return 0;
}
if (!reply->present) {
/* log_err_func(ctx, "failed to start using XKB extension: not available in server\n"); */
return 0;
}
base_event = reply->first_event;
base_error = reply->first_error;
}
{
xcb_generic_error_t *error = NULL;
xcb_xkb_use_extension_cookie_t cookie =
xcb_xkb_use_extension(conn, major_xkb_version, minor_xkb_version);
xcb_xkb_use_extension_reply_t *reply =
xcb_xkb_use_extension_reply(conn, cookie, &error);
if (!reply) {
/* log_err_func(ctx, */
/* "failed to start using XKB extension: error code %d\n", */
/* error ? error->error_code : -1); */
free(error);
return 0;
}
if (!reply->supported) {
/* log_err_func(ctx, */
/* "failed to start using XKB extension: server doesn't support version %d.%d\n", */
/* major_xkb_version, minor_xkb_version); */
free(reply);
return 0;
}
server_major = reply->serverMajor;
server_minor = reply->serverMinor;
free(reply);
}
/*
* The XkbUseExtension() in libX11 has a *bunch* of legacy stuff, but
* it doesn't seem like any of it is useful to us.
*/
if (major_xkb_version_out)
*major_xkb_version_out = server_major;
if (minor_xkb_version_out)
*minor_xkb_version_out = server_minor;
if (base_event_out)
*base_event_out = base_event;
if (base_error_out)
*base_error_out = base_error;
return 1;
}
XKB_EXPORT int32_t
xkb_x11_get_core_keyboard_device_id(xcb_connection_t *conn)
{
int32_t device_id;
xcb_xkb_get_device_info_cookie_t cookie =
xcb_xkb_get_device_info(conn, XCB_XKB_ID_USE_CORE_KBD,
0, 0, 0, 0, 0, 0);
xcb_xkb_get_device_info_reply_t *reply =
xcb_xkb_get_device_info_reply(conn, cookie, NULL);
if (!reply)
return -1;
device_id = reply->deviceID;
free(reply);
return device_id;
}
bool
get_atom_name(xcb_connection_t *conn, xcb_atom_t atom, char **out)
{
xcb_get_atom_name_cookie_t cookie;
xcb_get_atom_name_reply_t *reply;
int length;
char *name;
if (atom == 0) {
*out = NULL;
return true;
}
cookie = xcb_get_atom_name(conn, atom);
reply = xcb_get_atom_name_reply(conn, cookie, NULL);
if (!reply)
return false;
length = xcb_get_atom_name_name_length(reply);
name = xcb_get_atom_name_name(reply);
*out = strndup(name, length);
if (!*out) {
free(reply);
return false;
}
free(reply);
return true;
}
bool
adopt_atoms(struct xkb_context *ctx, xcb_connection_t *conn,
const xcb_atom_t *from, xkb_atom_t *to, const size_t count)
{
enum { SIZE = 128 };
xcb_get_atom_name_cookie_t cookies[SIZE];
const size_t num_batches = ROUNDUP(count, SIZE) / SIZE;
/* Send and collect the atoms in batches of reasonable SIZE. */
for (size_t batch = 0; batch < num_batches; batch++) {
const size_t start = batch * SIZE;
const size_t stop = min((batch + 1) * SIZE, count);
/* Send. */
for (size_t i = start; i < stop; i++)
if (from[i] != XCB_ATOM_NONE)
cookies[i % SIZE] = xcb_get_atom_name(conn, from[i]);
/* Collect. */
for (size_t i = start; i < stop; i++) {
xcb_get_atom_name_reply_t *reply;
if (from[i] == XCB_ATOM_NONE) {
to[i] = XKB_ATOM_NONE;
continue;
}
reply = xcb_get_atom_name_reply(conn, cookies[i % SIZE], NULL);
if (!reply)
goto err_discard;
to[i] = xkb_atom_intern(ctx,
xcb_get_atom_name_name(reply),
xcb_get_atom_name_name_length(reply));
free(reply);
if (to[i] == XKB_ATOM_NONE)
goto err_discard;
continue;
/*
* If we don't discard the uncollected replies, they just
* sit in the XCB queue waiting forever. Sad.
*/
err_discard:
for (size_t j = i + 1; j < stop; j++)
if (from[j] != XCB_ATOM_NONE)
xcb_discard_reply(conn, cookies[j % SIZE].sequence);
return false;
}
}
return true;
}
bool
adopt_atom(struct xkb_context *ctx, xcb_connection_t *conn, xcb_atom_t atom,
xkb_atom_t *out)
{
return adopt_atoms(ctx, conn, &atom, out, 1);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,54 +0,0 @@
/*
* Copyright © 2013 Ran Benita
*
* 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 (including the next
* paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
*/
#ifndef _XKBCOMMON_X11_PRIV_H
#define _XKBCOMMON_X11_PRIV_H
#include <xcb/xkb.h>
#include "keymap.h"
#include "xkbcommon/xkbcommon-x11.h"
/* Get a strdup'd name of an X atom. */
bool
get_atom_name(xcb_connection_t *conn, xcb_atom_t atom, char **out);
/*
* Make a xkb_atom_t's from X atoms (prefer to send as many as possible
* at once, to avoid many roundtrips).
*
* TODO: We can make this more flexible, such that @to doesn't have to
* be sequential. Then we can convert most adopt_atom() calls to
* adopt_atoms().
* Atom caching would also likely be useful for avoiding quite a
* few requests.
*/
bool
adopt_atoms(struct xkb_context *ctx, xcb_connection_t *conn,
const xcb_atom_t *from, xkb_atom_t *to, size_t count);
bool
adopt_atom(struct xkb_context *ctx, xcb_connection_t *conn, xcb_atom_t atom,
xkb_atom_t *out);
#endif

View File

@ -1,71 +0,0 @@
/*
* Copyright © 2013 Ran Benita
*
* 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 (including the next
* paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
*/
#include "x11-priv.h"
static bool
update_initial_state(struct xkb_state *state, xcb_connection_t *conn,
uint16_t device_id)
{
xcb_xkb_get_state_cookie_t cookie =
xcb_xkb_get_state(conn, device_id);
xcb_xkb_get_state_reply_t *reply =
xcb_xkb_get_state_reply(conn, cookie, NULL);
if (!reply)
return false;
xkb_state_update_mask(state,
reply->baseMods,
reply->latchedMods,
reply->lockedMods,
reply->baseGroup,
reply->latchedGroup,
reply->lockedGroup);
free(reply);
return true;
}
XKB_EXPORT struct xkb_state *
xkb_x11_state_new_from_device(struct xkb_keymap *keymap,
xcb_connection_t *conn, int32_t device_id)
{
struct xkb_state *state;
if (device_id < 0 || device_id > 255) {
log_err_func(keymap->ctx, "illegal device ID: %d", device_id);
return NULL;
}
state = xkb_state_new(keymap);
if (!state)
return NULL;
if (!update_initial_state(state, conn, device_id)) {
xkb_state_unref(state);
return NULL;
}
return state;
}

View File

@ -1,871 +0,0 @@
/************************************************************
* Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting
* documentation, and that the name of Silicon Graphics not be
* used in advertising or publicity pertaining to distribution
* of the software without specific prior written permission.
* Silicon Graphics makes no representation about the suitability
* of this software for any purpose. It is provided "as is"
* without any express or implied warranty.
*
* SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
* GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
********************************************************/
/*
* Copyright © 2012 Intel Corporation
* Copyright © 2012 Ran Benita <ran234@gmail.com>
*
* 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 (including the next
* paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
*
* Author: Daniel Stone <daniel@fooishbar.org>
* Ran Benita <ran234@gmail.com>
*/
#include "xkbcomp-priv.h"
#include "text.h"
#include "expr.h"
#include "action.h"
static const ExprBoolean constTrue = {
.expr = {
.common = { .type = STMT_EXPR, .next = NULL },
.op = EXPR_VALUE,
.value_type = EXPR_TYPE_BOOLEAN,
},
.set = true,
};
static const ExprBoolean constFalse = {
.expr = {
.common = { .type = STMT_EXPR, .next = NULL },
.op = EXPR_VALUE,
.value_type = EXPR_TYPE_BOOLEAN,
},
.set = false,
};
enum action_field {
ACTION_FIELD_CLEAR_LOCKS,
ACTION_FIELD_LATCH_TO_LOCK,
ACTION_FIELD_GEN_KEY_EVENT,
ACTION_FIELD_REPORT,
ACTION_FIELD_DEFAULT,
ACTION_FIELD_AFFECT,
ACTION_FIELD_INCREMENT,
ACTION_FIELD_MODIFIERS,
ACTION_FIELD_GROUP,
ACTION_FIELD_X,
ACTION_FIELD_Y,
ACTION_FIELD_ACCEL,
ACTION_FIELD_BUTTON,
ACTION_FIELD_VALUE,
ACTION_FIELD_CONTROLS,
ACTION_FIELD_TYPE,
ACTION_FIELD_COUNT,
ACTION_FIELD_SCREEN,
ACTION_FIELD_SAME,
ACTION_FIELD_DATA,
ACTION_FIELD_DEVICE,
ACTION_FIELD_KEYCODE,
ACTION_FIELD_MODS_TO_CLEAR,
};
ActionsInfo *
NewActionsInfo(void)
{
enum xkb_action_type type;
ActionsInfo *info;
info = calloc(1, sizeof(*info));
if (!info)
return NULL;
for (type = 0; type < _ACTION_TYPE_NUM_ENTRIES; type++)
info->actions[type].type = type;
/* Apply some "factory defaults". */
/* Increment default button. */
info->actions[ACTION_TYPE_PTR_DEFAULT].dflt.flags = 0;
info->actions[ACTION_TYPE_PTR_DEFAULT].dflt.value = 1;
info->actions[ACTION_TYPE_PTR_MOVE].ptr.flags = ACTION_ACCEL;
info->actions[ACTION_TYPE_SWITCH_VT].screen.flags = ACTION_SAME_SCREEN;
return info;
}
void
FreeActionsInfo(ActionsInfo *info)
{
free(info);
}
static const LookupEntry fieldStrings[] = {
{ "clearLocks", ACTION_FIELD_CLEAR_LOCKS },
{ "latchToLock", ACTION_FIELD_LATCH_TO_LOCK },
{ "genKeyEvent", ACTION_FIELD_GEN_KEY_EVENT },
{ "generateKeyEvent", ACTION_FIELD_GEN_KEY_EVENT },
{ "report", ACTION_FIELD_REPORT },
{ "default", ACTION_FIELD_DEFAULT },
{ "affect", ACTION_FIELD_AFFECT },
{ "increment", ACTION_FIELD_INCREMENT },
{ "modifiers", ACTION_FIELD_MODIFIERS },
{ "mods", ACTION_FIELD_MODIFIERS },
{ "group", ACTION_FIELD_GROUP },
{ "x", ACTION_FIELD_X },
{ "y", ACTION_FIELD_Y },
{ "accel", ACTION_FIELD_ACCEL },
{ "accelerate", ACTION_FIELD_ACCEL },
{ "repeat", ACTION_FIELD_ACCEL },
{ "button", ACTION_FIELD_BUTTON },
{ "value", ACTION_FIELD_VALUE },
{ "controls", ACTION_FIELD_CONTROLS },
{ "ctrls", ACTION_FIELD_CONTROLS },
{ "type", ACTION_FIELD_TYPE },
{ "count", ACTION_FIELD_COUNT },
{ "screen", ACTION_FIELD_SCREEN },
{ "same", ACTION_FIELD_SAME },
{ "sameServer", ACTION_FIELD_SAME },
{ "data", ACTION_FIELD_DATA },
{ "device", ACTION_FIELD_DEVICE },
{ "dev", ACTION_FIELD_DEVICE },
{ "key", ACTION_FIELD_KEYCODE },
{ "keycode", ACTION_FIELD_KEYCODE },
{ "kc", ACTION_FIELD_KEYCODE },
{ "clearmods", ACTION_FIELD_MODS_TO_CLEAR },
{ "clearmodifiers", ACTION_FIELD_MODS_TO_CLEAR },
{ NULL, 0 }
};
static bool
stringToAction(const char *str, enum xkb_action_type *type_rtrn)
{
return LookupString(actionTypeNames, str, type_rtrn);
}
static bool
stringToField(const char *str, enum action_field *field_rtrn)
{
return LookupString(fieldStrings, str, field_rtrn);
}
static const char *
fieldText(enum action_field field)
{
return LookupValue(fieldStrings, field);
}
/***====================================================================***/
static inline bool
ReportMismatch(struct xkb_context *ctx, enum xkb_action_type action,
enum action_field field, const char *type)
{
log_err(ctx,
"Value of %s field must be of type %s; "
"Action %s definition ignored\n",
fieldText(field), type, ActionTypeText(action));
return false;
}
static inline bool
ReportIllegal(struct xkb_context *ctx, enum xkb_action_type action,
enum action_field field)
{
log_err(ctx,
"Field %s is not defined for an action of type %s; "
"Action definition ignored\n",
fieldText(field), ActionTypeText(action));
return false;
}
static inline bool
ReportActionNotArray(struct xkb_context *ctx, enum xkb_action_type action,
enum action_field field)
{
log_err(ctx,
"The %s field in the %s action is not an array; "
"Action definition ignored\n",
fieldText(field), ActionTypeText(action));
return false;
}
static bool
HandleNoAction(struct xkb_context *ctx, const struct xkb_mod_set *mods,
union xkb_action *action, enum action_field field,
const ExprDef *array_ndx, const ExprDef *value)
{
return true;
}
static bool
CheckBooleanFlag(struct xkb_context *ctx, enum xkb_action_type action,
enum action_field field, enum xkb_action_flags flag,
const ExprDef *array_ndx, const ExprDef *value,
enum xkb_action_flags *flags_inout)
{
bool set;
if (array_ndx)
return ReportActionNotArray(ctx, action, field);
if (!ExprResolveBoolean(ctx, value, &set))
return ReportMismatch(ctx, action, field, "boolean");
if (set)
*flags_inout |= flag;
else
*flags_inout &= ~flag;
return true;
}
static bool
CheckModifierField(struct xkb_context *ctx, const struct xkb_mod_set *mods,
enum xkb_action_type action, const ExprDef *array_ndx,
const ExprDef *value, enum xkb_action_flags *flags_inout,
xkb_mod_mask_t *mods_rtrn)
{
if (array_ndx)
return ReportActionNotArray(ctx, action, ACTION_FIELD_MODIFIERS);
if (value->expr.op == EXPR_IDENT) {
const char *valStr;
valStr = xkb_atom_text(ctx, value->ident.ident);
if (valStr && (istreq(valStr, "usemodmapmods") ||
istreq(valStr, "modmapmods"))) {
*mods_rtrn = 0;
*flags_inout |= ACTION_MODS_LOOKUP_MODMAP;
return true;
}
}
if (!ExprResolveModMask(ctx, value, MOD_BOTH, mods, mods_rtrn))
return ReportMismatch(ctx, action,
ACTION_FIELD_MODIFIERS, "modifier mask");
*flags_inout &= ~ACTION_MODS_LOOKUP_MODMAP;
return true;
}
static const LookupEntry lockWhich[] = {
{ "both", 0 },
{ "lock", ACTION_LOCK_NO_UNLOCK },
{ "neither", (ACTION_LOCK_NO_LOCK | ACTION_LOCK_NO_UNLOCK) },
{ "unlock", ACTION_LOCK_NO_LOCK },
{ NULL, 0 }
};
static bool
CheckAffectField(struct xkb_context *ctx, enum xkb_action_type action,
const ExprDef *array_ndx, const ExprDef *value,
enum xkb_action_flags *flags_inout)
{
enum xkb_action_flags flags;
if (array_ndx)
return ReportActionNotArray(ctx, action, ACTION_FIELD_AFFECT);
if (!ExprResolveEnum(ctx, value, &flags, lockWhich))
return ReportMismatch(ctx, action, ACTION_FIELD_AFFECT,
"lock, unlock, both, neither");
*flags_inout &= ~(ACTION_LOCK_NO_LOCK | ACTION_LOCK_NO_UNLOCK);
*flags_inout |= flags;
return true;
}
static bool
HandleSetLatchLockMods(struct xkb_context *ctx, const struct xkb_mod_set *mods,
union xkb_action *action, enum action_field field,
const ExprDef *array_ndx, const ExprDef *value)
{
struct xkb_mod_action *act = &action->mods;
const enum xkb_action_type type = action->type;
if (field == ACTION_FIELD_MODIFIERS)
return CheckModifierField(ctx, mods, action->type, array_ndx, value,
&act->flags, &act->mods.mods);
if ((type == ACTION_TYPE_MOD_SET || type == ACTION_TYPE_MOD_LATCH) &&
field == ACTION_FIELD_CLEAR_LOCKS)
return CheckBooleanFlag(ctx, action->type, field,
ACTION_LOCK_CLEAR, array_ndx, value,
&act->flags);
if (type == ACTION_TYPE_MOD_LATCH &&
field == ACTION_FIELD_LATCH_TO_LOCK)
return CheckBooleanFlag(ctx, action->type, field,
ACTION_LATCH_TO_LOCK, array_ndx, value,
&act->flags);
if (type == ACTION_TYPE_MOD_LOCK &&
field == ACTION_FIELD_AFFECT)
return CheckAffectField(ctx, action->type, array_ndx, value,
&act->flags);
return ReportIllegal(ctx, action->type, field);
}
static bool
CheckGroupField(struct xkb_context *ctx, enum xkb_action_type action,
const ExprDef *array_ndx, const ExprDef *value,
enum xkb_action_flags *flags_inout, int32_t *group_rtrn)
{
const ExprDef *spec;
xkb_layout_index_t idx;
enum xkb_action_flags flags = *flags_inout;
if (array_ndx)
return ReportActionNotArray(ctx, action, ACTION_FIELD_GROUP);
if (value->expr.op == EXPR_NEGATE || value->expr.op == EXPR_UNARY_PLUS) {
flags &= ~ACTION_ABSOLUTE_SWITCH;
spec = value->unary.child;
}
else {
flags |= ACTION_ABSOLUTE_SWITCH;
spec = value;
}
if (!ExprResolveGroup(ctx, spec, &idx))
return ReportMismatch(ctx, action, ACTION_FIELD_GROUP,
"integer (range 1..8)");
/* +n, -n are relative, n is absolute. */
if (value->expr.op == EXPR_NEGATE || value->expr.op == EXPR_UNARY_PLUS) {
*group_rtrn = (int32_t) idx;
if (value->expr.op == EXPR_NEGATE)
*group_rtrn = -*group_rtrn;
}
else {
*group_rtrn = (int32_t) (idx - 1);
}
*flags_inout = flags;
return true;
}
static bool
HandleSetLatchLockGroup(struct xkb_context *ctx, const struct xkb_mod_set *mods,
union xkb_action *action, enum action_field field,
const ExprDef *array_ndx, const ExprDef *value)
{
struct xkb_group_action *act = &action->group;
const enum xkb_action_type type = action->type;
if (field == ACTION_FIELD_GROUP)
return CheckGroupField(ctx, action->type, array_ndx, value,
&act->flags, &act->group);
if ((type == ACTION_TYPE_GROUP_SET || type == ACTION_TYPE_GROUP_LATCH) &&
field == ACTION_FIELD_CLEAR_LOCKS)
return CheckBooleanFlag(ctx, action->type, field,
ACTION_LOCK_CLEAR, array_ndx, value,
&act->flags);
if (type == ACTION_TYPE_GROUP_LATCH &&
field == ACTION_FIELD_LATCH_TO_LOCK)
return CheckBooleanFlag(ctx, action->type, field,
ACTION_LATCH_TO_LOCK, array_ndx, value,
&act->flags);
return ReportIllegal(ctx, action->type, field);
}
static bool
HandleMovePtr(struct xkb_context *ctx, const struct xkb_mod_set *mods,
union xkb_action *action, enum action_field field,
const ExprDef *array_ndx, const ExprDef *value)
{
struct xkb_pointer_action *act = &action->ptr;
if (field == ACTION_FIELD_X || field == ACTION_FIELD_Y) {
int val;
const bool absolute = (value->expr.op != EXPR_NEGATE &&
value->expr.op != EXPR_UNARY_PLUS);
if (array_ndx)
return ReportActionNotArray(ctx, action->type, field);
if (!ExprResolveInteger(ctx, value, &val))
return ReportMismatch(ctx, action->type, field, "integer");
if (val < INT16_MIN || val > INT16_MAX) {
log_err(ctx,
"The %s field in the %s action must be in range %d..%d; "
"Action definition ignored\n",
fieldText(field), ActionTypeText(action->type),
INT16_MIN, INT16_MAX);
return false;
}
if (field == ACTION_FIELD_X) {
if (absolute)
act->flags |= ACTION_ABSOLUTE_X;
act->x = (int16_t) val;
}
else {
if (absolute)
act->flags |= ACTION_ABSOLUTE_Y;
act->y = (int16_t) val;
}
return true;
}
else if (field == ACTION_FIELD_ACCEL) {
return CheckBooleanFlag(ctx, action->type, field,
ACTION_ACCEL, array_ndx, value, &act->flags);
}
return ReportIllegal(ctx, action->type, field);
}
static bool
HandlePtrBtn(struct xkb_context *ctx, const struct xkb_mod_set *mods,
union xkb_action *action, enum action_field field,
const ExprDef *array_ndx, const ExprDef *value)
{
struct xkb_pointer_button_action *act = &action->btn;
if (field == ACTION_FIELD_BUTTON) {
int btn;
if (array_ndx)
return ReportActionNotArray(ctx, action->type, field);
if (!ExprResolveButton(ctx, value, &btn))
return ReportMismatch(ctx, action->type, field,
"integer (range 1..5)");
if (btn < 0 || btn > 5) {
log_err(ctx,
"Button must specify default or be in the range 1..5; "
"Illegal button value %d ignored\n", btn);
return false;
}
act->button = btn;
return true;
}
else if (action->type == ACTION_TYPE_PTR_LOCK &&
field == ACTION_FIELD_AFFECT) {
return CheckAffectField(ctx, action->type, array_ndx, value,
&act->flags);
}
else if (field == ACTION_FIELD_COUNT) {
int val;
if (array_ndx)
return ReportActionNotArray(ctx, action->type, field);
if (!ExprResolveInteger(ctx, value, &val))
return ReportMismatch(ctx, action->type, field, "integer");
if (val < 0 || val > 255) {
log_err(ctx,
"The count field must have a value in the range 0..255; "
"Illegal count %d ignored\n", val);
return false;
}
act->count = (uint8_t) val;
return true;
}
return ReportIllegal(ctx, action->type, field);
}
static const LookupEntry ptrDflts[] = {
{ "dfltbtn", 1 },
{ "defaultbutton", 1 },
{ "button", 1 },
{ NULL, 0 }
};
static bool
HandleSetPtrDflt(struct xkb_context *ctx, const struct xkb_mod_set *mods,
union xkb_action *action, enum action_field field,
const ExprDef *array_ndx, const ExprDef *value)
{
struct xkb_pointer_default_action *act = &action->dflt;
if (field == ACTION_FIELD_AFFECT) {
unsigned int val;
if (array_ndx)
return ReportActionNotArray(ctx, action->type, field);
if (!ExprResolveEnum(ctx, value, &val, ptrDflts))
return ReportMismatch(ctx, action->type, field,
"pointer component");
return true;
}
else if (field == ACTION_FIELD_BUTTON || field == ACTION_FIELD_VALUE) {
const ExprDef *button;
int btn;
if (array_ndx)
return ReportActionNotArray(ctx, action->type, field);
if (value->expr.op == EXPR_NEGATE ||
value->expr.op == EXPR_UNARY_PLUS) {
act->flags &= ~ACTION_ABSOLUTE_SWITCH;
button = value->unary.child;
}
else {
act->flags |= ACTION_ABSOLUTE_SWITCH;
button = value;
}
if (!ExprResolveButton(ctx, button, &btn))
return ReportMismatch(ctx, action->type, field,
"integer (range 1..5)");
if (btn < 0 || btn > 5) {
log_err(ctx,
"New default button value must be in the range 1..5; "
"Illegal default button value %d ignored\n", btn);
return false;
}
if (btn == 0) {
log_err(ctx,
"Cannot set default pointer button to \"default\"; "
"Illegal default button setting ignored\n");
return false;
}
act->value = (value->expr.op == EXPR_NEGATE ? -btn: btn);
return true;
}
return ReportIllegal(ctx, action->type, field);
}
static bool
HandleSwitchScreen(struct xkb_context *ctx, const struct xkb_mod_set *mods,
union xkb_action *action, enum action_field field,
const ExprDef *array_ndx, const ExprDef *value)
{
struct xkb_switch_screen_action *act = &action->screen;
if (field == ACTION_FIELD_SCREEN) {
const ExprDef *scrn;
int val;
if (array_ndx)
return ReportActionNotArray(ctx, action->type, field);
if (value->expr.op == EXPR_NEGATE ||
value->expr.op == EXPR_UNARY_PLUS) {
act->flags &= ~ACTION_ABSOLUTE_SWITCH;
scrn = value->unary.child;
}
else {
act->flags |= ACTION_ABSOLUTE_SWITCH;
scrn = value;
}
if (!ExprResolveInteger(ctx, scrn, &val))
return ReportMismatch(ctx, action->type, field,
"integer (0..255)");
if (val < 0 || val > 255) {
log_err(ctx,
"Screen index must be in the range 1..255; "
"Illegal screen value %d ignored\n", val);
return false;
}
act->screen = (value->expr.op == EXPR_NEGATE ? -val : val);
return true;
}
else if (field == ACTION_FIELD_SAME) {
return CheckBooleanFlag(ctx, action->type, field,
ACTION_SAME_SCREEN, array_ndx, value,
&act->flags);
}
return ReportIllegal(ctx, action->type, field);
}
static bool
HandleSetLockControls(struct xkb_context *ctx, const struct xkb_mod_set *mods,
union xkb_action *action, enum action_field field,
const ExprDef *array_ndx, const ExprDef *value)
{
struct xkb_controls_action *act = &action->ctrls;
if (field == ACTION_FIELD_CONTROLS) {
enum xkb_action_controls mask;
if (array_ndx)
return ReportActionNotArray(ctx, action->type, field);
if (!ExprResolveMask(ctx, value, &mask, ctrlMaskNames))
return ReportMismatch(ctx, action->type, field,
"controls mask");
act->ctrls = mask;
return true;
}
else if (field == ACTION_FIELD_AFFECT) {
return CheckAffectField(ctx, action->type, array_ndx, value,
&act->flags);
}
return ReportIllegal(ctx, action->type, field);
}
static bool
HandlePrivate(struct xkb_context *ctx, const struct xkb_mod_set *mods,
union xkb_action *action, enum action_field field,
const ExprDef *array_ndx, const ExprDef *value)
{
struct xkb_private_action *act = &action->priv;
if (field == ACTION_FIELD_TYPE) {
int type;
if (array_ndx)
return ReportActionNotArray(ctx, action->type, field);
if (!ExprResolveInteger(ctx, value, &type))
return ReportMismatch(ctx, ACTION_TYPE_PRIVATE, field, "integer");
if (type < 0 || type > 255) {
log_err(ctx,
"Private action type must be in the range 0..255; "
"Illegal type %d ignored\n", type);
return false;
}
/*
* It's possible for someone to write something like this:
* actions = [ Private(type=3,data[0]=1,data[1]=3,data[2]=3) ]
* where the type refers to some existing action type, e.g. LockMods.
* This assumes that this action's struct is laid out in memory
* exactly as described in the XKB specification and libraries.
* We, however, have changed these structs in various ways, so this
* assumption is no longer true. Since this is a lousy "feature", we
* make actions like these no-ops for now.
*/
if (type < ACTION_TYPE_PRIVATE) {
log_info(ctx,
"Private actions of type %s are not supported; Ignored\n",
ActionTypeText(type));
act->type = ACTION_TYPE_NONE;
}
else {
act->type = (enum xkb_action_type) type;
}
return true;
}
else if (field == ACTION_FIELD_DATA) {
if (array_ndx == NULL) {
xkb_atom_t val;
const char *str;
size_t len;
if (!ExprResolveString(ctx, value, &val))
return ReportMismatch(ctx, action->type, field, "string");
str = xkb_atom_text(ctx, val);
len = strlen(str);
if (len < 1 || len > 7) {
log_warn(ctx,
"A private action has 7 data bytes; "
"Illegal data ignored\n");
return false;
}
/* act->data may not be null-terminated, this is intentional */
strncpy((char *) act->data, str, sizeof(act->data));
return true;
}
else {
int ndx, datum;
if (!ExprResolveInteger(ctx, array_ndx, &ndx)) {
log_err(ctx,
"Array subscript must be integer; "
"Illegal subscript ignored\n");
return false;
}
if (ndx < 0 || (size_t) ndx >= sizeof(act->data)) {
log_err(ctx,
"The data for a private action is %lu bytes long; "
"Attempt to use data[%d] ignored\n",
(unsigned long) sizeof(act->data), ndx);
return false;
}
if (!ExprResolveInteger(ctx, value, &datum))
return ReportMismatch(ctx, act->type, field, "integer");
if (datum < 0 || datum > 255) {
log_err(ctx,
"All data for a private action must be 0..255; "
"Illegal datum %d ignored\n", datum);
return false;
}
act->data[ndx] = (uint8_t) datum;
return true;
}
}
return ReportIllegal(ctx, ACTION_TYPE_NONE, field);
}
typedef bool (*actionHandler)(struct xkb_context *ctx,
const struct xkb_mod_set *mods,
union xkb_action *action,
enum action_field field,
const ExprDef *array_ndx,
const ExprDef *value);
static const actionHandler handleAction[_ACTION_TYPE_NUM_ENTRIES] = {
[ACTION_TYPE_NONE] = HandleNoAction,
[ACTION_TYPE_MOD_SET] = HandleSetLatchLockMods,
[ACTION_TYPE_MOD_LATCH] = HandleSetLatchLockMods,
[ACTION_TYPE_MOD_LOCK] = HandleSetLatchLockMods,
[ACTION_TYPE_GROUP_SET] = HandleSetLatchLockGroup,
[ACTION_TYPE_GROUP_LATCH] = HandleSetLatchLockGroup,
[ACTION_TYPE_GROUP_LOCK] = HandleSetLatchLockGroup,
[ACTION_TYPE_PTR_MOVE] = HandleMovePtr,
[ACTION_TYPE_PTR_BUTTON] = HandlePtrBtn,
[ACTION_TYPE_PTR_LOCK] = HandlePtrBtn,
[ACTION_TYPE_PTR_DEFAULT] = HandleSetPtrDflt,
[ACTION_TYPE_TERMINATE] = HandleNoAction,
[ACTION_TYPE_SWITCH_VT] = HandleSwitchScreen,
[ACTION_TYPE_CTRL_SET] = HandleSetLockControls,
[ACTION_TYPE_CTRL_LOCK] = HandleSetLockControls,
[ACTION_TYPE_PRIVATE] = HandlePrivate,
};
/***====================================================================***/
bool
HandleActionDef(struct xkb_context *ctx, ActionsInfo *info,
const struct xkb_mod_set *mods, ExprDef *def,
union xkb_action *action)
{
ExprDef *arg;
const char *str;
enum xkb_action_type handler_type;
if (def->expr.op != EXPR_ACTION_DECL) {
log_err(ctx, "Expected an action definition, found %s\n",
expr_op_type_to_string(def->expr.op));
return false;
}
str = xkb_atom_text(ctx, def->action.name);
if (!stringToAction(str, &handler_type)) {
log_err(ctx, "Unknown action %s\n", str);
return false;
}
/*
* Get the default values for this action type, as modified by
* statements such as:
* latchMods.clearLocks = True;
*/
*action = info->actions[handler_type];
/*
* Now change the action properties as specified for this
* particular instance, e.g. "modifiers" and "clearLocks" in:
* SetMods(modifiers=Alt,clearLocks);
*/
for (arg = def->action.args; arg != NULL;
arg = (ExprDef *) arg->common.next) {
const ExprDef *value;
ExprDef *field, *arrayRtrn;
const char *elemRtrn, *fieldRtrn;
enum action_field fieldNdx;
if (arg->expr.op == EXPR_ASSIGN) {
field = arg->binary.left;
value = arg->binary.right;
}
else if (arg->expr.op == EXPR_NOT || arg->expr.op == EXPR_INVERT) {
field = arg->unary.child;
value = (const ExprDef *) &constFalse;
}
else {
field = arg;
value = (const ExprDef *) &constTrue;
}
if (!ExprResolveLhs(ctx, field, &elemRtrn, &fieldRtrn, &arrayRtrn))
return false;
if (elemRtrn) {
log_err(ctx,
"Cannot change defaults in an action definition; "
"Ignoring attempt to change %s.%s\n",
elemRtrn, fieldRtrn);
return false;
}
if (!stringToField(fieldRtrn, &fieldNdx)) {
log_err(ctx, "Unknown field name %s\n", fieldRtrn);
return false;
}
if (!handleAction[handler_type](ctx, mods, action, fieldNdx,
arrayRtrn, value))
return false;
}
return true;
}
bool
SetActionField(struct xkb_context *ctx, ActionsInfo *info,
struct xkb_mod_set *mods, const char *elem,
const char *field, ExprDef *array_ndx, ExprDef *value)
{
enum xkb_action_type action;
enum action_field action_field;
if (!stringToAction(elem, &action))
return false;
if (!stringToField(field, &action_field)) {
log_err(ctx, "\"%s\" is not a legal field name\n", field);
return false;
}
return handleAction[action](ctx, mods, &info->actions[action],
action_field, array_ndx, value);
}

View File

@ -1,56 +0,0 @@
/************************************************************
* Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting
* documentation, and that the name of Silicon Graphics not be
* used in advertising or publicity pertaining to distribution
* of the software without specific prior written permission.
* Silicon Graphics makes no representation about the suitability
* of this software for any purpose. It is provided "as is"
* without any express or implied warranty.
*
* SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
* GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
********************************************************/
#ifndef XKBCOMP_ACTION_H
#define XKBCOMP_ACTION_H
/*
* This struct contains the default values which every new action
* (e.g. in an interpret statement) starts off with. It can be
* modified within the files (see calls to SetActionField).
*/
typedef struct {
union xkb_action actions[_ACTION_TYPE_NUM_ENTRIES];
} ActionsInfo;
ActionsInfo *
NewActionsInfo(void);
void
FreeActionsInfo(ActionsInfo *info);
bool
HandleActionDef(struct xkb_context *ctx, ActionsInfo *info,
const struct xkb_mod_set *mods, ExprDef *def,
union xkb_action *action);
bool
SetActionField(struct xkb_context *ctx, ActionsInfo *info,
struct xkb_mod_set *mods, const char *elem,
const char *field, ExprDef *array_ndx, ExprDef *value);
#endif

View File

@ -1,806 +0,0 @@
/************************************************************
* Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting
* documentation, and that the name of Silicon Graphics not be
* used in advertising or publicity pertaining to distribution
* of the software without specific prior written permission.
* Silicon Graphics makes no representation about the suitability
* of this software for any purpose. It is provided "as is"
* without any express or implied warranty.
*
* SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
* GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
********************************************************/
/*
* Copyright © 2012 Intel Corporation
* Copyright © 2012 Ran Benita <ran234@gmail.com>
*
* 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 (including the next
* paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
*
* Author: Daniel Stone <daniel@fooishbar.org>
* Ran Benita <ran234@gmail.com>
*/
#include "xkbcomp-priv.h"
#include "ast-build.h"
#include "include.h"
ParseCommon *
AppendStmt(ParseCommon *to, ParseCommon *append)
{
ParseCommon *iter;
if (!to)
return append;
for (iter = to; iter->next; iter = iter->next);
iter->next = append;
return to;
}
static ExprDef *
ExprCreate(enum expr_op_type op, enum expr_value_type type, size_t size)
{
ExprDef *expr = malloc(size);
if (!expr)
return NULL;
expr->common.type = STMT_EXPR;
expr->common.next = NULL;
expr->expr.op = op;
expr->expr.value_type = type;
return expr;
}
#define EXPR_CREATE(type_, name_, op_, value_type_) \
ExprDef *name_ = ExprCreate(op_, value_type_, sizeof(type_)); \
if (!name_) \
return NULL;
ExprDef *
ExprCreateString(xkb_atom_t str)
{
EXPR_CREATE(ExprString, expr, EXPR_VALUE, EXPR_TYPE_STRING);
expr->string.str = str;
return expr;
}
ExprDef *
ExprCreateInteger(int ival)
{
EXPR_CREATE(ExprInteger, expr, EXPR_VALUE, EXPR_TYPE_INT);
expr->integer.ival = ival;
return expr;
}
ExprDef *
ExprCreateFloat(void)
{
EXPR_CREATE(ExprFloat, expr, EXPR_VALUE, EXPR_TYPE_FLOAT);
return expr;
}
ExprDef *
ExprCreateBoolean(bool set)
{
EXPR_CREATE(ExprBoolean, expr, EXPR_VALUE, EXPR_TYPE_BOOLEAN);
expr->boolean.set = set;
return expr;
}
ExprDef *
ExprCreateKeyName(xkb_atom_t key_name)
{
EXPR_CREATE(ExprKeyName, expr, EXPR_VALUE, EXPR_TYPE_KEYNAME);
expr->key_name.key_name = key_name;
return expr;
}
ExprDef *
ExprCreateIdent(xkb_atom_t ident)
{
EXPR_CREATE(ExprIdent, expr, EXPR_IDENT, EXPR_TYPE_UNKNOWN);
expr->ident.ident = ident;
return expr;
}
ExprDef *
ExprCreateUnary(enum expr_op_type op, enum expr_value_type type,
ExprDef *child)
{
EXPR_CREATE(ExprUnary, expr, op, type);
expr->unary.child = child;
return expr;
}
ExprDef *
ExprCreateBinary(enum expr_op_type op, ExprDef *left, ExprDef *right)
{
EXPR_CREATE(ExprBinary, expr, op, EXPR_TYPE_UNKNOWN);
if (op == EXPR_ASSIGN || left->expr.value_type == EXPR_TYPE_UNKNOWN)
expr->expr.value_type = right->expr.value_type;
else if (left->expr.value_type == right->expr.value_type ||
right->expr.value_type == EXPR_TYPE_UNKNOWN)
expr->expr.value_type = left->expr.value_type;
expr->binary.left = left;
expr->binary.right = right;
return expr;
}
ExprDef *
ExprCreateFieldRef(xkb_atom_t element, xkb_atom_t field)
{
EXPR_CREATE(ExprFieldRef, expr, EXPR_FIELD_REF, EXPR_TYPE_UNKNOWN);
expr->field_ref.element = element;
expr->field_ref.field = field;
return expr;
}
ExprDef *
ExprCreateArrayRef(xkb_atom_t element, xkb_atom_t field, ExprDef *entry)
{
EXPR_CREATE(ExprArrayRef, expr, EXPR_ARRAY_REF, EXPR_TYPE_UNKNOWN);
expr->array_ref.element = element;
expr->array_ref.field = field;
expr->array_ref.entry = entry;
return expr;
}
ExprDef *
ExprCreateAction(xkb_atom_t name, ExprDef *args)
{
EXPR_CREATE(ExprAction, expr, EXPR_ACTION_DECL, EXPR_TYPE_UNKNOWN);
expr->action.name = name;
expr->action.args = args;
return expr;
}
ExprDef *
ExprCreateKeysymList(xkb_keysym_t sym)
{
EXPR_CREATE(ExprKeysymList, expr, EXPR_KEYSYM_LIST, EXPR_TYPE_SYMBOLS);
darray_init(expr->keysym_list.syms);
darray_init(expr->keysym_list.symsMapIndex);
darray_init(expr->keysym_list.symsNumEntries);
darray_append(expr->keysym_list.syms, sym);
darray_append(expr->keysym_list.symsMapIndex, 0);
darray_append(expr->keysym_list.symsNumEntries, 1);
return expr;
}
ExprDef *
ExprCreateMultiKeysymList(ExprDef *expr)
{
unsigned nLevels = darray_size(expr->keysym_list.symsMapIndex);
darray_resize(expr->keysym_list.symsMapIndex, 1);
darray_resize(expr->keysym_list.symsNumEntries, 1);
darray_item(expr->keysym_list.symsMapIndex, 0) = 0;
darray_item(expr->keysym_list.symsNumEntries, 0) = nLevels;
return expr;
}
ExprDef *
ExprAppendKeysymList(ExprDef *expr, xkb_keysym_t sym)
{
unsigned nSyms = darray_size(expr->keysym_list.syms);
darray_append(expr->keysym_list.symsMapIndex, nSyms);
darray_append(expr->keysym_list.symsNumEntries, 1);
darray_append(expr->keysym_list.syms, sym);
return expr;
}
ExprDef *
ExprAppendMultiKeysymList(ExprDef *expr, ExprDef *append)
{
unsigned nSyms = darray_size(expr->keysym_list.syms);
unsigned numEntries = darray_size(append->keysym_list.syms);
darray_append(expr->keysym_list.symsMapIndex, nSyms);
darray_append(expr->keysym_list.symsNumEntries, numEntries);
darray_concat(expr->keysym_list.syms, append->keysym_list.syms);
FreeStmt((ParseCommon *) append);
return expr;
}
KeycodeDef *
KeycodeCreate(xkb_atom_t name, int64_t value)
{
KeycodeDef *def = malloc(sizeof(*def));
if (!def)
return NULL;
def->common.type = STMT_KEYCODE;
def->common.next = NULL;
def->name = name;
def->value = value;
return def;
}
KeyAliasDef *
KeyAliasCreate(xkb_atom_t alias, xkb_atom_t real)
{
KeyAliasDef *def = malloc(sizeof(*def));
if (!def)
return NULL;
def->common.type = STMT_ALIAS;
def->common.next = NULL;
def->alias = alias;
def->real = real;
return def;
}
VModDef *
VModCreate(xkb_atom_t name, ExprDef *value)
{
VModDef *def = malloc(sizeof(*def));
if (!def)
return NULL;
def->common.type = STMT_VMOD;
def->common.next = NULL;
def->name = name;
def->value = value;
return def;
}
VarDef *
VarCreate(ExprDef *name, ExprDef *value)
{
VarDef *def = malloc(sizeof(*def));
if (!def)
return NULL;
def->common.type = STMT_VAR;
def->common.next = NULL;
def->name = name;
def->value = value;
return def;
}
VarDef *
BoolVarCreate(xkb_atom_t ident, bool set)
{
ExprDef *name, *value;
VarDef *def;
if (!(name = ExprCreateIdent(ident))) {
return NULL;
}
if (!(value = ExprCreateBoolean(set))) {
FreeStmt((ParseCommon *) name);
return NULL;
}
if (!(def = VarCreate(name, value))) {
FreeStmt((ParseCommon *) name);
FreeStmt((ParseCommon *) value);
return NULL;
}
return def;
}
InterpDef *
InterpCreate(xkb_keysym_t sym, ExprDef *match)
{
InterpDef *def = malloc(sizeof(*def));
if (!def)
return NULL;
def->common.type = STMT_INTERP;
def->common.next = NULL;
def->sym = sym;
def->match = match;
def->def = NULL;
return def;
}
KeyTypeDef *
KeyTypeCreate(xkb_atom_t name, VarDef *body)
{
KeyTypeDef *def = malloc(sizeof(*def));
if (!def)
return NULL;
def->common.type = STMT_TYPE;
def->common.next = NULL;
def->merge = MERGE_DEFAULT;
def->name = name;
def->body = body;
return def;
}
SymbolsDef *
SymbolsCreate(xkb_atom_t keyName, VarDef *symbols)
{
SymbolsDef *def = malloc(sizeof(*def));
if (!def)
return NULL;
def->common.type = STMT_SYMBOLS;
def->common.next = NULL;
def->merge = MERGE_DEFAULT;
def->keyName = keyName;
def->symbols = symbols;
return def;
}
GroupCompatDef *
GroupCompatCreate(unsigned group, ExprDef *val)
{
GroupCompatDef *def = malloc(sizeof(*def));
if (!def)
return NULL;
def->common.type = STMT_GROUP_COMPAT;
def->common.next = NULL;
def->merge = MERGE_DEFAULT;
def->group = group;
def->def = val;
return def;
}
ModMapDef *
ModMapCreate(xkb_atom_t modifier, ExprDef *keys)
{
ModMapDef *def = malloc(sizeof(*def));
if (!def)
return NULL;
def->common.type = STMT_MODMAP;
def->common.next = NULL;
def->merge = MERGE_DEFAULT;
def->modifier = modifier;
def->keys = keys;
return def;
}
LedMapDef *
LedMapCreate(xkb_atom_t name, VarDef *body)
{
LedMapDef *def = malloc(sizeof(*def));
if (!def)
return NULL;
def->common.type = STMT_LED_MAP;
def->common.next = NULL;
def->merge = MERGE_DEFAULT;
def->name = name;
def->body = body;
return def;
}
LedNameDef *
LedNameCreate(unsigned ndx, ExprDef *name, bool virtual)
{
LedNameDef *def = malloc(sizeof(*def));
if (!def)
return NULL;
def->common.type = STMT_LED_NAME;
def->common.next = NULL;
def->merge = MERGE_DEFAULT;
def->ndx = ndx;
def->name = name;
def->virtual = virtual;
return def;
}
static void
FreeInclude(IncludeStmt *incl);
IncludeStmt *
IncludeCreate(struct xkb_context *ctx, char *str, enum merge_mode merge)
{
IncludeStmt *incl, *first;
char *file, *map, *stmt, *tmp, *extra_data;
char nextop;
incl = first = NULL;
file = map = NULL;
tmp = str;
stmt = strdup_safe(str);
while (tmp && *tmp)
{
if (!ParseIncludeMap(&tmp, &file, &map, &nextop, &extra_data))
goto err;
/*
* Given an RMLVO (here layout) like 'us,,fr', the rules parser
* will give out something like 'pc+us+:2+fr:3+inet(evdev)'.
* We should just skip the ':2' in this case and leave it to the
* appropriate section to deal with the empty group.
*/
if (isempty(file)) {
free(file);
free(map);
free(extra_data);
continue;
}
if (first == NULL) {
first = incl = malloc(sizeof(*first));
} else {
incl->next_incl = malloc(sizeof(*first));
incl = incl->next_incl;
}
if (!incl)
break;
incl->common.type = STMT_INCLUDE;
incl->common.next = NULL;
incl->merge = merge;
incl->stmt = NULL;
incl->file = file;
incl->map = map;
incl->modifier = extra_data;
incl->next_incl = NULL;
if (nextop == '|')
merge = MERGE_AUGMENT;
else
merge = MERGE_OVERRIDE;
}
if (first)
first->stmt = stmt;
else
free(stmt);
return first;
err:
log_err(ctx, "Illegal include statement \"%s\"; Ignored\n", stmt);
FreeInclude(first);
free(stmt);
return NULL;
}
XkbFile *
XkbFileCreate(enum xkb_file_type type, char *name, ParseCommon *defs,
enum xkb_map_flags flags)
{
XkbFile *file;
file = calloc(1, sizeof(*file));
if (!file)
return NULL;
XkbEscapeMapName(name);
file->file_type = type;
file->name = name ? name : strdup("(unnamed)");
file->defs = defs;
file->flags = flags;
return file;
}
XkbFile *
XkbFileFromComponents(struct xkb_context *ctx,
const struct xkb_component_names *kkctgs)
{
char *const components[] = {
kkctgs->keycodes, kkctgs->types,
kkctgs->compat, kkctgs->symbols,
};
enum xkb_file_type type;
IncludeStmt *include = NULL;
XkbFile *file = NULL;
ParseCommon *defs = NULL;
for (type = FIRST_KEYMAP_FILE_TYPE; type <= LAST_KEYMAP_FILE_TYPE; type++) {
include = IncludeCreate(ctx, components[type], MERGE_DEFAULT);
if (!include)
goto err;
file = XkbFileCreate(type, NULL, (ParseCommon *) include, 0);
if (!file) {
FreeInclude(include);
goto err;
}
defs = AppendStmt(defs, &file->common);
}
file = XkbFileCreate(FILE_TYPE_KEYMAP, NULL, defs, 0);
if (!file)
goto err;
return file;
err:
FreeXkbFile((XkbFile *) defs);
return NULL;
}
static void
FreeExpr(ExprDef *expr)
{
if (!expr)
return;
switch (expr->expr.op) {
case EXPR_ACTION_LIST:
case EXPR_NEGATE:
case EXPR_UNARY_PLUS:
case EXPR_NOT:
case EXPR_INVERT:
FreeStmt((ParseCommon *) expr->unary.child);
break;
case EXPR_DIVIDE:
case EXPR_ADD:
case EXPR_SUBTRACT:
case EXPR_MULTIPLY:
case EXPR_ASSIGN:
FreeStmt((ParseCommon *) expr->binary.left);
FreeStmt((ParseCommon *) expr->binary.right);
break;
case EXPR_ACTION_DECL:
FreeStmt((ParseCommon *) expr->action.args);
break;
case EXPR_ARRAY_REF:
FreeStmt((ParseCommon *) expr->array_ref.entry);
break;
case EXPR_KEYSYM_LIST:
darray_free(expr->keysym_list.syms);
darray_free(expr->keysym_list.symsMapIndex);
darray_free(expr->keysym_list.symsNumEntries);
break;
default:
break;
}
}
static void
FreeInclude(IncludeStmt *incl)
{
IncludeStmt *next;
while (incl)
{
next = incl->next_incl;
free(incl->file);
free(incl->map);
free(incl->modifier);
free(incl->stmt);
free(incl);
incl = next;
}
}
void
FreeStmt(ParseCommon *stmt)
{
ParseCommon *next;
while (stmt)
{
next = stmt->next;
switch (stmt->type) {
case STMT_INCLUDE:
FreeInclude((IncludeStmt *) stmt);
/* stmt is already free'd here. */
stmt = NULL;
break;
case STMT_EXPR:
FreeExpr((ExprDef *) stmt);
break;
case STMT_VAR:
FreeStmt((ParseCommon *) ((VarDef *) stmt)->name);
FreeStmt((ParseCommon *) ((VarDef *) stmt)->value);
break;
case STMT_TYPE:
FreeStmt((ParseCommon *) ((KeyTypeDef *) stmt)->body);
break;
case STMT_INTERP:
FreeStmt((ParseCommon *) ((InterpDef *) stmt)->match);
FreeStmt((ParseCommon *) ((InterpDef *) stmt)->def);
break;
case STMT_VMOD:
FreeStmt((ParseCommon *) ((VModDef *) stmt)->value);
break;
case STMT_SYMBOLS:
FreeStmt((ParseCommon *) ((SymbolsDef *) stmt)->symbols);
break;
case STMT_MODMAP:
FreeStmt((ParseCommon *) ((ModMapDef *) stmt)->keys);
break;
case STMT_GROUP_COMPAT:
FreeStmt((ParseCommon *) ((GroupCompatDef *) stmt)->def);
break;
case STMT_LED_MAP:
FreeStmt((ParseCommon *) ((LedMapDef *) stmt)->body);
break;
case STMT_LED_NAME:
FreeStmt((ParseCommon *) ((LedNameDef *) stmt)->name);
break;
default:
break;
}
free(stmt);
stmt = next;
}
}
void
FreeXkbFile(XkbFile *file)
{
XkbFile *next;
while (file)
{
next = (XkbFile *) file->common.next;
switch (file->file_type) {
case FILE_TYPE_KEYMAP:
FreeXkbFile((XkbFile *) file->defs);
break;
case FILE_TYPE_TYPES:
case FILE_TYPE_COMPAT:
case FILE_TYPE_SYMBOLS:
case FILE_TYPE_KEYCODES:
case FILE_TYPE_GEOMETRY:
FreeStmt(file->defs);
break;
default:
break;
}
free(file->name);
free(file);
file = next;
}
}
static const char *xkb_file_type_strings[_FILE_TYPE_NUM_ENTRIES] = {
[FILE_TYPE_KEYCODES] = "xkb_keycodes",
[FILE_TYPE_TYPES] = "xkb_types",
[FILE_TYPE_COMPAT] = "xkb_compatibility",
[FILE_TYPE_SYMBOLS] = "xkb_symbols",
[FILE_TYPE_GEOMETRY] = "xkb_geometry",
[FILE_TYPE_KEYMAP] = "xkb_keymap",
[FILE_TYPE_RULES] = "rules",
};
const char *
xkb_file_type_to_string(enum xkb_file_type type)
{
if (type >= _FILE_TYPE_NUM_ENTRIES)
return "unknown";
return xkb_file_type_strings[type];
}
static const char *stmt_type_strings[_STMT_NUM_VALUES] = {
[STMT_UNKNOWN] = "unknown statement",
[STMT_INCLUDE] = "include statement",
[STMT_KEYCODE] = "key name definition",
[STMT_ALIAS] = "key alias definition",
[STMT_EXPR] = "expression",
[STMT_VAR] = "variable definition",
[STMT_TYPE] = "key type definition",
[STMT_INTERP] = "symbol interpretation definition",
[STMT_VMOD] = "virtual modifiers definition",
[STMT_SYMBOLS] = "key symbols definition",
[STMT_MODMAP] = "modifier map declaration",
[STMT_GROUP_COMPAT] = "group declaration",
[STMT_LED_MAP] = "indicator map declaration",
[STMT_LED_NAME] = "indicator name declaration",
};
const char *
stmt_type_to_string(enum stmt_type type)
{
if (type >= _STMT_NUM_VALUES)
return NULL;
return stmt_type_strings[type];
}
static const char *expr_op_type_strings[_EXPR_NUM_VALUES] = {
[EXPR_VALUE] = "literal",
[EXPR_IDENT] = "identifier",
[EXPR_ACTION_DECL] = "action declaration",
[EXPR_FIELD_REF] = "field reference",
[EXPR_ARRAY_REF] = "array reference",
[EXPR_KEYSYM_LIST] = "list of keysyms",
[EXPR_ACTION_LIST] = "list of actions",
[EXPR_ADD] = "addition",
[EXPR_SUBTRACT] = "subtraction",
[EXPR_MULTIPLY] = "multiplication",
[EXPR_DIVIDE] = "division",
[EXPR_ASSIGN] = "assignment",
[EXPR_NOT] = "logical negation",
[EXPR_NEGATE] = "arithmetic negation",
[EXPR_INVERT] = "bitwise inversion",
[EXPR_UNARY_PLUS] = "unary plus",
};
const char *
expr_op_type_to_string(enum expr_op_type type)
{
if (type >= _EXPR_NUM_VALUES)
return NULL;
return expr_op_type_strings[type];
}
static const char *expr_value_type_strings[_EXPR_TYPE_NUM_VALUES] = {
[EXPR_TYPE_UNKNOWN] = "unknown",
[EXPR_TYPE_BOOLEAN] = "boolean",
[EXPR_TYPE_INT] = "int",
[EXPR_TYPE_FLOAT] = "float",
[EXPR_TYPE_STRING] = "string",
[EXPR_TYPE_ACTION] = "action",
[EXPR_TYPE_KEYNAME] = "keyname",
[EXPR_TYPE_SYMBOLS] = "symbols",
};
const char *
expr_value_type_to_string(enum expr_value_type type)
{
if (type >= _EXPR_TYPE_NUM_VALUES)
return NULL;
return expr_value_type_strings[type];
}

View File

@ -1,125 +0,0 @@
/************************************************************
* Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting
* documentation, and that the name of Silicon Graphics not be
* used in advertising or publicity pertaining to distribution
* of the software without specific prior written permission.
* Silicon Graphics makes no representation about the suitability
* of this software for any purpose. It is provided "as is"
* without any express or implied warranty.
*
* SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
* GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
********************************************************/
#ifndef XKBCOMP_AST_BUILD_H
#define XKBCOMP_AST_BUILD_H
ParseCommon *
AppendStmt(ParseCommon *to, ParseCommon *append);
ExprDef *
ExprCreateString(xkb_atom_t str);
ExprDef *
ExprCreateInteger(int ival);
ExprDef *
ExprCreateFloat(void);
ExprDef *
ExprCreateBoolean(bool set);
ExprDef *
ExprCreateKeyName(xkb_atom_t key_name);
ExprDef *
ExprCreateIdent(xkb_atom_t ident);
ExprDef *
ExprCreateUnary(enum expr_op_type op, enum expr_value_type type,
ExprDef *child);
ExprDef *
ExprCreateBinary(enum expr_op_type op, ExprDef *left, ExprDef *right);
ExprDef *
ExprCreateFieldRef(xkb_atom_t element, xkb_atom_t field);
ExprDef *
ExprCreateArrayRef(xkb_atom_t element, xkb_atom_t field, ExprDef *entry);
ExprDef *
ExprCreateAction(xkb_atom_t name, ExprDef *args);
ExprDef *
ExprCreateMultiKeysymList(ExprDef *list);
ExprDef *
ExprCreateKeysymList(xkb_keysym_t sym);
ExprDef *
ExprAppendMultiKeysymList(ExprDef *list, ExprDef *append);
ExprDef *
ExprAppendKeysymList(ExprDef *list, xkb_keysym_t sym);
KeycodeDef *
KeycodeCreate(xkb_atom_t name, int64_t value);
KeyAliasDef *
KeyAliasCreate(xkb_atom_t alias, xkb_atom_t real);
VModDef *
VModCreate(xkb_atom_t name, ExprDef *value);
VarDef *
VarCreate(ExprDef *name, ExprDef *value);
VarDef *
BoolVarCreate(xkb_atom_t ident, bool set);
InterpDef *
InterpCreate(xkb_keysym_t sym, ExprDef *match);
KeyTypeDef *
KeyTypeCreate(xkb_atom_t name, VarDef *body);
SymbolsDef *
SymbolsCreate(xkb_atom_t keyName, VarDef *symbols);
GroupCompatDef *
GroupCompatCreate(unsigned group, ExprDef *def);
ModMapDef *
ModMapCreate(xkb_atom_t modifier, ExprDef *keys);
LedMapDef *
LedMapCreate(xkb_atom_t name, VarDef *body);
LedNameDef *
LedNameCreate(unsigned ndx, ExprDef *name, bool virtual);
IncludeStmt *
IncludeCreate(struct xkb_context *ctx, char *str, enum merge_mode merge);
XkbFile *
XkbFileCreate(enum xkb_file_type type, char *name, ParseCommon *defs,
enum xkb_map_flags flags);
void
FreeStmt(ParseCommon *stmt);
#endif

View File

@ -1,353 +0,0 @@
/************************************************************
* Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting
* documentation, and that the name of Silicon Graphics not be
* used in advertising or publicity pertaining to distribution
* of the software without specific prior written permission.
* Silicon Graphics makes no representation about the suitability
* of this software for any purpose. It is provided "as is"
* without any express or implied warranty.
*
* SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
* GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
********************************************************/
/*
* Copyright © 2012 Ran Benita <ran234@gmail.com>
*
* 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 (including the next
* paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
*/
#ifndef XKBCOMP_AST_H
#define XKBCOMP_AST_H
enum xkb_file_type {
/* Component files, by order of compilation. */
FILE_TYPE_KEYCODES = 0,
FILE_TYPE_TYPES = 1,
FILE_TYPE_COMPAT = 2,
FILE_TYPE_SYMBOLS = 3,
/* Geometry is not compiled any more. */
FILE_TYPE_GEOMETRY = 4,
/* A top level file which includes the above files. */
FILE_TYPE_KEYMAP,
/* File types which must be found in a keymap file. */
#define FIRST_KEYMAP_FILE_TYPE FILE_TYPE_KEYCODES
#define LAST_KEYMAP_FILE_TYPE FILE_TYPE_SYMBOLS
/* This one doesn't mix with the others, but useful here as well. */
FILE_TYPE_RULES,
_FILE_TYPE_NUM_ENTRIES
};
enum stmt_type {
STMT_UNKNOWN = 0,
STMT_INCLUDE,
STMT_KEYCODE,
STMT_ALIAS,
STMT_EXPR,
STMT_VAR,
STMT_TYPE,
STMT_INTERP,
STMT_VMOD,
STMT_SYMBOLS,
STMT_MODMAP,
STMT_GROUP_COMPAT,
STMT_LED_MAP,
STMT_LED_NAME,
_STMT_NUM_VALUES
};
enum expr_value_type {
EXPR_TYPE_UNKNOWN = 0,
EXPR_TYPE_BOOLEAN,
EXPR_TYPE_INT,
EXPR_TYPE_FLOAT,
EXPR_TYPE_STRING,
EXPR_TYPE_ACTION,
EXPR_TYPE_KEYNAME,
EXPR_TYPE_SYMBOLS,
_EXPR_TYPE_NUM_VALUES
};
enum expr_op_type {
EXPR_VALUE,
EXPR_IDENT,
EXPR_ACTION_DECL,
EXPR_FIELD_REF,
EXPR_ARRAY_REF,
EXPR_KEYSYM_LIST,
EXPR_ACTION_LIST,
EXPR_ADD,
EXPR_SUBTRACT,
EXPR_MULTIPLY,
EXPR_DIVIDE,
EXPR_ASSIGN,
EXPR_NOT,
EXPR_NEGATE,
EXPR_INVERT,
EXPR_UNARY_PLUS,
_EXPR_NUM_VALUES
};
enum merge_mode {
MERGE_DEFAULT,
MERGE_AUGMENT,
MERGE_OVERRIDE,
MERGE_REPLACE,
};
const char *
xkb_file_type_to_string(enum xkb_file_type type);
const char *
stmt_type_to_string(enum stmt_type type);
const char *
expr_op_type_to_string(enum expr_op_type type);
const char *
expr_value_type_to_string(enum expr_value_type type);
typedef struct _ParseCommon {
struct _ParseCommon *next;
enum stmt_type type;
} ParseCommon;
typedef struct _IncludeStmt {
ParseCommon common;
enum merge_mode merge;
char *stmt;
char *file;
char *map;
char *modifier;
struct _IncludeStmt *next_incl;
} IncludeStmt;
typedef struct {
ParseCommon common;
enum expr_op_type op;
enum expr_value_type value_type;
} ExprCommon;
typedef union ExprDef ExprDef;
typedef struct {
ExprCommon expr;
xkb_atom_t ident;
} ExprIdent;
typedef struct {
ExprCommon expr;
xkb_atom_t str;
} ExprString;
typedef struct {
ExprCommon expr;
bool set;
} ExprBoolean;
typedef struct {
ExprCommon expr;
int ival;
} ExprInteger;
typedef struct {
ExprCommon expr;
/* We don't support floats, but we still represnt them in the AST, in
* order to provide proper error messages. */
} ExprFloat;
typedef struct {
ExprCommon expr;
xkb_atom_t key_name;
} ExprKeyName;
typedef struct {
ExprCommon expr;
ExprDef *left;
ExprDef *right;
} ExprBinary;
typedef struct {
ExprCommon expr;
ExprDef *child;
} ExprUnary;
typedef struct {
ExprCommon expr;
xkb_atom_t element;
xkb_atom_t field;
} ExprFieldRef;
typedef struct {
ExprCommon expr;
xkb_atom_t element;
xkb_atom_t field;
ExprDef *entry;
} ExprArrayRef;
typedef struct {
ExprCommon expr;
xkb_atom_t name;
ExprDef *args;
} ExprAction;
typedef struct {
ExprCommon expr;
darray(xkb_keysym_t) syms;
darray(unsigned int) symsMapIndex;
darray(unsigned int) symsNumEntries;
} ExprKeysymList;
union ExprDef {
ParseCommon common;
/* Maybe someday we can use C11 anonymous struct for ExprCommon here. */
ExprCommon expr;
ExprIdent ident;
ExprString string;
ExprBoolean boolean;
ExprInteger integer;
ExprKeyName key_name;
ExprBinary binary;
ExprUnary unary;
ExprFieldRef field_ref;
ExprArrayRef array_ref;
ExprAction action;
ExprKeysymList keysym_list;
};
typedef struct {
ParseCommon common;
enum merge_mode merge;
ExprDef *name;
ExprDef *value;
} VarDef;
typedef struct {
ParseCommon common;
enum merge_mode merge;
xkb_atom_t name;
ExprDef *value;
} VModDef;
typedef struct {
ParseCommon common;
enum merge_mode merge;
xkb_atom_t name;
int64_t value;
} KeycodeDef;
typedef struct {
ParseCommon common;
enum merge_mode merge;
xkb_atom_t alias;
xkb_atom_t real;
} KeyAliasDef;
typedef struct {
ParseCommon common;
enum merge_mode merge;
xkb_atom_t name;
VarDef *body;
} KeyTypeDef;
typedef struct {
ParseCommon common;
enum merge_mode merge;
xkb_atom_t keyName;
VarDef *symbols;
} SymbolsDef;
typedef struct {
ParseCommon common;
enum merge_mode merge;
xkb_atom_t modifier;
ExprDef *keys;
} ModMapDef;
typedef struct {
ParseCommon common;
enum merge_mode merge;
unsigned group;
ExprDef *def;
} GroupCompatDef;
typedef struct {
ParseCommon common;
enum merge_mode merge;
xkb_keysym_t sym;
ExprDef *match;
VarDef *def;
} InterpDef;
typedef struct {
ParseCommon common;
enum merge_mode merge;
unsigned ndx;
ExprDef *name;
bool virtual;
} LedNameDef;
typedef struct {
ParseCommon common;
enum merge_mode merge;
xkb_atom_t name;
VarDef *body;
} LedMapDef;
enum xkb_map_flags {
MAP_IS_DEFAULT = (1 << 0),
MAP_IS_PARTIAL = (1 << 1),
MAP_IS_HIDDEN = (1 << 2),
MAP_HAS_ALPHANUMERIC = (1 << 3),
MAP_HAS_MODIFIER = (1 << 4),
MAP_HAS_KEYPAD = (1 << 5),
MAP_HAS_FN = (1 << 6),
MAP_IS_ALTGR = (1 << 7),
};
typedef struct {
ParseCommon common;
enum xkb_file_type file_type;
char *name;
ParseCommon *defs;
enum xkb_map_flags flags;
} XkbFile;
#endif

View File

@ -1,932 +0,0 @@
/************************************************************
* Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting
* documentation, and that the name of Silicon Graphics not be
* used in advertising or publicity pertaining to distribution
* of the software without specific prior written permission.
* Silicon Graphics makes no representation about the suitability
* of this software for any purpose. It is provided "as is"
* without any express or implied warranty.
*
* SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
* GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
********************************************************/
/*
* Copyright © 2012 Ran Benita <ran234@gmail.com>
*
* 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 (including the next
* paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
*/
#include "xkbcomp-priv.h"
#include "text.h"
#include "expr.h"
#include "action.h"
#include "vmod.h"
#include "include.h"
enum si_field {
SI_FIELD_VIRTUAL_MOD = (1 << 0),
SI_FIELD_ACTION = (1 << 1),
SI_FIELD_AUTO_REPEAT = (1 << 2),
SI_FIELD_LEVEL_ONE_ONLY = (1 << 3),
};
typedef struct {
enum si_field defined;
enum merge_mode merge;
struct xkb_sym_interpret interp;
} SymInterpInfo;
enum led_field {
LED_FIELD_MODS = (1 << 0),
LED_FIELD_GROUPS = (1 << 1),
LED_FIELD_CTRLS = (1 << 2),
};
typedef struct {
enum led_field defined;
enum merge_mode merge;
struct xkb_led led;
} LedInfo;
typedef struct {
char *name;
int errorCount;
SymInterpInfo default_interp;
darray(SymInterpInfo) interps;
LedInfo default_led;
LedInfo leds[XKB_MAX_LEDS];
unsigned int num_leds;
ActionsInfo *actions;
struct xkb_mod_set mods;
struct xkb_context *ctx;
} CompatInfo;
static const char *
siText(SymInterpInfo *si, CompatInfo *info)
{
char *buf = xkb_context_get_buffer(info->ctx, 128);
if (si == &info->default_interp)
return "default";
snprintf(buf, 128, "%s+%s(%s)",
KeysymText(info->ctx, si->interp.sym),
SIMatchText(si->interp.match),
ModMaskText(info->ctx, &info->mods, si->interp.mods));
return buf;
}
static inline bool
ReportSINotArray(CompatInfo *info, SymInterpInfo *si, const char *field)
{
return ReportNotArray(info->ctx, "symbol interpretation", field,
siText(si, info));
}
static inline bool
ReportSIBadType(CompatInfo *info, SymInterpInfo *si, const char *field,
const char *wanted)
{
return ReportBadType(info->ctx, "symbol interpretation", field,
siText(si, info), wanted);
}
static inline bool
ReportLedBadType(CompatInfo *info, LedInfo *ledi, const char *field,
const char *wanted)
{
return ReportBadType(info->ctx, "indicator map", field,
xkb_atom_text(info->ctx, ledi->led.name),
wanted);
}
static inline bool
ReportLedNotArray(CompatInfo *info, LedInfo *ledi, const char *field)
{
return ReportNotArray(info->ctx, "indicator map", field,
xkb_atom_text(info->ctx, ledi->led.name));
}
static void
InitCompatInfo(CompatInfo *info, struct xkb_context *ctx,
ActionsInfo *actions, const struct xkb_mod_set *mods)
{
memset(info, 0, sizeof(*info));
info->ctx = ctx;
info->actions = actions;
info->mods = *mods;
info->default_interp.merge = MERGE_OVERRIDE;
info->default_interp.interp.virtual_mod = XKB_MOD_INVALID;
info->default_led.merge = MERGE_OVERRIDE;
}
static void
ClearCompatInfo(CompatInfo *info)
{
free(info->name);
darray_free(info->interps);
}
static SymInterpInfo *
FindMatchingInterp(CompatInfo *info, SymInterpInfo *new)
{
SymInterpInfo *old;
darray_foreach(old, info->interps)
if (old->interp.sym == new->interp.sym &&
old->interp.mods == new->interp.mods &&
old->interp.match == new->interp.match)
return old;
return NULL;
}
static bool
UseNewInterpField(enum si_field field, SymInterpInfo *old, SymInterpInfo *new,
bool report, enum si_field *collide)
{
if (!(old->defined & field))
return true;
if (new->defined & field) {
if (report)
*collide |= field;
if (new->merge != MERGE_AUGMENT)
return true;
}
return false;
}
static bool
AddInterp(CompatInfo *info, SymInterpInfo *new, bool same_file)
{
SymInterpInfo *old = FindMatchingInterp(info, new);
if (old) {
const int verbosity = xkb_context_get_log_verbosity(info->ctx);
const bool report = (same_file && verbosity > 0) || verbosity > 9;
enum si_field collide = 0;
if (new->merge == MERGE_REPLACE) {
if (report)
log_warn(info->ctx,
"Multiple definitions for \"%s\"; "
"Earlier interpretation ignored\n",
siText(new, info));
*old = *new;
return true;
}
if (UseNewInterpField(SI_FIELD_VIRTUAL_MOD, old, new, report,
&collide)) {
old->interp.virtual_mod = new->interp.virtual_mod;
old->defined |= SI_FIELD_VIRTUAL_MOD;
}
if (UseNewInterpField(SI_FIELD_ACTION, old, new, report,
&collide)) {
old->interp.action = new->interp.action;
old->defined |= SI_FIELD_ACTION;
}
if (UseNewInterpField(SI_FIELD_AUTO_REPEAT, old, new, report,
&collide)) {
old->interp.repeat = new->interp.repeat;
old->defined |= SI_FIELD_AUTO_REPEAT;
}
if (UseNewInterpField(SI_FIELD_LEVEL_ONE_ONLY, old, new, report,
&collide)) {
old->interp.level_one_only = new->interp.level_one_only;
old->defined |= SI_FIELD_LEVEL_ONE_ONLY;
}
if (collide) {
log_warn(info->ctx,
"Multiple interpretations of \"%s\"; "
"Using %s definition for duplicate fields\n",
siText(new, info),
(new->merge != MERGE_AUGMENT ? "last" : "first"));
}
return true;
}
darray_append(info->interps, *new);
return true;
}
/***====================================================================***/
static bool
ResolveStateAndPredicate(ExprDef *expr, enum xkb_match_operation *pred_rtrn,
xkb_mod_mask_t *mods_rtrn, CompatInfo *info)
{
if (expr == NULL) {
*pred_rtrn = MATCH_ANY_OR_NONE;
*mods_rtrn = MOD_REAL_MASK_ALL;
return true;
}
*pred_rtrn = MATCH_EXACTLY;
if (expr->expr.op == EXPR_ACTION_DECL) {
const char *pred_txt = xkb_atom_text(info->ctx, expr->action.name);
if (!LookupString(symInterpretMatchMaskNames, pred_txt, pred_rtrn) ||
!expr->action.args) {
log_err(info->ctx,
"Illegal modifier predicate \"%s\"; Ignored\n", pred_txt);
return false;
}
expr = expr->action.args;
}
else if (expr->expr.op == EXPR_IDENT) {
const char *pred_txt = xkb_atom_text(info->ctx, expr->ident.ident);
if (pred_txt && istreq(pred_txt, "any")) {
*pred_rtrn = MATCH_ANY;
*mods_rtrn = MOD_REAL_MASK_ALL;
return true;
}
}
return ExprResolveModMask(info->ctx, expr, MOD_REAL, &info->mods,
mods_rtrn);
}
/***====================================================================***/
static bool
UseNewLEDField(enum led_field field, LedInfo *old, LedInfo *new,
bool report, enum led_field *collide)
{
if (!(old->defined & field))
return true;
if (new->defined & field) {
if (report)
*collide |= field;
if (new->merge != MERGE_AUGMENT)
return true;
}
return false;
}
static bool
AddLedMap(CompatInfo *info, LedInfo *new, bool same_file)
{
enum led_field collide;
const int verbosity = xkb_context_get_log_verbosity(info->ctx);
const bool report = (same_file && verbosity > 0) || verbosity > 9;
for (xkb_led_index_t i = 0; i < info->num_leds; i++) {
LedInfo *old = &info->leds[i];
if (old->led.name != new->led.name)
continue;
if (old->led.mods.mods == new->led.mods.mods &&
old->led.groups == new->led.groups &&
old->led.ctrls == new->led.ctrls &&
old->led.which_mods == new->led.which_mods &&
old->led.which_groups == new->led.which_groups) {
old->defined |= new->defined;
return true;
}
if (new->merge == MERGE_REPLACE) {
if (report)
log_warn(info->ctx,
"Map for indicator %s redefined; "
"Earlier definition ignored\n",
xkb_atom_text(info->ctx, old->led.name));
*old = *new;
return true;
}
collide = 0;
if (UseNewLEDField(LED_FIELD_MODS, old, new, report, &collide)) {
old->led.which_mods = new->led.which_mods;
old->led.mods = new->led.mods;
old->defined |= LED_FIELD_MODS;
}
if (UseNewLEDField(LED_FIELD_GROUPS, old, new, report, &collide)) {
old->led.which_groups = new->led.which_groups;
old->led.groups = new->led.groups;
old->defined |= LED_FIELD_GROUPS;
}
if (UseNewLEDField(LED_FIELD_CTRLS, old, new, report, &collide)) {
old->led.ctrls = new->led.ctrls;
old->defined |= LED_FIELD_CTRLS;
}
if (collide) {
log_warn(info->ctx,
"Map for indicator %s redefined; "
"Using %s definition for duplicate fields\n",
xkb_atom_text(info->ctx, old->led.name),
(new->merge == MERGE_AUGMENT ? "first" : "last"));
}
return true;
}
if (info->num_leds >= XKB_MAX_LEDS) {
log_err(info->ctx,
"Too many LEDs defined (maximum %d)\n",
XKB_MAX_LEDS);
return false;
}
info->leds[info->num_leds++] = *new;
return true;
}
static void
MergeIncludedCompatMaps(CompatInfo *into, CompatInfo *from,
enum merge_mode merge)
{
if (from->errorCount > 0) {
into->errorCount += from->errorCount;
return;
}
into->mods = from->mods;
if (into->name == NULL) {
into->name = from->name;
from->name = NULL;
}
if (darray_empty(into->interps)) {
into->interps = from->interps;
darray_init(from->interps);
}
else {
SymInterpInfo *si;
darray_foreach(si, from->interps) {
si->merge = (merge == MERGE_DEFAULT ? si->merge : merge);
if (!AddInterp(into, si, false))
into->errorCount++;
}
}
if (into->num_leds == 0) {
memcpy(into->leds, from->leds, sizeof(*from->leds) * from->num_leds);
into->num_leds = from->num_leds;
from->num_leds = 0;
}
else {
for (xkb_led_index_t i = 0; i < from->num_leds; i++) {
LedInfo *ledi = &from->leds[i];
ledi->merge = (merge == MERGE_DEFAULT ? ledi->merge : merge);
if (!AddLedMap(into, ledi, false))
into->errorCount++;
}
}
}
static void
HandleCompatMapFile(CompatInfo *info, XkbFile *file, enum merge_mode merge);
static bool
HandleIncludeCompatMap(CompatInfo *info, IncludeStmt *include)
{
CompatInfo included;
InitCompatInfo(&included, info->ctx, info->actions, &info->mods);
included.name = include->stmt;
include->stmt = NULL;
for (IncludeStmt *stmt = include; stmt; stmt = stmt->next_incl) {
CompatInfo next_incl;
XkbFile *file;
file = ProcessIncludeFile(info->ctx, stmt, FILE_TYPE_COMPAT);
if (!file) {
info->errorCount += 10;
ClearCompatInfo(&included);
return false;
}
InitCompatInfo(&next_incl, info->ctx, info->actions, &included.mods);
next_incl.default_interp = info->default_interp;
next_incl.default_interp.merge = stmt->merge;
next_incl.default_led = info->default_led;
next_incl.default_led.merge = stmt->merge;
HandleCompatMapFile(&next_incl, file, MERGE_OVERRIDE);
MergeIncludedCompatMaps(&included, &next_incl, stmt->merge);
ClearCompatInfo(&next_incl);
FreeXkbFile(file);
}
MergeIncludedCompatMaps(info, &included, include->merge);
ClearCompatInfo(&included);
return (info->errorCount == 0);
}
static bool
SetInterpField(CompatInfo *info, SymInterpInfo *si, const char *field,
ExprDef *arrayNdx, ExprDef *value)
{
xkb_mod_index_t ndx;
if (istreq(field, "action")) {
if (arrayNdx)
return ReportSINotArray(info, si, field);
if (!HandleActionDef(info->ctx, info->actions, &info->mods,
value, &si->interp.action))
return false;
si->defined |= SI_FIELD_ACTION;
}
else if (istreq(field, "virtualmodifier") ||
istreq(field, "virtualmod")) {
if (arrayNdx)
return ReportSINotArray(info, si, field);
if (!ExprResolveMod(info->ctx, value, MOD_VIRT, &info->mods, &ndx))
return ReportSIBadType(info, si, field, "virtual modifier");
si->interp.virtual_mod = ndx;
si->defined |= SI_FIELD_VIRTUAL_MOD;
}
else if (istreq(field, "repeat")) {
bool set;
if (arrayNdx)
return ReportSINotArray(info, si, field);
if (!ExprResolveBoolean(info->ctx, value, &set))
return ReportSIBadType(info, si, field, "boolean");
si->interp.repeat = set;
si->defined |= SI_FIELD_AUTO_REPEAT;
}
else if (istreq(field, "locking")) {
log_dbg(info->ctx,
"The \"locking\" field in symbol interpretation is unsupported; "
"Ignored\n");
}
else if (istreq(field, "usemodmap") ||
istreq(field, "usemodmapmods")) {
unsigned int val;
if (arrayNdx)
return ReportSINotArray(info, si, field);
if (!ExprResolveEnum(info->ctx, value, &val, useModMapValueNames))
return ReportSIBadType(info, si, field, "level specification");
si->interp.level_one_only = val;
si->defined |= SI_FIELD_LEVEL_ONE_ONLY;
}
else {
return ReportBadField(info->ctx, "symbol interpretation", field,
siText(si, info));
}
return true;
}
static bool
SetLedMapField(CompatInfo *info, LedInfo *ledi, const char *field,
ExprDef *arrayNdx, ExprDef *value)
{
bool ok = true;
if (istreq(field, "modifiers") || istreq(field, "mods")) {
if (arrayNdx)
return ReportLedNotArray(info, ledi, field);
if (!ExprResolveModMask(info->ctx, value, MOD_BOTH,
&info->mods, &ledi->led.mods.mods))
return ReportLedBadType(info, ledi, field, "modifier mask");
ledi->defined |= LED_FIELD_MODS;
}
else if (istreq(field, "groups")) {
unsigned int mask;
if (arrayNdx)
return ReportLedNotArray(info, ledi, field);
if (!ExprResolveMask(info->ctx, value, &mask, groupMaskNames))
return ReportLedBadType(info, ledi, field, "group mask");
ledi->led.groups = mask;
ledi->defined |= LED_FIELD_GROUPS;
}
else if (istreq(field, "controls") || istreq(field, "ctrls")) {
unsigned int mask;
if (arrayNdx)
return ReportLedNotArray(info, ledi, field);
if (!ExprResolveMask(info->ctx, value, &mask, ctrlMaskNames))
return ReportLedBadType(info, ledi, field, "controls mask");
ledi->led.ctrls = mask;
ledi->defined |= LED_FIELD_CTRLS;
}
else if (istreq(field, "allowexplicit")) {
log_dbg(info->ctx,
"The \"allowExplicit\" field in indicator statements is unsupported; "
"Ignored\n");
}
else if (istreq(field, "whichmodstate") ||
istreq(field, "whichmodifierstate")) {
unsigned int mask;
if (arrayNdx)
return ReportLedNotArray(info, ledi, field);
if (!ExprResolveMask(info->ctx, value, &mask,
modComponentMaskNames))
return ReportLedBadType(info, ledi, field,
"mask of modifier state components");
ledi->led.which_mods = mask;
}
else if (istreq(field, "whichgroupstate")) {
unsigned mask;
if (arrayNdx)
return ReportLedNotArray(info, ledi, field);
if (!ExprResolveMask(info->ctx, value, &mask,
groupComponentMaskNames))
return ReportLedBadType(info, ledi, field,
"mask of group state components");
ledi->led.which_groups = mask;
}
else if (istreq(field, "driveskbd") ||
istreq(field, "driveskeyboard") ||
istreq(field, "leddriveskbd") ||
istreq(field, "leddriveskeyboard") ||
istreq(field, "indicatordriveskbd") ||
istreq(field, "indicatordriveskeyboard")) {
log_dbg(info->ctx,
"The \"%s\" field in indicator statements is unsupported; "
"Ignored\n", field);
}
else if (istreq(field, "index")) {
/* Users should see this, it might cause unexpected behavior. */
log_err(info->ctx,
"The \"index\" field in indicator statements is unsupported; "
"Ignored\n");
}
else {
log_err(info->ctx,
"Unknown field %s in map for %s indicator; "
"Definition ignored\n",
field, xkb_atom_text(info->ctx, ledi->led.name));
ok = false;
}
return ok;
}
static bool
HandleGlobalVar(CompatInfo *info, VarDef *stmt)
{
const char *elem, *field;
ExprDef *ndx;
bool ret;
if (!ExprResolveLhs(info->ctx, stmt->name, &elem, &field, &ndx))
ret = false;
else if (elem && istreq(elem, "interpret"))
ret = SetInterpField(info, &info->default_interp, field, ndx,
stmt->value);
else if (elem && istreq(elem, "indicator"))
ret = SetLedMapField(info, &info->default_led, field, ndx,
stmt->value);
else
ret = SetActionField(info->ctx, info->actions, &info->mods,
elem, field, ndx, stmt->value);
return ret;
}
static bool
HandleInterpBody(CompatInfo *info, VarDef *def, SymInterpInfo *si)
{
bool ok = true;
const char *elem, *field;
ExprDef *arrayNdx;
for (; def; def = (VarDef *) def->common.next) {
if (def->name && def->name->expr.op == EXPR_FIELD_REF) {
log_err(info->ctx,
"Cannot set a global default value from within an interpret statement; "
"Move statements to the global file scope\n");
ok = false;
continue;
}
ok = ExprResolveLhs(info->ctx, def->name, &elem, &field, &arrayNdx);
if (!ok)
continue;
ok = SetInterpField(info, si, field, arrayNdx, def->value);
}
return ok;
}
static bool
HandleInterpDef(CompatInfo *info, InterpDef *def, enum merge_mode merge)
{
enum xkb_match_operation pred;
xkb_mod_mask_t mods;
SymInterpInfo si;
if (!ResolveStateAndPredicate(def->match, &pred, &mods, info)) {
log_err(info->ctx,
"Couldn't determine matching modifiers; "
"Symbol interpretation ignored\n");
return false;
}
si = info->default_interp;
si.merge = merge = (def->merge == MERGE_DEFAULT ? merge : def->merge);
si.interp.sym = def->sym;
si.interp.match = pred;
si.interp.mods = mods;
if (!HandleInterpBody(info, def->def, &si)) {
info->errorCount++;
return false;
}
if (!AddInterp(info, &si, true)) {
info->errorCount++;
return false;
}
return true;
}
static bool
HandleLedMapDef(CompatInfo *info, LedMapDef *def, enum merge_mode merge)
{
LedInfo ledi;
VarDef *var;
bool ok;
if (def->merge != MERGE_DEFAULT)
merge = def->merge;
ledi = info->default_led;
ledi.merge = merge;
ledi.led.name = def->name;
ok = true;
for (var = def->body; var != NULL; var = (VarDef *) var->common.next) {
const char *elem, *field;
ExprDef *arrayNdx;
if (!ExprResolveLhs(info->ctx, var->name, &elem, &field, &arrayNdx)) {
ok = false;
continue;
}
if (elem) {
log_err(info->ctx,
"Cannot set defaults for \"%s\" element in indicator map; "
"Assignment to %s.%s ignored\n", elem, elem, field);
ok = false;
}
else {
ok = SetLedMapField(info, &ledi, field, arrayNdx, var->value) && ok;
}
}
if (ok)
return AddLedMap(info, &ledi, true);
return false;
}
static void
HandleCompatMapFile(CompatInfo *info, XkbFile *file, enum merge_mode merge)
{
bool ok;
merge = (merge == MERGE_DEFAULT ? MERGE_AUGMENT : merge);
free(info->name);
info->name = strdup_safe(file->name);
for (ParseCommon *stmt = file->defs; stmt; stmt = stmt->next) {
switch (stmt->type) {
case STMT_INCLUDE:
ok = HandleIncludeCompatMap(info, (IncludeStmt *) stmt);
break;
case STMT_INTERP:
ok = HandleInterpDef(info, (InterpDef *) stmt, merge);
break;
case STMT_GROUP_COMPAT:
log_dbg(info->ctx,
"The \"group\" statement in compat is unsupported; "
"Ignored\n");
ok = true;
break;
case STMT_LED_MAP:
ok = HandleLedMapDef(info, (LedMapDef *) stmt, merge);
break;
case STMT_VAR:
ok = HandleGlobalVar(info, (VarDef *) stmt);
break;
case STMT_VMOD:
ok = HandleVModDef(info->ctx, &info->mods, (VModDef *) stmt, merge);
break;
default:
log_err(info->ctx,
"Compat files may not include other types; "
"Ignoring %s\n", stmt_type_to_string(stmt->type));
ok = false;
break;
}
if (!ok)
info->errorCount++;
if (info->errorCount > 10) {
log_err(info->ctx,
"Abandoning compatibility map \"%s\"\n", file->name);
break;
}
}
}
/* Temporary struct for CopyInterps. */
struct collect {
darray(struct xkb_sym_interpret) sym_interprets;
};
static void
CopyInterps(CompatInfo *info, bool needSymbol, enum xkb_match_operation pred,
struct collect *collect)
{
SymInterpInfo *si;
darray_foreach(si, info->interps)
if (si->interp.match == pred &&
(si->interp.sym != XKB_KEY_NoSymbol) == needSymbol)
darray_append(collect->sym_interprets, si->interp);
}
static void
CopyLedMapDefsToKeymap(struct xkb_keymap *keymap, CompatInfo *info)
{
for (xkb_led_index_t idx = 0; idx < info->num_leds; idx++) {
LedInfo *ledi = &info->leds[idx];
xkb_led_index_t i;
struct xkb_led *led;
/*
* Find the LED with the given name, if it was already declared
* in keycodes.
*/
xkb_leds_enumerate(i, led, keymap)
if (led->name == ledi->led.name)
break;
/* Not previously declared; create it with next free index. */
if (i >= keymap->num_leds) {
log_dbg(keymap->ctx,
"Indicator name \"%s\" was not declared in the keycodes section; "
"Adding new indicator\n",
xkb_atom_text(keymap->ctx, ledi->led.name));
xkb_leds_enumerate(i, led, keymap)
if (led->name == XKB_ATOM_NONE)
break;
if (i >= keymap->num_leds) {
/* Not place to put it; ignore. */
if (i >= XKB_MAX_LEDS) {
log_err(keymap->ctx,
"Too many indicators (maximum is %d); "
"Indicator name \"%s\" ignored\n",
XKB_MAX_LEDS,
xkb_atom_text(keymap->ctx, ledi->led.name));
continue;
}
/* Add a new LED. */
led = &keymap->leds[keymap->num_leds++];
}
}
*led = ledi->led;
if (led->groups != 0 && led->which_groups == 0)
led->which_groups = XKB_STATE_LAYOUT_EFFECTIVE;
if (led->mods.mods != 0 && led->which_mods == 0)
led->which_mods = XKB_STATE_MODS_EFFECTIVE;
}
}
static bool
CopyCompatToKeymap(struct xkb_keymap *keymap, CompatInfo *info)
{
keymap->compat_section_name = strdup_safe(info->name);
XkbEscapeMapName(keymap->compat_section_name);
keymap->mods = info->mods;
if (!darray_empty(info->interps)) {
struct collect collect;
darray_init(collect.sym_interprets);
/* Most specific to least specific. */
CopyInterps(info, true, MATCH_EXACTLY, &collect);
CopyInterps(info, true, MATCH_ALL, &collect);
CopyInterps(info, true, MATCH_NONE, &collect);
CopyInterps(info, true, MATCH_ANY, &collect);
CopyInterps(info, true, MATCH_ANY_OR_NONE, &collect);
CopyInterps(info, false, MATCH_EXACTLY, &collect);
CopyInterps(info, false, MATCH_ALL, &collect);
CopyInterps(info, false, MATCH_NONE, &collect);
CopyInterps(info, false, MATCH_ANY, &collect);
CopyInterps(info, false, MATCH_ANY_OR_NONE, &collect);
darray_steal(collect.sym_interprets,
&keymap->sym_interprets, &keymap->num_sym_interprets);
}
CopyLedMapDefsToKeymap(keymap, info);
return true;
}
bool
CompileCompatMap(XkbFile *file, struct xkb_keymap *keymap,
enum merge_mode merge)
{
CompatInfo info;
ActionsInfo *actions;
actions = NewActionsInfo();
if (!actions)
return false;
InitCompatInfo(&info, keymap->ctx, actions, &keymap->mods);
info.default_interp.merge = merge;
info.default_led.merge = merge;
HandleCompatMapFile(&info, file, merge);
if (info.errorCount != 0)
goto err_info;
if (!CopyCompatToKeymap(keymap, &info))
goto err_info;
ClearCompatInfo(&info);
FreeActionsInfo(actions);
return true;
err_info:
ClearCompatInfo(&info);
FreeActionsInfo(actions);
return false;
}

View File

@ -1,686 +0,0 @@
/************************************************************
* Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting
* documentation, and that the name of Silicon Graphics not be
* used in advertising or publicity pertaining to distribution
* of the software without specific prior written permission.
* Silicon Graphics makes no representation about the suitability
* of this software for any purpose. It is provided "as is"
* without any express or implied warranty.
*
* SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
* GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
********************************************************/
#include "xkbcomp-priv.h"
#include "text.h"
#include "expr.h"
typedef bool (*IdentLookupFunc)(struct xkb_context *ctx, const void *priv,
xkb_atom_t field, enum expr_value_type type,
unsigned int *val_rtrn);
bool
ExprResolveLhs(struct xkb_context *ctx, const ExprDef *expr,
const char **elem_rtrn, const char **field_rtrn,
ExprDef **index_rtrn)
{
switch (expr->expr.op) {
case EXPR_IDENT:
*elem_rtrn = NULL;
*field_rtrn = xkb_atom_text(ctx, expr->ident.ident);
*index_rtrn = NULL;
return (*field_rtrn != NULL);
case EXPR_FIELD_REF:
*elem_rtrn = xkb_atom_text(ctx, expr->field_ref.element);
*field_rtrn = xkb_atom_text(ctx, expr->field_ref.field);
*index_rtrn = NULL;
return (*elem_rtrn != NULL && *field_rtrn != NULL);
case EXPR_ARRAY_REF:
*elem_rtrn = xkb_atom_text(ctx, expr->array_ref.element);
*field_rtrn = xkb_atom_text(ctx, expr->array_ref.field);
*index_rtrn = expr->array_ref.entry;
if (expr->array_ref.element != XKB_ATOM_NONE && *elem_rtrn == NULL)
return false;
if (*field_rtrn == NULL)
return false;
return true;
default:
break;
}
log_wsgo(ctx, "Unexpected operator %d in ResolveLhs\n", expr->expr.op);
return false;
}
static bool
SimpleLookup(struct xkb_context *ctx, const void *priv, xkb_atom_t field,
enum expr_value_type type, unsigned int *val_rtrn)
{
const LookupEntry *entry;
const char *str;
if (!priv || field == XKB_ATOM_NONE || type != EXPR_TYPE_INT)
return false;
str = xkb_atom_text(ctx, field);
for (entry = priv; entry && entry->name; entry++) {
if (istreq(str, entry->name)) {
*val_rtrn = entry->value;
return true;
}
}
return false;
}
/* Data passed in the *priv argument for LookupModMask. */
typedef struct {
const struct xkb_mod_set *mods;
enum mod_type mod_type;
} LookupModMaskPriv;
static bool
LookupModMask(struct xkb_context *ctx, const void *priv, xkb_atom_t field,
enum expr_value_type type, xkb_mod_mask_t *val_rtrn)
{
const char *str;
xkb_mod_index_t ndx;
const LookupModMaskPriv *arg = priv;
const struct xkb_mod_set *mods = arg->mods;
enum mod_type mod_type = arg->mod_type;
if (type != EXPR_TYPE_INT)
return false;
str = xkb_atom_text(ctx, field);
if (!str)
return false;
if (istreq(str, "all")) {
*val_rtrn = MOD_REAL_MASK_ALL;
return true;
}
if (istreq(str, "none")) {
*val_rtrn = 0;
return true;
}
ndx = XkbModNameToIndex(mods, field, mod_type);
if (ndx == XKB_MOD_INVALID)
return false;
*val_rtrn = (1u << ndx);
return true;
}
bool
ExprResolveBoolean(struct xkb_context *ctx, const ExprDef *expr,
bool *set_rtrn)
{
bool ok = false;
const char *ident;
switch (expr->expr.op) {
case EXPR_VALUE:
if (expr->expr.value_type != EXPR_TYPE_BOOLEAN) {
log_err(ctx,
"Found constant of type %s where boolean was expected\n",
expr_value_type_to_string(expr->expr.value_type));
return false;
}
*set_rtrn = expr->boolean.set;
return true;
case EXPR_IDENT:
ident = xkb_atom_text(ctx, expr->ident.ident);
if (ident) {
if (istreq(ident, "true") ||
istreq(ident, "yes") ||
istreq(ident, "on")) {
*set_rtrn = true;
return true;
}
else if (istreq(ident, "false") ||
istreq(ident, "no") ||
istreq(ident, "off")) {
*set_rtrn = false;
return true;
}
}
log_err(ctx, "Identifier \"%s\" of type boolean is unknown\n", ident);
return false;
case EXPR_FIELD_REF:
log_err(ctx, "Default \"%s.%s\" of type boolean is unknown\n",
xkb_atom_text(ctx, expr->field_ref.element),
xkb_atom_text(ctx, expr->field_ref.field));
return false;
case EXPR_INVERT:
case EXPR_NOT:
ok = ExprResolveBoolean(ctx, expr->unary.child, set_rtrn);
if (ok)
*set_rtrn = !*set_rtrn;
return ok;
case EXPR_ADD:
case EXPR_SUBTRACT:
case EXPR_MULTIPLY:
case EXPR_DIVIDE:
case EXPR_ASSIGN:
case EXPR_NEGATE:
case EXPR_UNARY_PLUS:
log_err(ctx, "%s of boolean values not permitted\n",
expr_op_type_to_string(expr->expr.op));
break;
default:
log_wsgo(ctx, "Unknown operator %d in ResolveBoolean\n",
expr->expr.op);
break;
}
return false;
}
bool
ExprResolveKeyCode(struct xkb_context *ctx, const ExprDef *expr,
xkb_keycode_t *kc)
{
xkb_keycode_t leftRtrn, rightRtrn;
switch (expr->expr.op) {
case EXPR_VALUE:
if (expr->expr.value_type != EXPR_TYPE_INT) {
log_err(ctx,
"Found constant of type %s where an int was expected\n",
expr_value_type_to_string(expr->expr.value_type));
return false;
}
*kc = (xkb_keycode_t) expr->integer.ival;
return true;
case EXPR_ADD:
case EXPR_SUBTRACT:
case EXPR_MULTIPLY:
case EXPR_DIVIDE:
if (!ExprResolveKeyCode(ctx, expr->binary.left, &leftRtrn) ||
!ExprResolveKeyCode(ctx, expr->binary.right, &rightRtrn))
return false;
switch (expr->expr.op) {
case EXPR_ADD:
*kc = leftRtrn + rightRtrn;
break;
case EXPR_SUBTRACT:
*kc = leftRtrn - rightRtrn;
break;
case EXPR_MULTIPLY:
*kc = leftRtrn * rightRtrn;
break;
case EXPR_DIVIDE:
if (rightRtrn == 0) {
log_err(ctx, "Cannot divide by zero: %d / %d\n",
leftRtrn, rightRtrn);
return false;
}
*kc = leftRtrn / rightRtrn;
break;
default:
break;
}
return true;
case EXPR_NEGATE:
if (!ExprResolveKeyCode(ctx, expr->unary.child, &leftRtrn))
return false;
*kc = ~leftRtrn;
return true;
case EXPR_UNARY_PLUS:
return ExprResolveKeyCode(ctx, expr->unary.child, kc);
default:
log_wsgo(ctx, "Unknown operator %d in ResolveKeyCode\n",
expr->expr.op);
break;
}
return false;
}
/**
* This function returns ... something. It's a bit of a guess, really.
*
* If an integer is given in value ctx, it will be returned in ival.
* If an ident or field reference is given, the lookup function (if given)
* will be called. At the moment, only SimpleLookup use this, and they both
* return the results in uval. And don't support field references.
*
* Cool.
*/
static bool
ExprResolveIntegerLookup(struct xkb_context *ctx, const ExprDef *expr,
int *val_rtrn, IdentLookupFunc lookup,
const void *lookupPriv)
{
bool ok = false;
int l, r;
unsigned u;
ExprDef *left, *right;
switch (expr->expr.op) {
case EXPR_VALUE:
if (expr->expr.value_type != EXPR_TYPE_INT) {
log_err(ctx,
"Found constant of type %s where an int was expected\n",
expr_value_type_to_string(expr->expr.value_type));
return false;
}
*val_rtrn = expr->integer.ival;
return true;
case EXPR_IDENT:
if (lookup)
ok = lookup(ctx, lookupPriv, expr->ident.ident, EXPR_TYPE_INT, &u);
if (!ok)
log_err(ctx, "Identifier \"%s\" of type int is unknown\n",
xkb_atom_text(ctx, expr->ident.ident));
else
*val_rtrn = (int) u;
return ok;
case EXPR_FIELD_REF:
log_err(ctx, "Default \"%s.%s\" of type int is unknown\n",
xkb_atom_text(ctx, expr->field_ref.element),
xkb_atom_text(ctx, expr->field_ref.field));
return false;
case EXPR_ADD:
case EXPR_SUBTRACT:
case EXPR_MULTIPLY:
case EXPR_DIVIDE:
left = expr->binary.left;
right = expr->binary.right;
if (!ExprResolveIntegerLookup(ctx, left, &l, lookup, lookupPriv) ||
!ExprResolveIntegerLookup(ctx, right, &r, lookup, lookupPriv))
return false;
switch (expr->expr.op) {
case EXPR_ADD:
*val_rtrn = l + r;
break;
case EXPR_SUBTRACT:
*val_rtrn = l - r;
break;
case EXPR_MULTIPLY:
*val_rtrn = l * r;
break;
case EXPR_DIVIDE:
if (r == 0) {
log_err(ctx, "Cannot divide by zero: %d / %d\n", l, r);
return false;
}
*val_rtrn = l / r;
break;
default:
log_err(ctx, "%s of integers not permitted\n",
expr_op_type_to_string(expr->expr.op));
return false;
}
return true;
case EXPR_ASSIGN:
log_wsgo(ctx, "Assignment operator not implemented yet\n");
break;
case EXPR_NOT:
log_err(ctx, "The ! operator cannot be applied to an integer\n");
return false;
case EXPR_INVERT:
case EXPR_NEGATE:
left = expr->unary.child;
if (!ExprResolveIntegerLookup(ctx, left, &l, lookup, lookupPriv))
return false;
*val_rtrn = (expr->expr.op == EXPR_NEGATE ? -l : ~l);
return true;
case EXPR_UNARY_PLUS:
left = expr->unary.child;
return ExprResolveIntegerLookup(ctx, left, val_rtrn, lookup,
lookupPriv);
default:
log_wsgo(ctx, "Unknown operator %d in ResolveInteger\n",
expr->expr.op);
break;
}
return false;
}
bool
ExprResolveInteger(struct xkb_context *ctx, const ExprDef *expr,
int *val_rtrn)
{
return ExprResolveIntegerLookup(ctx, expr, val_rtrn, NULL, NULL);
}
bool
ExprResolveGroup(struct xkb_context *ctx, const ExprDef *expr,
xkb_layout_index_t *group_rtrn)
{
bool ok;
int result;
ok = ExprResolveIntegerLookup(ctx, expr, &result, SimpleLookup,
groupNames);
if (!ok)
return false;
if (result <= 0 || result > XKB_MAX_GROUPS) {
log_err(ctx, "Group index %u is out of range (1..%d)\n",
result, XKB_MAX_GROUPS);
return false;
}
*group_rtrn = (xkb_layout_index_t) result;
return true;
}
bool
ExprResolveLevel(struct xkb_context *ctx, const ExprDef *expr,
xkb_level_index_t *level_rtrn)
{
bool ok;
int result;
ok = ExprResolveIntegerLookup(ctx, expr, &result, SimpleLookup,
levelNames);
if (!ok)
return false;
if (result < 1) {
log_err(ctx, "Shift level %d is out of range\n", result);
return false;
}
/* Level is zero-indexed from now on. */
*level_rtrn = (unsigned int) (result - 1);
return true;
}
bool
ExprResolveButton(struct xkb_context *ctx, const ExprDef *expr, int *btn_rtrn)
{
return ExprResolveIntegerLookup(ctx, expr, btn_rtrn, SimpleLookup,
buttonNames);
}
bool
ExprResolveString(struct xkb_context *ctx, const ExprDef *expr,
xkb_atom_t *val_rtrn)
{
switch (expr->expr.op) {
case EXPR_VALUE:
if (expr->expr.value_type != EXPR_TYPE_STRING) {
log_err(ctx, "Found constant of type %s, expected a string\n",
expr_value_type_to_string(expr->expr.value_type));
return false;
}
*val_rtrn = expr->string.str;
return true;
case EXPR_IDENT:
log_err(ctx, "Identifier \"%s\" of type string not found\n",
xkb_atom_text(ctx, expr->ident.ident));
return false;
case EXPR_FIELD_REF:
log_err(ctx, "Default \"%s.%s\" of type string not found\n",
xkb_atom_text(ctx, expr->field_ref.element),
xkb_atom_text(ctx, expr->field_ref.field));
return false;
case EXPR_ADD:
case EXPR_SUBTRACT:
case EXPR_MULTIPLY:
case EXPR_DIVIDE:
case EXPR_ASSIGN:
case EXPR_NEGATE:
case EXPR_INVERT:
case EXPR_NOT:
case EXPR_UNARY_PLUS:
log_err(ctx, "%s of strings not permitted\n",
expr_op_type_to_string(expr->expr.op));
return false;
default:
log_wsgo(ctx, "Unknown operator %d in ResolveString\n",
expr->expr.op);
break;
}
return false;
}
bool
ExprResolveEnum(struct xkb_context *ctx, const ExprDef *expr,
unsigned int *val_rtrn, const LookupEntry *values)
{
if (expr->expr.op != EXPR_IDENT) {
log_err(ctx, "Found a %s where an enumerated value was expected\n",
expr_op_type_to_string(expr->expr.op));
return false;
}
if (!SimpleLookup(ctx, values, expr->ident.ident, EXPR_TYPE_INT,
val_rtrn)) {
log_err(ctx, "Illegal identifier %s; expected one of:\n",
xkb_atom_text(ctx, expr->ident.ident));
while (values && values->name)
{
log_err(ctx, "\t%s\n", values->name);
values++;
}
return false;
}
return true;
}
static bool
ExprResolveMaskLookup(struct xkb_context *ctx, const ExprDef *expr,
unsigned int *val_rtrn, IdentLookupFunc lookup,
const void *lookupPriv)
{
bool ok = false;
unsigned int l = 0, r = 0;
int v;
ExprDef *left, *right;
const char *bogus = NULL;
switch (expr->expr.op) {
case EXPR_VALUE:
if (expr->expr.value_type != EXPR_TYPE_INT) {
log_err(ctx,
"Found constant of type %s where a mask was expected\n",
expr_value_type_to_string(expr->expr.value_type));
return false;
}
*val_rtrn = (unsigned int) expr->integer.ival;
return true;
case EXPR_IDENT:
ok = lookup(ctx, lookupPriv, expr->ident.ident, EXPR_TYPE_INT,
val_rtrn);
if (!ok)
log_err(ctx, "Identifier \"%s\" of type int is unknown\n",
xkb_atom_text(ctx, expr->ident.ident));
return ok;
case EXPR_FIELD_REF:
log_err(ctx, "Default \"%s.%s\" of type int is unknown\n",
xkb_atom_text(ctx, expr->field_ref.element),
xkb_atom_text(ctx, expr->field_ref.field));
return false;
case EXPR_ARRAY_REF:
bogus = "array reference";
/* fallthrough */
case EXPR_ACTION_DECL:
if (bogus == NULL)
bogus = "function use";
log_err(ctx,
"Unexpected %s in mask expression; Expression Ignored\n",
bogus);
return false;
case EXPR_ADD:
case EXPR_SUBTRACT:
case EXPR_MULTIPLY:
case EXPR_DIVIDE:
left = expr->binary.left;
right = expr->binary.right;
if (!ExprResolveMaskLookup(ctx, left, &l, lookup, lookupPriv) ||
!ExprResolveMaskLookup(ctx, right, &r, lookup, lookupPriv))
return false;
switch (expr->expr.op) {
case EXPR_ADD:
*val_rtrn = l | r;
break;
case EXPR_SUBTRACT:
*val_rtrn = l & (~r);
break;
case EXPR_MULTIPLY:
case EXPR_DIVIDE:
log_err(ctx, "Cannot %s masks; Illegal operation ignored\n",
(expr->expr.op == EXPR_DIVIDE ? "divide" : "multiply"));
return false;
default:
break;
}
return true;
case EXPR_ASSIGN:
log_wsgo(ctx, "Assignment operator not implemented yet\n");
break;
case EXPR_INVERT:
left = expr->unary.child;
if (!ExprResolveIntegerLookup(ctx, left, &v, lookup, lookupPriv))
return false;
*val_rtrn = ~v;
return true;
case EXPR_UNARY_PLUS:
case EXPR_NEGATE:
case EXPR_NOT:
left = expr->unary.child;
if (!ExprResolveIntegerLookup(ctx, left, &v, lookup, lookupPriv))
log_err(ctx, "The %s operator cannot be used with a mask\n",
(expr->expr.op == EXPR_NEGATE ? "-" : "!"));
return false;
default:
log_wsgo(ctx, "Unknown operator %d in ResolveMask\n",
expr->expr.op);
break;
}
return false;
}
bool
ExprResolveMask(struct xkb_context *ctx, const ExprDef *expr,
unsigned int *mask_rtrn, const LookupEntry *values)
{
return ExprResolveMaskLookup(ctx, expr, mask_rtrn, SimpleLookup, values);
}
bool
ExprResolveModMask(struct xkb_context *ctx, const ExprDef *expr,
enum mod_type mod_type, const struct xkb_mod_set *mods,
xkb_mod_mask_t *mask_rtrn)
{
LookupModMaskPriv priv = { .mods = mods, .mod_type = mod_type };
return ExprResolveMaskLookup(ctx, expr, mask_rtrn, LookupModMask, &priv);
}
bool
ExprResolveKeySym(struct xkb_context *ctx, const ExprDef *expr,
xkb_keysym_t *sym_rtrn)
{
int val;
if (expr->expr.op == EXPR_IDENT) {
const char *str = xkb_atom_text(ctx, expr->ident.ident);
*sym_rtrn = xkb_keysym_from_name(str, 0);
if (*sym_rtrn != XKB_KEY_NoSymbol)
return true;
}
if (!ExprResolveInteger(ctx, expr, &val))
return false;
if (val < 0 || val >= 10)
return false;
*sym_rtrn = XKB_KEY_0 + (xkb_keysym_t) val;
return true;
}
bool
ExprResolveMod(struct xkb_context *ctx, const ExprDef *def,
enum mod_type mod_type, const struct xkb_mod_set *mods,
xkb_mod_index_t *ndx_rtrn)
{
xkb_mod_index_t ndx;
xkb_atom_t name;
if (def->expr.op != EXPR_IDENT) {
log_err(ctx,
"Cannot resolve virtual modifier: "
"found %s where a virtual modifier name was expected\n",
expr_op_type_to_string(def->expr.op));
return false;
}
name = def->ident.ident;
ndx = XkbModNameToIndex(mods, name, mod_type);
if (ndx == XKB_MOD_INVALID) {
log_err(ctx,
"Cannot resolve virtual modifier: "
"\"%s\" was not previously declared\n",
xkb_atom_text(ctx, name));
return false;
}
*ndx_rtrn = ndx;
return true;
}

View File

@ -1,85 +0,0 @@
/************************************************************
* Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting
* documentation, and that the name of Silicon Graphics not be
* used in advertising or publicity pertaining to distribution
* of the software without specific prior written permission.
* Silicon Graphics makes no representation about the suitability
* of this software for any purpose. It is provided "as is"
* without any express or implied warranty.
*
* SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
* GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
********************************************************/
#ifndef XKBCOMP_EXPR_H
#define XKBCOMP_EXPR_H
bool
ExprResolveLhs(struct xkb_context *ctx, const ExprDef *expr,
const char **elem_rtrn, const char **field_rtrn,
ExprDef **index_rtrn);
bool
ExprResolveModMask(struct xkb_context *ctx, const ExprDef *expr,
enum mod_type mod_type, const struct xkb_mod_set *mods,
xkb_mod_mask_t *mask_rtrn);
bool
ExprResolveMod(struct xkb_context *ctx, const ExprDef *def,
enum mod_type mod_type, const struct xkb_mod_set *mods,
xkb_mod_index_t *ndx_rtrn);
bool
ExprResolveBoolean(struct xkb_context *ctx, const ExprDef *expr,
bool *set_rtrn);
bool
ExprResolveKeyCode(struct xkb_context *ctx, const ExprDef *expr,
xkb_keycode_t *kc);
bool
ExprResolveInteger(struct xkb_context *ctx, const ExprDef *expr,
int *val_rtrn);
bool
ExprResolveLevel(struct xkb_context *ctx, const ExprDef *expr,
xkb_level_index_t *level_rtrn);
bool
ExprResolveGroup(struct xkb_context *ctx, const ExprDef *expr,
xkb_layout_index_t *group_rtrn);
bool
ExprResolveButton(struct xkb_context *ctx, const ExprDef *expr,
int *btn_rtrn);
bool
ExprResolveString(struct xkb_context *ctx, const ExprDef *expr,
xkb_atom_t *val_rtrn);
bool
ExprResolveEnum(struct xkb_context *ctx, const ExprDef *expr,
unsigned int *val_rtrn, const LookupEntry *values);
bool
ExprResolveMask(struct xkb_context *ctx, const ExprDef *expr,
unsigned int *mask_rtrn, const LookupEntry *values);
bool
ExprResolveKeySym(struct xkb_context *ctx, const ExprDef *expr,
xkb_keysym_t *sym_rtrn);
#endif

View File

@ -1,309 +0,0 @@
/************************************************************
* Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting
* documentation, and that the name of Silicon Graphics not be
* used in advertising or publicity pertaining to distribution
* of the software without specific prior written permission.
* Silicon Graphics makes no representation about the suitability
* of this software for any purpose. It is provided "as is"
* without any express or implied warranty.
*
* SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
* GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
********************************************************/
/*
* Copyright © 2012 Ran Benita <ran234@gmail.com>
*
* 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 (including the next
* paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
*/
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include "xkbcomp-priv.h"
#include "include.h"
/**
* Parse an include statement. Each call returns a file name, along with
* (possibly) a specific map in the file, an explicit group designator, and
* the separator from the next file, used to determine the merge mode.
*
* @param str_inout Input statement, modified in-place. Should be passed in
* repeatedly. If str_inout is NULL, the parsing has completed.
*
* @param file_rtrn Set to the name of the include file to be used. Combined
* with an enum xkb_file_type, this determines which file to look for in the
* include path.
*
* @param map_rtrn Set to the string between '(' and ')', if any. This will
* result in the compilation of a specific named map within the file (e.g.
* xkb_symbols "basic" { ... }) , as opposed to the default map of the file.
*
* @param nextop_rtrn Set to the next operation in the complete statement,
* which is '\0' if it's the last file or '+' or '|' if there are more.
* Separating the files with '+' sets the merge mode to MERGE_MODE_OVERRIDE,
* while '|' sets the merge mode to MERGE_MODE_AUGMENT.
*
* @param extra_data Set to the string after ':', if any. Currently the
* extra data is only used for setting an explicit group index for a symbols
* file.
*
* @return true if parsing was successful, false for an illegal string.
*
* Example: "evdev+aliases(qwerty):2"
* str_inout = "aliases(qwerty):2"
* file_rtrn = "evdev"
* map_rtrn = NULL
* nextop_retrn = "+"
* extra_data = NULL
*
* 2nd run with "aliases(qwerty):2"
* str_inout = NULL
* file_rtrn = "aliases"
* map_rtrn = "qwerty"
* nextop_retrn = ""
* extra_data = "2"
*
*/
bool
ParseIncludeMap(char **str_inout, char **file_rtrn, char **map_rtrn,
char *nextop_rtrn, char **extra_data)
{
char *tmp, *str, *next;
str = *str_inout;
/*
* Find the position in the string where the next file is included,
* if there is more than one left in the statement.
*/
next = strpbrk(str, "|+");
if (next) {
/* Got more files, this function will be called again. */
*nextop_rtrn = *next;
/* Separate the string, for strchr etc. to work on this file only. */
*next++ = '\0';
}
else {
/* This is the last file in this statement, won't be called again. */
*nextop_rtrn = '\0';
next = NULL;
}
/*
* Search for the explicit group designator, if any. If it's there,
* it goes after the file name and map.
*/
tmp = strchr(str, ':');
if (tmp != NULL) {
*tmp++ = '\0';
*extra_data = strdup(tmp);
}
else {
*extra_data = NULL;
}
/* Look for a map, if any. */
tmp = strchr(str, '(');
if (tmp == NULL) {
/* No map. */
*file_rtrn = strdup(str);
*map_rtrn = NULL;
}
else if (str[0] == '(') {
/* Map without file - invalid. */
free(*extra_data);
return false;
}
else {
/* Got a map; separate the file and the map for the strdup's. */
*tmp++ = '\0';
*file_rtrn = strdup(str);
str = tmp;
tmp = strchr(str, ')');
if (tmp == NULL || tmp[1] != '\0') {
free(*file_rtrn);
free(*extra_data);
return false;
}
*tmp++ = '\0';
*map_rtrn = strdup(str);
}
/* Set up the next file for the next call, if any. */
if (*nextop_rtrn == '\0')
*str_inout = NULL;
else if (*nextop_rtrn == '|' || *nextop_rtrn == '+')
*str_inout = next;
else
return false;
return true;
}
static const char *xkb_file_type_include_dirs[_FILE_TYPE_NUM_ENTRIES] = {
[FILE_TYPE_KEYCODES] = "keycodes",
[FILE_TYPE_TYPES] = "types",
[FILE_TYPE_COMPAT] = "compat",
[FILE_TYPE_SYMBOLS] = "symbols",
[FILE_TYPE_GEOMETRY] = "geometry",
[FILE_TYPE_KEYMAP] = "keymap",
[FILE_TYPE_RULES] = "rules",
};
/**
* Return the xkb directory based on the type.
*/
static const char *
DirectoryForInclude(enum xkb_file_type type)
{
if (type >= _FILE_TYPE_NUM_ENTRIES)
return "";
return xkb_file_type_include_dirs[type];
}
FILE *
FindFileInXkbPath(struct xkb_context *ctx, const char *name,
enum xkb_file_type type, char **pathRtrn)
{
unsigned int i;
FILE *file = NULL;
char *buf = NULL;
const char *typeDir;
size_t buf_size = 0, typeDirLen, name_len;
typeDir = DirectoryForInclude(type);
typeDirLen = strlen(typeDir);
name_len = strlen(name);
for (i = 0; i < xkb_context_num_include_paths(ctx); i++) {
size_t new_buf_size = strlen(xkb_context_include_path_get(ctx, i)) +
typeDirLen + name_len + 3;
int ret;
if (new_buf_size > buf_size) {
void *buf_new = realloc(buf, new_buf_size);
if (buf_new) {
buf_size = new_buf_size;
buf = buf_new;
} else {
log_err(ctx, "Cannot realloc for name (%s/%s/%s)\n",
xkb_context_include_path_get(ctx, i), typeDir, name);
continue;
}
}
ret = snprintf(buf, buf_size, "%s/%s/%s",
xkb_context_include_path_get(ctx, i),
typeDir, name);
if (ret < 0) {
log_err(ctx, "snprintf error (%s/%s/%s)\n",
xkb_context_include_path_get(ctx, i), typeDir, name);
continue;
}
file = fopen(buf, "r");
if (file)
break;
}
if (!file) {
log_err(ctx, "Couldn't find file \"%s/%s\" in include paths\n",
typeDir, name);
if (xkb_context_num_include_paths(ctx) > 0) {
log_err(ctx, "%d include paths searched:\n",
xkb_context_num_include_paths(ctx));
for (i = 0; i < xkb_context_num_include_paths(ctx); i++)
log_err(ctx, "\t%s\n",
xkb_context_include_path_get(ctx, i));
}
else {
log_err(ctx, "There are no include paths to search\n");
}
if (xkb_context_num_failed_include_paths(ctx) > 0) {
log_err(ctx, "%d include paths could not be added:\n",
xkb_context_num_failed_include_paths(ctx));
for (i = 0; i < xkb_context_num_failed_include_paths(ctx); i++)
log_err(ctx, "\t%s\n",
xkb_context_failed_include_path_get(ctx, i));
}
free(buf);
return NULL;
}
if (pathRtrn)
*pathRtrn = buf;
else
free(buf);
return file;
}
XkbFile *
ProcessIncludeFile(struct xkb_context *ctx, IncludeStmt *stmt,
enum xkb_file_type file_type)
{
FILE *file;
XkbFile *xkb_file;
file = FindFileInXkbPath(ctx, stmt->file, file_type, NULL);
if (!file)
return false;
xkb_file = XkbParseFile(ctx, file, stmt->file, stmt->map);
fclose(file);
if (!xkb_file) {
if (stmt->map)
log_err(ctx, "Couldn't process include statement for '%s(%s)'\n",
stmt->file, stmt->map);
else
log_err(ctx, "Couldn't process include statement for '%s'\n",
stmt->file);
return NULL;
}
if (xkb_file->file_type != file_type) {
log_err(ctx,
"Include file of wrong type (expected %s, got %s); "
"Include file \"%s\" ignored\n",
xkb_file_type_to_string(file_type),
xkb_file_type_to_string(xkb_file->file_type), stmt->file);
FreeXkbFile(xkb_file);
return NULL;
}
/* FIXME: we have to check recursive includes here (or somewhere) */
return xkb_file;
}

View File

@ -1,42 +0,0 @@
/************************************************************
* Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting
* documentation, and that the name of Silicon Graphics not be
* used in advertising or publicity pertaining to distribution
* of the software without specific prior written permission.
* Silicon Graphics makes no representation about the suitability
* of this software for any purpose. It is provided "as is"
* without any express or implied warranty.
*
* SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
* GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
********************************************************/
#ifndef XKBCOMP_INCLUDE_H
#define XKBCOMP_INCLUDE_H
bool
ParseIncludeMap(char **str_inout, char **file_rtrn, char **map_rtrn,
char *nextop_rtrn, char **extra_data);
FILE *
FindFileInXkbPath(struct xkb_context *ctx, const char *name,
enum xkb_file_type type, char **pathRtrn);
XkbFile *
ProcessIncludeFile(struct xkb_context *ctx, IncludeStmt *stmt,
enum xkb_file_type file_type);
#endif

View File

@ -1,668 +0,0 @@
/************************************************************
* Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting
* documentation, and that the name of Silicon Graphics not be
* used in advertising or publicity pertaining to distribution
* of the software without specific prior written permission.
* Silicon Graphics makes no representation about the suitability
* of this software for any purpose. It is provided "as is"
* without any express or implied warranty.
*
* SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
* GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
********************************************************/
#include "xkbcomp-priv.h"
#include "text.h"
#include "expr.h"
#include "include.h"
typedef struct {
enum merge_mode merge;
xkb_atom_t alias;
xkb_atom_t real;
} AliasInfo;
typedef struct {
enum merge_mode merge;
xkb_atom_t name;
} LedNameInfo;
typedef struct {
char *name;
int errorCount;
xkb_keycode_t min_key_code;
xkb_keycode_t max_key_code;
darray(xkb_atom_t) key_names;
LedNameInfo led_names[XKB_MAX_LEDS];
unsigned int num_led_names;
darray(AliasInfo) aliases;
struct xkb_context *ctx;
} KeyNamesInfo;
/***====================================================================***/
static void
InitAliasInfo(AliasInfo *info, enum merge_mode merge,
xkb_atom_t alias, xkb_atom_t real)
{
memset(info, 0, sizeof(*info));
info->merge = merge;
info->alias = alias;
info->real = real;
}
static LedNameInfo *
FindLedByName(KeyNamesInfo *info, xkb_atom_t name,
xkb_led_index_t *idx_out)
{
for (xkb_led_index_t idx = 0; idx < info->num_led_names; idx++) {
LedNameInfo *ledi = &info->led_names[idx];
if (ledi->name == name) {
*idx_out = idx;
return ledi;
}
}
return NULL;
}
static bool
AddLedName(KeyNamesInfo *info, enum merge_mode merge, bool same_file,
LedNameInfo *new, xkb_led_index_t new_idx)
{
xkb_led_index_t old_idx;
LedNameInfo *old;
const int verbosity = xkb_context_get_log_verbosity(info->ctx);
const bool report = (same_file && verbosity > 0) || verbosity > 9;
const bool replace = (merge == MERGE_REPLACE || merge == MERGE_OVERRIDE);
/* LED with the same name already exists. */
old = FindLedByName(info, new->name, &old_idx);
if (old) {
if (old_idx == new_idx) {
log_warn(info->ctx,
"Multiple indicators named \"%s\"; "
"Identical definitions ignored\n",
xkb_atom_text(info->ctx, new->name));
return true;
}
if (report) {
xkb_led_index_t use = (replace ? new_idx + 1 : old_idx + 1);
xkb_led_index_t ignore = (replace ? old_idx + 1 : new_idx + 1);
log_warn(info->ctx,
"Multiple indicators named %s; Using %d, ignoring %d\n",
xkb_atom_text(info->ctx, new->name), use, ignore);
}
if (replace)
*old = *new;
return true;
}
if (new_idx >= info->num_led_names)
info->num_led_names = new_idx + 1;
/* LED with the same index already exists. */
old = &info->led_names[new_idx];
if (old->name != XKB_ATOM_NONE) {
if (report) {
const xkb_atom_t use = (replace ? new->name : old->name);
const xkb_atom_t ignore = (replace ? old->name : new->name);
log_warn(info->ctx, "Multiple names for indicator %d; "
"Using %s, ignoring %s\n", new_idx + 1,
xkb_atom_text(info->ctx, use),
xkb_atom_text(info->ctx, ignore));
}
if (replace)
*old = *new;
return true;
}
*old = *new;
return true;
}
static void
ClearKeyNamesInfo(KeyNamesInfo *info)
{
free(info->name);
darray_free(info->key_names);
darray_free(info->aliases);
}
static void
InitKeyNamesInfo(KeyNamesInfo *info, struct xkb_context *ctx)
{
memset(info, 0, sizeof(*info));
info->ctx = ctx;
info->min_key_code = XKB_KEYCODE_INVALID;
#if XKB_KEYCODE_INVALID < XKB_KEYCODE_MAX
#error "Hey, you can't be changing stuff like that."
#endif
}
static xkb_keycode_t
FindKeyByName(KeyNamesInfo *info, xkb_atom_t name)
{
xkb_keycode_t i;
for (i = info->min_key_code; i <= info->max_key_code; i++)
if (darray_item(info->key_names, i) == name)
return i;
return XKB_KEYCODE_INVALID;
}
static bool
AddKeyName(KeyNamesInfo *info, xkb_keycode_t kc, xkb_atom_t name,
enum merge_mode merge, bool same_file, bool report)
{
xkb_atom_t old_name;
xkb_keycode_t old_kc;
const int verbosity = xkb_context_get_log_verbosity(info->ctx);
report = report && ((same_file && verbosity > 0) || verbosity > 7);
if (kc >= darray_size(info->key_names))
darray_resize0(info->key_names, kc + 1);
info->min_key_code = MIN(info->min_key_code, kc);
info->max_key_code = MAX(info->max_key_code, kc);
/* There's already a key with this keycode. */
old_name = darray_item(info->key_names, kc);
if (old_name != XKB_ATOM_NONE) {
const char *lname = KeyNameText(info->ctx, old_name);
const char *kname = KeyNameText(info->ctx, name);
if (old_name == name) {
if (report)
log_warn(info->ctx,
"Multiple identical key name definitions; "
"Later occurrences of \"%s = %d\" ignored\n",
lname, kc);
return true;
}
else if (merge == MERGE_AUGMENT) {
if (report)
log_warn(info->ctx,
"Multiple names for keycode %d; "
"Using %s, ignoring %s\n", kc, lname, kname);
return true;
}
else {
if (report)
log_warn(info->ctx,
"Multiple names for keycode %d; "
"Using %s, ignoring %s\n", kc, kname, lname);
darray_item(info->key_names, kc) = XKB_ATOM_NONE;
}
}
/* There's already a key with this name. */
old_kc = FindKeyByName(info, name);
if (old_kc != XKB_KEYCODE_INVALID && old_kc != kc) {
const char *kname = KeyNameText(info->ctx, name);
if (merge == MERGE_OVERRIDE) {
darray_item(info->key_names, old_kc) = XKB_ATOM_NONE;
if (report)
log_warn(info->ctx,
"Key name %s assigned to multiple keys; "
"Using %d, ignoring %d\n", kname, kc, old_kc);
}
else {
if (report)
log_vrb(info->ctx, 3,
"Key name %s assigned to multiple keys; "
"Using %d, ignoring %d\n", kname, old_kc, kc);
return true;
}
}
darray_item(info->key_names, kc) = name;
return true;
}
/***====================================================================***/
static bool
HandleAliasDef(KeyNamesInfo *info, KeyAliasDef *def, enum merge_mode merge);
static void
MergeIncludedKeycodes(KeyNamesInfo *into, KeyNamesInfo *from,
enum merge_mode merge)
{
if (from->errorCount > 0) {
into->errorCount += from->errorCount;
return;
}
if (into->name == NULL) {
into->name = from->name;
from->name = NULL;
}
/* Merge key names. */
if (darray_empty(into->key_names)) {
into->key_names = from->key_names;
darray_init(from->key_names);
into->min_key_code = from->min_key_code;
into->max_key_code = from->max_key_code;
}
else {
if (darray_size(into->key_names) < darray_size(from->key_names))
darray_resize0(into->key_names, darray_size(from->key_names));
for (unsigned i = from->min_key_code; i <= from->max_key_code; i++) {
xkb_atom_t name = darray_item(from->key_names, i);
if (name == XKB_ATOM_NONE)
continue;
if (!AddKeyName(into, i, name, merge, true, false))
into->errorCount++;
}
}
/* Merge key aliases. */
if (darray_empty(into->aliases)) {
into->aliases = from->aliases;
darray_init(from->aliases);
}
else {
AliasInfo *alias;
darray_foreach(alias, from->aliases) {
KeyAliasDef def;
def.merge = (merge == MERGE_DEFAULT ? alias->merge : merge);
def.alias = alias->alias;
def.real = alias->real;
if (!HandleAliasDef(into, &def, def.merge))
into->errorCount++;
}
}
/* Merge LED names. */
if (into->num_led_names == 0) {
memcpy(into->led_names, from->led_names,
sizeof(*from->led_names) * from->num_led_names);
into->num_led_names = from->num_led_names;
from->num_led_names = 0;
}
else {
for (xkb_led_index_t idx = 0; idx < from->num_led_names; idx++) {
LedNameInfo *ledi = &from->led_names[idx];
if (ledi->name == XKB_ATOM_NONE)
continue;
ledi->merge = (merge == MERGE_DEFAULT ? ledi->merge : merge);
if (!AddLedName(into, ledi->merge, false, ledi, idx))
into->errorCount++;
}
}
}
static void
HandleKeycodesFile(KeyNamesInfo *info, XkbFile *file, enum merge_mode merge);
static bool
HandleIncludeKeycodes(KeyNamesInfo *info, IncludeStmt *include)
{
KeyNamesInfo included;
InitKeyNamesInfo(&included, info->ctx);
included.name = include->stmt;
include->stmt = NULL;
for (IncludeStmt *stmt = include; stmt; stmt = stmt->next_incl) {
KeyNamesInfo next_incl;
XkbFile *file;
file = ProcessIncludeFile(info->ctx, stmt, FILE_TYPE_KEYCODES);
if (!file) {
info->errorCount += 10;
ClearKeyNamesInfo(&included);
return false;
}
InitKeyNamesInfo(&next_incl, info->ctx);
HandleKeycodesFile(&next_incl, file, MERGE_OVERRIDE);
MergeIncludedKeycodes(&included, &next_incl, stmt->merge);
ClearKeyNamesInfo(&next_incl);
FreeXkbFile(file);
}
MergeIncludedKeycodes(info, &included, include->merge);
ClearKeyNamesInfo(&included);
return (info->errorCount == 0);
}
static bool
HandleKeycodeDef(KeyNamesInfo *info, KeycodeDef *stmt, enum merge_mode merge)
{
if (stmt->merge != MERGE_DEFAULT) {
if (stmt->merge == MERGE_REPLACE)
merge = MERGE_OVERRIDE;
else
merge = stmt->merge;
}
if (stmt->value < 0 || stmt->value > XKB_KEYCODE_MAX) {
log_err(info->ctx,
"Illegal keycode %lld: must be between 0..%u; "
"Key ignored\n", (long long) stmt->value, XKB_KEYCODE_MAX);
return false;
}
return AddKeyName(info, stmt->value, stmt->name, merge, false, true);
}
static bool
HandleAliasDef(KeyNamesInfo *info, KeyAliasDef *def, enum merge_mode merge)
{
AliasInfo *old, new;
darray_foreach(old, info->aliases) {
if (old->alias == def->alias) {
if (def->real == old->real) {
log_vrb(info->ctx, 1,
"Alias of %s for %s declared more than once; "
"First definition ignored\n",
KeyNameText(info->ctx, def->alias),
KeyNameText(info->ctx, def->real));
}
else {
xkb_atom_t use, ignore;
use = (merge == MERGE_AUGMENT ? old->real : def->real);
ignore = (merge == MERGE_AUGMENT ? def->real : old->real);
log_warn(info->ctx,
"Multiple definitions for alias %s; "
"Using %s, ignoring %s\n",
KeyNameText(info->ctx, old->alias),
KeyNameText(info->ctx, use),
KeyNameText(info->ctx, ignore));
old->real = use;
}
old->merge = merge;
return true;
}
}
InitAliasInfo(&new, merge, def->alias, def->real);
darray_append(info->aliases, new);
return true;
}
static bool
HandleKeyNameVar(KeyNamesInfo *info, VarDef *stmt)
{
const char *elem, *field;
ExprDef *arrayNdx;
if (!ExprResolveLhs(info->ctx, stmt->name, &elem, &field, &arrayNdx))
return false;
if (elem) {
log_err(info->ctx, "Unknown element %s encountered; "
"Default for field %s ignored\n", elem, field);
return false;
}
if (!istreq(field, "minimum") && !istreq(field, "maximum")) {
log_err(info->ctx, "Unknown field encountered; "
"Assignment to field %s ignored\n", field);
return false;
}
/* We ignore explicit min/max statements, we always use computed. */
return true;
}
static bool
HandleLedNameDef(KeyNamesInfo *info, LedNameDef *def,
enum merge_mode merge)
{
LedNameInfo ledi;
xkb_atom_t name;
if (def->ndx < 1 || def->ndx > XKB_MAX_LEDS) {
info->errorCount++;
log_err(info->ctx,
"Illegal indicator index (%d) specified; must be between 1 .. %d; "
"Ignored\n", def->ndx, XKB_MAX_LEDS);
return false;
}
if (!ExprResolveString(info->ctx, def->name, &name)) {
char buf[20];
snprintf(buf, sizeof(buf), "%u", def->ndx);
info->errorCount++;
return ReportBadType(info->ctx, "indicator", "name", buf, "string");
}
ledi.merge = merge;
ledi.name = name;
return AddLedName(info, merge, true, &ledi, def->ndx - 1);
}
static void
HandleKeycodesFile(KeyNamesInfo *info, XkbFile *file, enum merge_mode merge)
{
bool ok;
free(info->name);
info->name = strdup_safe(file->name);
for (ParseCommon *stmt = file->defs; stmt; stmt = stmt->next) {
switch (stmt->type) {
case STMT_INCLUDE:
ok = HandleIncludeKeycodes(info, (IncludeStmt *) stmt);
break;
case STMT_KEYCODE:
ok = HandleKeycodeDef(info, (KeycodeDef *) stmt, merge);
break;
case STMT_ALIAS:
ok = HandleAliasDef(info, (KeyAliasDef *) stmt, merge);
break;
case STMT_VAR:
ok = HandleKeyNameVar(info, (VarDef *) stmt);
break;
case STMT_LED_NAME:
ok = HandleLedNameDef(info, (LedNameDef *) stmt, merge);
break;
default:
log_err(info->ctx,
"Keycode files may define key and indicator names only; "
"Ignoring %s\n", stmt_type_to_string(stmt->type));
ok = false;
break;
}
if (!ok)
info->errorCount++;
if (info->errorCount > 10) {
log_err(info->ctx, "Abandoning keycodes file \"%s\"\n",
file->name);
break;
}
}
}
/***====================================================================***/
static bool
CopyKeyNamesToKeymap(struct xkb_keymap *keymap, KeyNamesInfo *info)
{
struct xkb_key *keys;
xkb_keycode_t min_key_code, max_key_code, kc;
min_key_code = info->min_key_code;
max_key_code = info->max_key_code;
/* If the keymap has no keys, let's just use the safest pair we know. */
if (min_key_code == XKB_KEYCODE_INVALID) {
min_key_code = 8;
max_key_code = 255;
}
keys = calloc(max_key_code + 1, sizeof(*keys));
if (!keys)
return false;
for (kc = min_key_code; kc <= max_key_code; kc++)
keys[kc].keycode = kc;
for (kc = info->min_key_code; kc <= info->max_key_code; kc++)
keys[kc].name = darray_item(info->key_names, kc);
keymap->min_key_code = min_key_code;
keymap->max_key_code = max_key_code;
keymap->keys = keys;
return true;
}
static bool
CopyKeyAliasesToKeymap(struct xkb_keymap *keymap, KeyNamesInfo *info)
{
AliasInfo *alias;
unsigned i, num_key_aliases;
struct xkb_key_alias *key_aliases;
/*
* Do some sanity checking on the aliases. We can't do it before
* because keys and their aliases may be added out-of-order.
*/
num_key_aliases = 0;
darray_foreach(alias, info->aliases) {
/* Check that ->real is a key. */
if (!XkbKeyByName(keymap, alias->real, false)) {
log_vrb(info->ctx, 5,
"Attempt to alias %s to non-existent key %s; Ignored\n",
KeyNameText(info->ctx, alias->alias),
KeyNameText(info->ctx, alias->real));
alias->real = XKB_ATOM_NONE;
continue;
}
/* Check that ->alias is not a key. */
if (XkbKeyByName(keymap, alias->alias, false)) {
log_vrb(info->ctx, 5,
"Attempt to create alias with the name of a real key; "
"Alias \"%s = %s\" ignored\n",
KeyNameText(info->ctx, alias->alias),
KeyNameText(info->ctx, alias->real));
alias->real = XKB_ATOM_NONE;
continue;
}
num_key_aliases++;
}
/* Copy key aliases. */
key_aliases = NULL;
if (num_key_aliases > 0) {
key_aliases = calloc(num_key_aliases, sizeof(*key_aliases));
if (!key_aliases)
return false;
i = 0;
darray_foreach(alias, info->aliases) {
if (alias->real != XKB_ATOM_NONE) {
key_aliases[i].alias = alias->alias;
key_aliases[i].real = alias->real;
i++;
}
}
}
keymap->num_key_aliases = num_key_aliases;
keymap->key_aliases = key_aliases;
return true;
}
static bool
CopyLedNamesToKeymap(struct xkb_keymap *keymap, KeyNamesInfo *info)
{
keymap->num_leds = info->num_led_names;
for (xkb_led_index_t idx = 0; idx < info->num_led_names; idx++) {
LedNameInfo *ledi = &info->led_names[idx];
if (ledi->name == XKB_ATOM_NONE)
continue;
keymap->leds[idx].name = ledi->name;
}
return true;
}
static bool
CopyKeyNamesInfoToKeymap(struct xkb_keymap *keymap, KeyNamesInfo *info)
{
/* This function trashes keymap on error, but that's OK. */
if (!CopyKeyNamesToKeymap(keymap, info) ||
!CopyKeyAliasesToKeymap(keymap, info) ||
!CopyLedNamesToKeymap(keymap, info))
return false;
keymap->keycodes_section_name = strdup_safe(info->name);
XkbEscapeMapName(keymap->keycodes_section_name);
return true;
}
/***====================================================================***/
bool
CompileKeycodes(XkbFile *file, struct xkb_keymap *keymap,
enum merge_mode merge)
{
KeyNamesInfo info;
InitKeyNamesInfo(&info, keymap->ctx);
HandleKeycodesFile(&info, file, merge);
if (info.errorCount != 0)
goto err_info;
if (!CopyKeyNamesInfoToKeymap(keymap, &info))
goto err_info;
ClearKeyNamesInfo(&info);
return true;
err_info:
ClearKeyNamesInfo(&info);
return false;
}

View File

@ -1,664 +0,0 @@
/************************************************************
* Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting
* documentation, and that the name of Silicon Graphics not be
* used in advertising or publicity pertaining to distribution
* of the software without specific prior written permission.
* Silicon Graphics makes no representation about the suitability
* of this software for any purpose. It is provided "as is"
* without any express or implied warranty.
*
* SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
* GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
********************************************************/
/*
* Copyright © 2012 Intel Corporation
*
* 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 (including the next
* paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
*
* Author: Daniel Stone <daniel@fooishbar.org>
*/
#include "xkbcomp-priv.h"
#include "text.h"
#define BUF_CHUNK_SIZE 4096
struct buf {
char *buf;
size_t size;
size_t alloc;
};
static bool
do_realloc(struct buf *buf, size_t at_least)
{
char *new;
buf->alloc += BUF_CHUNK_SIZE;
if (at_least >= BUF_CHUNK_SIZE)
buf->alloc += at_least;
new = realloc(buf->buf, buf->alloc);
if (!new)
return false;
buf->buf = new;
return true;
}
ATTR_PRINTF(2, 3) static bool
check_write_buf(struct buf *buf, const char *fmt, ...)
{
va_list args;
int printed;
size_t available;
available = buf->alloc - buf->size;
va_start(args, fmt);
printed = vsnprintf(buf->buf + buf->size, available, fmt, args);
va_end(args);
if (printed < 0)
goto err;
if ((size_t) printed >= available)
if (!do_realloc(buf, printed))
goto err;
/* The buffer has enough space now. */
available = buf->alloc - buf->size;
va_start(args, fmt);
printed = vsnprintf(buf->buf + buf->size, available, fmt, args);
va_end(args);
if (printed < 0 || (size_t) printed >= available)
goto err;
buf->size += printed;
return true;
err:
free(buf->buf);
buf->buf = NULL;
return false;
}
#define write_buf(buf, ...) do { \
if (!check_write_buf(buf, __VA_ARGS__)) \
return false; \
} while (0)
static bool
write_vmods(struct xkb_keymap *keymap, struct buf *buf)
{
const struct xkb_mod *mod;
xkb_mod_index_t num_vmods = 0;
xkb_mods_foreach(mod, &keymap->mods) {
if (mod->type != MOD_VIRT)
continue;
if (num_vmods == 0)
write_buf(buf, "\tvirtual_modifiers ");
else
write_buf(buf, ",");
write_buf(buf, "%s", xkb_atom_text(keymap->ctx, mod->name));
num_vmods++;
}
if (num_vmods > 0)
write_buf(buf, ";\n\n");
return true;
}
static bool
write_keycodes(struct xkb_keymap *keymap, struct buf *buf)
{
const struct xkb_key *key;
xkb_led_index_t idx;
const struct xkb_led *led;
if (keymap->keycodes_section_name)
write_buf(buf, "xkb_keycodes \"%s\" {\n",
keymap->keycodes_section_name);
else
write_buf(buf, "xkb_keycodes {\n");
/* xkbcomp and X11 really want to see keymaps with a minimum of 8, and
* a maximum of at least 255, else XWayland really starts hating life.
* If this is a problem and people really need strictly bounded keymaps,
* we should probably control this with a flag. */
write_buf(buf, "\tminimum = %u;\n", min(keymap->min_key_code, 8));
write_buf(buf, "\tmaximum = %u;\n", max(keymap->max_key_code, 255));
xkb_keys_foreach(key, keymap) {
if (key->name == XKB_ATOM_NONE)
continue;
write_buf(buf, "\t%-20s = %u;\n",
KeyNameText(keymap->ctx, key->name), key->keycode);
}
xkb_leds_enumerate(idx, led, keymap)
if (led->name != XKB_ATOM_NONE)
write_buf(buf, "\tindicator %u = \"%s\";\n",
idx + 1, xkb_atom_text(keymap->ctx, led->name));
for (unsigned i = 0; i < keymap->num_key_aliases; i++)
write_buf(buf, "\talias %-14s = %s;\n",
KeyNameText(keymap->ctx, keymap->key_aliases[i].alias),
KeyNameText(keymap->ctx, keymap->key_aliases[i].real));
write_buf(buf, "};\n\n");
return true;
}
static bool
write_types(struct xkb_keymap *keymap, struct buf *buf)
{
if (keymap->types_section_name)
write_buf(buf, "xkb_types \"%s\" {\n",
keymap->types_section_name);
else
write_buf(buf, "xkb_types {\n");
write_vmods(keymap, buf);
for (unsigned i = 0; i < keymap->num_types; i++) {
const struct xkb_key_type *type = &keymap->types[i];
write_buf(buf, "\ttype \"%s\" {\n",
xkb_atom_text(keymap->ctx, type->name));
write_buf(buf, "\t\tmodifiers= %s;\n",
ModMaskText(keymap->ctx, &keymap->mods, type->mods.mods));
for (unsigned j = 0; j < type->num_entries; j++) {
const char *str;
const struct xkb_key_type_entry *entry = &type->entries[j];
/*
* Printing level 1 entries is redundant, it's the default,
* unless there's preserve info.
*/
if (entry->level == 0 && entry->preserve.mods == 0)
continue;
str = ModMaskText(keymap->ctx, &keymap->mods, entry->mods.mods);
write_buf(buf, "\t\tmap[%s]= Level%u;\n",
str, entry->level + 1);
if (entry->preserve.mods)
write_buf(buf, "\t\tpreserve[%s]= %s;\n",
str, ModMaskText(keymap->ctx, &keymap->mods,
entry->preserve.mods));
}
for (xkb_level_index_t n = 0; n < type->num_level_names; n++)
if (type->level_names[n])
write_buf(buf, "\t\tlevel_name[Level%u]= \"%s\";\n", n + 1,
xkb_atom_text(keymap->ctx, type->level_names[n]));
write_buf(buf, "\t};\n");
}
write_buf(buf, "};\n\n");
return true;
}
static bool
write_led_map(struct xkb_keymap *keymap, struct buf *buf,
const struct xkb_led *led)
{
write_buf(buf, "\tindicator \"%s\" {\n",
xkb_atom_text(keymap->ctx, led->name));
if (led->which_groups) {
if (led->which_groups != XKB_STATE_LAYOUT_EFFECTIVE) {
write_buf(buf, "\t\twhichGroupState= %s;\n",
LedStateMaskText(keymap->ctx, led->which_groups));
}
write_buf(buf, "\t\tgroups= 0x%02x;\n",
led->groups);
}
if (led->which_mods) {
if (led->which_mods != XKB_STATE_MODS_EFFECTIVE) {
write_buf(buf, "\t\twhichModState= %s;\n",
LedStateMaskText(keymap->ctx, led->which_mods));
}
write_buf(buf, "\t\tmodifiers= %s;\n",
ModMaskText(keymap->ctx, &keymap->mods, led->mods.mods));
}
if (led->ctrls) {
write_buf(buf, "\t\tcontrols= %s;\n",
ControlMaskText(keymap->ctx, led->ctrls));
}
write_buf(buf, "\t};\n");
return true;
}
static const char *
affect_lock_text(enum xkb_action_flags flags)
{
switch (flags & (ACTION_LOCK_NO_LOCK | ACTION_LOCK_NO_UNLOCK)) {
case ACTION_LOCK_NO_UNLOCK:
return ",affect=lock";
case ACTION_LOCK_NO_LOCK:
return ",affect=unlock";
case ACTION_LOCK_NO_LOCK | ACTION_LOCK_NO_UNLOCK:
return ",affect=neither";
}
return "";
}
static bool
write_action(struct xkb_keymap *keymap, struct buf *buf,
const union xkb_action *action,
const char *prefix, const char *suffix)
{
const char *type;
const char *args = NULL;
if (!prefix)
prefix = "";
if (!suffix)
suffix = "";
type = ActionTypeText(action->type);
switch (action->type) {
case ACTION_TYPE_MOD_SET:
case ACTION_TYPE_MOD_LATCH:
case ACTION_TYPE_MOD_LOCK:
if (action->mods.flags & ACTION_MODS_LOOKUP_MODMAP)
args = "modMapMods";
else
args = ModMaskText(keymap->ctx, &keymap->mods,
action->mods.mods.mods);
write_buf(buf, "%s%s(modifiers=%s%s%s%s)%s", prefix, type, args,
(action->type != ACTION_TYPE_MOD_LOCK && (action->mods.flags & ACTION_LOCK_CLEAR)) ? ",clearLocks" : "",
(action->type != ACTION_TYPE_MOD_LOCK && (action->mods.flags & ACTION_LATCH_TO_LOCK)) ? ",latchToLock" : "",
(action->type == ACTION_TYPE_MOD_LOCK) ? affect_lock_text(action->mods.flags) : "",
suffix);
break;
case ACTION_TYPE_GROUP_SET:
case ACTION_TYPE_GROUP_LATCH:
case ACTION_TYPE_GROUP_LOCK:
write_buf(buf, "%s%s(group=%s%d%s%s)%s", prefix, type,
(!(action->group.flags & ACTION_ABSOLUTE_SWITCH) && action->group.group > 0) ? "+" : "",
(action->group.flags & ACTION_ABSOLUTE_SWITCH) ? action->group.group + 1 : action->group.group,
(action->type != ACTION_TYPE_GROUP_LOCK && (action->group.flags & ACTION_LOCK_CLEAR)) ? ",clearLocks" : "",
(action->type != ACTION_TYPE_GROUP_LOCK && (action->group.flags & ACTION_LATCH_TO_LOCK)) ? ",latchToLock" : "",
suffix);
break;
case ACTION_TYPE_TERMINATE:
write_buf(buf, "%s%s()%s", prefix, type, suffix);
break;
case ACTION_TYPE_PTR_MOVE:
write_buf(buf, "%s%s(x=%s%d,y=%s%d%s)%s", prefix, type,
(!(action->ptr.flags & ACTION_ABSOLUTE_X) && action->ptr.x >= 0) ? "+" : "",
action->ptr.x,
(!(action->ptr.flags & ACTION_ABSOLUTE_Y) && action->ptr.y >= 0) ? "+" : "",
action->ptr.y,
(action->ptr.flags & ACTION_ACCEL) ? "" : ",!accel",
suffix);
break;
case ACTION_TYPE_PTR_LOCK:
args = affect_lock_text(action->btn.flags);
/* fallthrough */
case ACTION_TYPE_PTR_BUTTON:
write_buf(buf, "%s%s(button=", prefix, type);
if (action->btn.button > 0 && action->btn.button <= 5)
write_buf(buf, "%d", action->btn.button);
else
write_buf(buf, "default");
if (action->btn.count)
write_buf(buf, ",count=%d", action->btn.count);
if (args)
write_buf(buf, "%s", args);
write_buf(buf, ")%s", suffix);
break;
case ACTION_TYPE_PTR_DEFAULT:
write_buf(buf, "%s%s(", prefix, type);
write_buf(buf, "affect=button,button=%s%d",
(!(action->dflt.flags & ACTION_ABSOLUTE_SWITCH) && action->dflt.value >= 0) ? "+" : "",
action->dflt.value);
write_buf(buf, ")%s", suffix);
break;
case ACTION_TYPE_SWITCH_VT:
write_buf(buf, "%s%s(screen=%s%d,%ssame)%s", prefix, type,
(!(action->screen.flags & ACTION_ABSOLUTE_SWITCH) && action->screen.screen >= 0) ? "+" : "",
action->screen.screen,
(action->screen.flags & ACTION_SAME_SCREEN) ? "" : "!",
suffix);
break;
case ACTION_TYPE_CTRL_SET:
case ACTION_TYPE_CTRL_LOCK:
write_buf(buf, "%s%s(controls=%s%s)%s", prefix, type,
ControlMaskText(keymap->ctx, action->ctrls.ctrls),
(action->type == ACTION_TYPE_CTRL_LOCK) ? affect_lock_text(action->ctrls.flags) : "",
suffix);
break;
case ACTION_TYPE_NONE:
write_buf(buf, "%sNoAction()%s", prefix, suffix);
break;
default:
write_buf(buf,
"%s%s(type=0x%02x,data[0]=0x%02x,data[1]=0x%02x,data[2]=0x%02x,data[3]=0x%02x,data[4]=0x%02x,data[5]=0x%02x,data[6]=0x%02x)%s",
prefix, type, action->type, action->priv.data[0],
action->priv.data[1], action->priv.data[2],
action->priv.data[3], action->priv.data[4],
action->priv.data[5], action->priv.data[6],
suffix);
break;
}
return true;
}
static bool
write_compat(struct xkb_keymap *keymap, struct buf *buf)
{
const struct xkb_led *led;
if (keymap->compat_section_name)
write_buf(buf, "xkb_compatibility \"%s\" {\n",
keymap->compat_section_name);
else
write_buf(buf, "xkb_compatibility {\n");
write_vmods(keymap, buf);
write_buf(buf, "\tinterpret.useModMapMods= AnyLevel;\n");
write_buf(buf, "\tinterpret.repeat= False;\n");
for (unsigned i = 0; i < keymap->num_sym_interprets; i++) {
const struct xkb_sym_interpret *si = &keymap->sym_interprets[i];
write_buf(buf, "\tinterpret %s+%s(%s) {\n",
si->sym ? KeysymText(keymap->ctx, si->sym) : "Any",
SIMatchText(si->match),
ModMaskText(keymap->ctx, &keymap->mods, si->mods));
if (si->virtual_mod != XKB_MOD_INVALID)
write_buf(buf, "\t\tvirtualModifier= %s;\n",
ModIndexText(keymap->ctx, &keymap->mods,
si->virtual_mod));
if (si->level_one_only)
write_buf(buf, "\t\tuseModMapMods=level1;\n");
if (si->repeat)
write_buf(buf, "\t\trepeat= True;\n");
write_action(keymap, buf, &si->action, "\t\taction= ", ";\n");
write_buf(buf, "\t};\n");
}
xkb_leds_foreach(led, keymap)
if (led->which_groups || led->groups || led->which_mods ||
led->mods.mods || led->ctrls)
write_led_map(keymap, buf, led);
write_buf(buf, "};\n\n");
return true;
}
static bool
write_keysyms(struct xkb_keymap *keymap, struct buf *buf,
const struct xkb_key *key, xkb_layout_index_t group)
{
for (xkb_level_index_t level = 0; level < XkbKeyNumLevels(key, group);
level++) {
const xkb_keysym_t *syms;
int num_syms;
if (level != 0)
write_buf(buf, ", ");
num_syms = xkb_keymap_key_get_syms_by_level(keymap, key->keycode,
group, level, &syms);
if (num_syms == 0) {
write_buf(buf, "%15s", "NoSymbol");
}
else if (num_syms == 1) {
write_buf(buf, "%15s", KeysymText(keymap->ctx, syms[0]));
}
else {
write_buf(buf, "{ ");
for (int s = 0; s < num_syms; s++) {
if (s != 0)
write_buf(buf, ", ");
write_buf(buf, "%s", KeysymText(keymap->ctx, syms[s]));
}
write_buf(buf, " }");
}
}
return true;
}
static bool
write_key(struct xkb_keymap *keymap, struct buf *buf,
const struct xkb_key *key)
{
xkb_layout_index_t group;
bool simple = true;
bool explicit_types = false;
bool multi_type = false;
bool show_actions;
write_buf(buf, "\tkey %-20s {", KeyNameText(keymap->ctx, key->name));
for (group = 0; group < key->num_groups; group++) {
if (key->groups[group].explicit_type)
explicit_types = true;
if (group != 0 && key->groups[group].type != key->groups[0].type)
multi_type = true;
}
if (explicit_types) {
const struct xkb_key_type *type;
simple = false;
if (multi_type) {
for (group = 0; group < key->num_groups; group++) {
if (!key->groups[group].explicit_type)
continue;
type = key->groups[group].type;
write_buf(buf, "\n\t\ttype[group%u]= \"%s\",",
group + 1,
xkb_atom_text(keymap->ctx, type->name));
}
}
else {
type = key->groups[0].type;
write_buf(buf, "\n\t\ttype= \"%s\",",
xkb_atom_text(keymap->ctx, type->name));
}
}
if (key->explicit & EXPLICIT_REPEAT) {
if (key->repeats)
write_buf(buf, "\n\t\trepeat= Yes,");
else
write_buf(buf, "\n\t\trepeat= No,");
simple = false;
}
if (key->vmodmap && (key->explicit & EXPLICIT_VMODMAP))
write_buf(buf, "\n\t\tvirtualMods= %s,",
ModMaskText(keymap->ctx, &keymap->mods, key->vmodmap));
switch (key->out_of_range_group_action) {
case RANGE_SATURATE:
write_buf(buf, "\n\t\tgroupsClamp,");
break;
case RANGE_REDIRECT:
write_buf(buf, "\n\t\tgroupsRedirect= Group%u,",
key->out_of_range_group_number + 1);
break;
default:
break;
}
show_actions = (key->explicit & EXPLICIT_INTERP);
if (key->num_groups > 1 || show_actions)
simple = false;
if (simple) {
write_buf(buf, "\t[ ");
if (!write_keysyms(keymap, buf, key, 0))
return false;
write_buf(buf, " ] };\n");
}
else {
xkb_level_index_t level;
for (group = 0; group < key->num_groups; group++) {
if (group != 0)
write_buf(buf, ",");
write_buf(buf, "\n\t\tsymbols[Group%u]= [ ", group + 1);
if (!write_keysyms(keymap, buf, key, group))
return false;
write_buf(buf, " ]");
if (show_actions) {
write_buf(buf, ",\n\t\tactions[Group%u]= [ ", group + 1);
for (level = 0; level < XkbKeyNumLevels(key, group); level++) {
if (level != 0)
write_buf(buf, ", ");
write_action(keymap, buf,
&key->groups[group].levels[level].action,
NULL, NULL);
}
write_buf(buf, " ]");
}
}
write_buf(buf, "\n\t};\n");
}
return true;
}
static bool
write_symbols(struct xkb_keymap *keymap, struct buf *buf)
{
const struct xkb_key *key;
xkb_layout_index_t group;
xkb_mod_index_t i;
const struct xkb_mod *mod;
if (keymap->symbols_section_name)
write_buf(buf, "xkb_symbols \"%s\" {\n",
keymap->symbols_section_name);
else
write_buf(buf, "xkb_symbols {\n");
for (group = 0; group < keymap->num_group_names; group++)
if (keymap->group_names[group])
write_buf(buf,
"\tname[group%u]=\"%s\";\n", group + 1,
xkb_atom_text(keymap->ctx, keymap->group_names[group]));
if (group > 0)
write_buf(buf, "\n");
xkb_keys_foreach(key, keymap)
if (key->num_groups > 0)
write_key(keymap, buf, key);
xkb_mods_enumerate(i, mod, &keymap->mods) {
bool had_any = false;
xkb_keys_foreach(key, keymap) {
if (key->modmap & (1u << i)) {
if (!had_any)
write_buf(buf, "\tmodifier_map %s { ",
xkb_atom_text(keymap->ctx, mod->name));
write_buf(buf, "%s%s",
had_any ? ", " : "",
KeyNameText(keymap->ctx, key->name));
had_any = true;
}
}
if (had_any)
write_buf(buf, " };\n");
}
write_buf(buf, "};\n\n");
return true;
}
static bool
write_keymap(struct xkb_keymap *keymap, struct buf *buf)
{
return (check_write_buf(buf, "xkb_keymap {\n") &&
write_keycodes(keymap, buf) &&
write_types(keymap, buf) &&
write_compat(keymap, buf) &&
write_symbols(keymap, buf) &&
check_write_buf(buf, "};\n"));
}
char *
text_v1_keymap_get_as_string(struct xkb_keymap *keymap)
{
struct buf buf = { NULL, 0, 0 };
if (!write_keymap(keymap, &buf)) {
free(buf.buf);
return NULL;
}
return buf.buf;
}

View File

@ -1,348 +0,0 @@
/* ANSI-C code produced by gperf version 3.0.4 */
/* Command-line: gperf */
/* Computed positions: -k'1-2,5' */
#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
&& ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
&& (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
&& ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
&& ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
&& ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
&& ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
&& ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
&& ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
&& ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
&& ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
&& ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
&& ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
&& ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
&& ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
&& ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
&& ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
&& ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
&& ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
&& ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
&& ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
&& ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
&& ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
/* The character set is not based on ISO-646. */
#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
#endif
#include "xkbcomp-priv.h"
#include "parser-priv.h"
static unsigned int
keyword_gperf_hash(const char *str, unsigned int len);
static const struct keyword_tok *
keyword_gperf_lookup(const char *str, unsigned int len);
struct keyword_tok { int name; int tok; };
#include <string.h>
/* maximum key range = 70, duplicates = 0 */
#ifndef GPERF_DOWNCASE
#define GPERF_DOWNCASE 1
static unsigned char gperf_downcase[256] =
{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
60, 61, 62, 63, 64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106,
107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121,
122, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134,
135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164,
165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179,
180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194,
195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209,
210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224,
225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254,
255
};
#endif
#ifndef GPERF_CASE_STRCMP
#define GPERF_CASE_STRCMP 1
static int
gperf_case_strcmp (register const char *s1, register const char *s2)
{
for (;;)
{
unsigned char c1 = gperf_downcase[(unsigned char)*s1++];
unsigned char c2 = gperf_downcase[(unsigned char)*s2++];
if (c1 != 0 && c1 == c2)
continue;
return (int)c1 - (int)c2;
}
}
#endif
#ifdef __GNUC__
__inline
#else
#ifdef __cplusplus
inline
#endif
#endif
static unsigned int
keyword_gperf_hash (register const char *str, register unsigned int len)
{
static const unsigned char asso_values[] =
{
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
73, 73, 73, 73, 73, 0, 73, 5, 36, 0,
10, 1, 15, 15, 73, 0, 10, 20, 35, 20,
50, 73, 10, 10, 5, 0, 15, 73, 0, 15,
73, 73, 73, 73, 73, 73, 73, 0, 73, 5,
36, 0, 10, 1, 15, 15, 73, 0, 10, 20,
35, 20, 50, 73, 10, 10, 5, 0, 15, 73,
0, 15, 73, 73, 73, 73, 73, 73, 73, 73,
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
73, 73, 73, 73, 73, 73
};
register int hval = len;
switch (hval)
{
default:
hval += asso_values[(unsigned char)str[4]];
/*FALLTHROUGH*/
case 4:
case 3:
case 2:
hval += asso_values[(unsigned char)str[1]];
/*FALLTHROUGH*/
case 1:
hval += asso_values[(unsigned char)str[0]];
break;
}
return hval;
}
struct stringpool_t
{
char stringpool_str3[sizeof("key")];
char stringpool_str4[sizeof("keys")];
char stringpool_str7[sizeof("augment")];
char stringpool_str9[sizeof("text")];
char stringpool_str10[sizeof("xkb_keymap")];
char stringpool_str11[sizeof("keypad_keys")];
char stringpool_str12[sizeof("xkb_keycodes")];
char stringpool_str13[sizeof("xkb_geometry")];
char stringpool_str14[sizeof("xkb_types")];
char stringpool_str15[sizeof("xkb_compat")];
char stringpool_str17[sizeof("replace")];
char stringpool_str19[sizeof("xkb_compat_map")];
char stringpool_str20[sizeof("xkb_layout")];
char stringpool_str21[sizeof("xkb_symbols")];
char stringpool_str22[sizeof("xkb_compatibility")];
char stringpool_str23[sizeof("xkb_semantics")];
char stringpool_str24[sizeof("type")];
char stringpool_str25[sizeof("alias")];
char stringpool_str26[sizeof("xkb_compatibility_map")];
char stringpool_str27[sizeof("alphanumeric_keys")];
char stringpool_str28[sizeof("function_keys")];
char stringpool_str29[sizeof("alternate")];
char stringpool_str30[sizeof("shape")];
char stringpool_str31[sizeof("action")];
char stringpool_str32[sizeof("section")];
char stringpool_str33[sizeof("row")];
char stringpool_str34[sizeof("logo")];
char stringpool_str35[sizeof("alternate_group")];
char stringpool_str36[sizeof("hidden")];
char stringpool_str37[sizeof("virtual")];
char stringpool_str42[sizeof("outline")];
char stringpool_str43[sizeof("default")];
char stringpool_str46[sizeof("modmap")];
char stringpool_str47[sizeof("virtual_modifiers")];
char stringpool_str52[sizeof("overlay")];
char stringpool_str53[sizeof("override")];
char stringpool_str57[sizeof("include")];
char stringpool_str62[sizeof("modifier_map")];
char stringpool_str63[sizeof("modifier_keys")];
char stringpool_str64[sizeof("indicator")];
char stringpool_str66[sizeof("group")];
char stringpool_str67[sizeof("mod_map")];
char stringpool_str69[sizeof("interpret")];
char stringpool_str71[sizeof("solid")];
char stringpool_str72[sizeof("partial")];
};
static const struct stringpool_t stringpool_contents =
{
"key",
"keys",
"augment",
"text",
"xkb_keymap",
"keypad_keys",
"xkb_keycodes",
"xkb_geometry",
"xkb_types",
"xkb_compat",
"replace",
"xkb_compat_map",
"xkb_layout",
"xkb_symbols",
"xkb_compatibility",
"xkb_semantics",
"type",
"alias",
"xkb_compatibility_map",
"alphanumeric_keys",
"function_keys",
"alternate",
"shape",
"action",
"section",
"row",
"logo",
"alternate_group",
"hidden",
"virtual",
"outline",
"default",
"modmap",
"virtual_modifiers",
"overlay",
"override",
"include",
"modifier_map",
"modifier_keys",
"indicator",
"group",
"mod_map",
"interpret",
"solid",
"partial"
};
#define stringpool ((const char *) &stringpool_contents)
#ifdef __GNUC__
__inline
#if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__
__attribute__ ((__gnu_inline__))
#endif
#endif
const struct keyword_tok *
keyword_gperf_lookup (register const char *str, register unsigned int len)
{
enum
{
TOTAL_KEYWORDS = 45,
MIN_WORD_LENGTH = 3,
MAX_WORD_LENGTH = 21,
MIN_HASH_VALUE = 3,
MAX_HASH_VALUE = 72
};
static const struct keyword_tok wordlist[] =
{
{-1}, {-1}, {-1},
{(int)(long)&((struct stringpool_t *)0)->stringpool_str3, KEY},
{(int)(long)&((struct stringpool_t *)0)->stringpool_str4, KEYS},
{-1}, {-1},
{(int)(long)&((struct stringpool_t *)0)->stringpool_str7, AUGMENT},
{-1},
{(int)(long)&((struct stringpool_t *)0)->stringpool_str9, TEXT},
{(int)(long)&((struct stringpool_t *)0)->stringpool_str10, XKB_KEYMAP},
{(int)(long)&((struct stringpool_t *)0)->stringpool_str11, KEYPAD_KEYS},
{(int)(long)&((struct stringpool_t *)0)->stringpool_str12, XKB_KEYCODES},
{(int)(long)&((struct stringpool_t *)0)->stringpool_str13, XKB_GEOMETRY},
{(int)(long)&((struct stringpool_t *)0)->stringpool_str14, XKB_TYPES},
{(int)(long)&((struct stringpool_t *)0)->stringpool_str15, XKB_COMPATMAP},
{-1},
{(int)(long)&((struct stringpool_t *)0)->stringpool_str17, REPLACE},
{-1},
{(int)(long)&((struct stringpool_t *)0)->stringpool_str19, XKB_COMPATMAP},
{(int)(long)&((struct stringpool_t *)0)->stringpool_str20, XKB_LAYOUT},
{(int)(long)&((struct stringpool_t *)0)->stringpool_str21, XKB_SYMBOLS},
{(int)(long)&((struct stringpool_t *)0)->stringpool_str22, XKB_COMPATMAP},
{(int)(long)&((struct stringpool_t *)0)->stringpool_str23, XKB_SEMANTICS},
{(int)(long)&((struct stringpool_t *)0)->stringpool_str24, TYPE},
{(int)(long)&((struct stringpool_t *)0)->stringpool_str25, ALIAS},
{(int)(long)&((struct stringpool_t *)0)->stringpool_str26, XKB_COMPATMAP},
{(int)(long)&((struct stringpool_t *)0)->stringpool_str27, ALPHANUMERIC_KEYS},
{(int)(long)&((struct stringpool_t *)0)->stringpool_str28, FUNCTION_KEYS},
{(int)(long)&((struct stringpool_t *)0)->stringpool_str29, ALTERNATE},
{(int)(long)&((struct stringpool_t *)0)->stringpool_str30, SHAPE},
{(int)(long)&((struct stringpool_t *)0)->stringpool_str31, ACTION_TOK},
{(int)(long)&((struct stringpool_t *)0)->stringpool_str32, SECTION},
{(int)(long)&((struct stringpool_t *)0)->stringpool_str33, ROW},
{(int)(long)&((struct stringpool_t *)0)->stringpool_str34, LOGO},
{(int)(long)&((struct stringpool_t *)0)->stringpool_str35, ALTERNATE_GROUP},
{(int)(long)&((struct stringpool_t *)0)->stringpool_str36, HIDDEN},
{(int)(long)&((struct stringpool_t *)0)->stringpool_str37, VIRTUAL},
{-1}, {-1}, {-1}, {-1},
{(int)(long)&((struct stringpool_t *)0)->stringpool_str42, OUTLINE},
{(int)(long)&((struct stringpool_t *)0)->stringpool_str43, DEFAULT},
{-1}, {-1},
{(int)(long)&((struct stringpool_t *)0)->stringpool_str46, MODIFIER_MAP},
{(int)(long)&((struct stringpool_t *)0)->stringpool_str47, VIRTUAL_MODS},
{-1}, {-1}, {-1}, {-1},
{(int)(long)&((struct stringpool_t *)0)->stringpool_str52, OVERLAY},
{(int)(long)&((struct stringpool_t *)0)->stringpool_str53, OVERRIDE},
{-1}, {-1}, {-1},
{(int)(long)&((struct stringpool_t *)0)->stringpool_str57, INCLUDE},
{-1}, {-1}, {-1}, {-1},
{(int)(long)&((struct stringpool_t *)0)->stringpool_str62, MODIFIER_MAP},
{(int)(long)&((struct stringpool_t *)0)->stringpool_str63, MODIFIER_KEYS},
{(int)(long)&((struct stringpool_t *)0)->stringpool_str64, INDICATOR},
{-1},
{(int)(long)&((struct stringpool_t *)0)->stringpool_str66, GROUP},
{(int)(long)&((struct stringpool_t *)0)->stringpool_str67, MODIFIER_MAP},
{-1},
{(int)(long)&((struct stringpool_t *)0)->stringpool_str69, INTERPRET},
{-1},
{(int)(long)&((struct stringpool_t *)0)->stringpool_str71, SOLID},
{(int)(long)&((struct stringpool_t *)0)->stringpool_str72, PARTIAL}
};
if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
{
register int key = keyword_gperf_hash (str, len);
if (key <= MAX_HASH_VALUE && key >= 0)
{
register int o = wordlist[key].name;
if (o >= 0)
{
register const char *s = o + stringpool;
if ((((unsigned char)*str ^ (unsigned char)*s) & ~32) == 0 && !gperf_case_strcmp (str, s))
return &wordlist[key];
}
}
}
return 0;
}
int
keyword_to_token(const char *string, unsigned int len)
{
const struct keyword_tok *kt = keyword_gperf_lookup(string, len);
if (!kt)
return -1;
return kt->tok;
}

View File

@ -1,44 +0,0 @@
/************************************************************
* Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting
* documentation, and that the name of Silicon Graphics not be
* used in advertising or publicity pertaining to distribution
* of the software without specific prior written permission.
* Silicon Graphics makes no representation about the suitability
* of this software for any purpose. It is provided "as is"
* without any express or implied warranty.
*
* SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
* GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
********************************************************/
#ifndef XKBCOMP_PARSER_PRIV_H
#define XKBCOMP_PARSER_PRIV_H
struct parser_param;
struct scanner;
#include "parser.h"
int
_xkbcommon_lex(YYSTYPE *yylval, struct scanner *scanner);
XkbFile *
parse(struct xkb_context *ctx, struct scanner *scanner, const char *map);
int
keyword_to_token(const char *string, unsigned int len);
#endif

View File

@ -1,157 +0,0 @@
/* A Bison parser, made by GNU Bison 3.0.4. */
/* Bison interface for Yacc-like parsers in C
Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* As a special exception, you may create a larger work that contains
part or all of the Bison parser skeleton and distribute that work
under terms of your choice, so long as that work isn't itself a
parser generator using the skeleton or a modified version thereof
as a parser skeleton. Alternatively, if you modify or redistribute
the parser skeleton itself, you may (at your option) remove this
special exception, which will cause the skeleton and the resulting
Bison output files to be licensed under the GNU General Public
License without this special exception.
This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */
#ifndef YY__XKBCOMMON_XKBCOMMON_INTERNAL_STA_PARSER_H_INCLUDED
# define YY__XKBCOMMON_XKBCOMMON_INTERNAL_STA_PARSER_H_INCLUDED
/* Debug traces. */
#ifndef YYDEBUG
# define YYDEBUG 0
#endif
#if YYDEBUG
extern int _xkbcommon_debug;
#endif
/* Token type. */
#ifndef YYTOKENTYPE
# define YYTOKENTYPE
enum yytokentype
{
END_OF_FILE = 0,
ERROR_TOK = 255,
XKB_KEYMAP = 1,
XKB_KEYCODES = 2,
XKB_TYPES = 3,
XKB_SYMBOLS = 4,
XKB_COMPATMAP = 5,
XKB_GEOMETRY = 6,
XKB_SEMANTICS = 7,
XKB_LAYOUT = 8,
INCLUDE = 10,
OVERRIDE = 11,
AUGMENT = 12,
REPLACE = 13,
ALTERNATE = 14,
VIRTUAL_MODS = 20,
TYPE = 21,
INTERPRET = 22,
ACTION_TOK = 23,
KEY = 24,
ALIAS = 25,
GROUP = 26,
MODIFIER_MAP = 27,
INDICATOR = 28,
SHAPE = 29,
KEYS = 30,
ROW = 31,
SECTION = 32,
OVERLAY = 33,
TEXT = 34,
OUTLINE = 35,
SOLID = 36,
LOGO = 37,
VIRTUAL = 38,
EQUALS = 40,
PLUS = 41,
MINUS = 42,
DIVIDE = 43,
TIMES = 44,
OBRACE = 45,
CBRACE = 46,
OPAREN = 47,
CPAREN = 48,
OBRACKET = 49,
CBRACKET = 50,
DOT = 51,
COMMA = 52,
SEMI = 53,
EXCLAM = 54,
INVERT = 55,
STRING = 60,
INTEGER = 61,
FLOAT = 62,
IDENT = 63,
KEYNAME = 64,
PARTIAL = 70,
DEFAULT = 71,
HIDDEN = 72,
ALPHANUMERIC_KEYS = 73,
MODIFIER_KEYS = 74,
KEYPAD_KEYS = 75,
FUNCTION_KEYS = 76,
ALTERNATE_GROUP = 77
};
#endif
/* Value type. */
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
union YYSTYPE
{
#line 162 "../src/xkbcomp/parser.y" /* yacc.c:1909 */
int ival;
int64_t num;
enum xkb_file_type file_type;
char *str;
xkb_atom_t atom;
enum merge_mode merge;
enum xkb_map_flags mapFlags;
xkb_keysym_t keysym;
ParseCommon *any;
ExprDef *expr;
VarDef *var;
VModDef *vmod;
InterpDef *interp;
KeyTypeDef *keyType;
SymbolsDef *syms;
ModMapDef *modMask;
GroupCompatDef *groupCompat;
LedMapDef *ledMap;
LedNameDef *ledName;
KeycodeDef *keyCode;
KeyAliasDef *keyAlias;
void *geom;
XkbFile *file;
#line 146 "xkbcommon-internal@sta/parser.h" /* yacc.c:1909 */
};
typedef union YYSTYPE YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1
# define YYSTYPE_IS_DECLARED 1
#endif
int _xkbcommon_parse (struct parser_param *param);
#endif /* !YY__XKBCOMMON_XKBCOMMON_INTERNAL_STA_PARSER_H_INCLUDED */

File diff suppressed because it is too large Load Diff

View File

@ -1,32 +0,0 @@
/*
* Copyright © 2009 Dan Nicholson
*
* 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 (including the next
* paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
*/
#ifndef XKBCOMP_RULES_H
#define XKBCOMP_RULES_H
bool
xkb_components_from_rules(struct xkb_context *ctx,
const struct xkb_rule_names *rmlvo,
struct xkb_component_names *out);
#endif

View File

@ -1,208 +0,0 @@
/*
* Copyright © 2012 Ran Benita <ran234@gmail.com>
*
* 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 (including the next
* paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
*/
#include "xkbcomp-priv.h"
#include "parser-priv.h"
#include "scanner-utils.h"
static bool
number(struct scanner *s, int64_t *out, int *out_tok)
{
bool is_float = false, is_hex = false;
const char *start = s->s + s->pos;
char *end;
if (lit(s, "0x")) {
while (is_xdigit(peek(s))) next(s);
is_hex = true;
}
else {
while (is_digit(peek(s))) next(s);
is_float = chr(s, '.');
while (is_digit(peek(s))) next(s);
}
if (s->s + s->pos == start)
return false;
errno = 0;
if (is_hex)
*out = strtoul(start, &end, 16);
else if (is_float)
*out = strtod(start, &end);
else
*out = strtoul(start, &end, 10);
if (errno != 0 || s->s + s->pos != end)
*out_tok = ERROR_TOK;
else
*out_tok = (is_float ? FLOAT : INTEGER);
return true;
}
int
_xkbcommon_lex(YYSTYPE *yylval, struct scanner *s)
{
int tok;
skip_more_whitespace_and_comments:
/* Skip spaces. */
while (is_space(peek(s))) next(s);
/* Skip comments. */
if (lit(s, "//") || chr(s, '#')) {
skip_to_eol(s);
goto skip_more_whitespace_and_comments;
}
/* See if we're done. */
if (eof(s)) return END_OF_FILE;
/* New token. */
s->token_line = s->line;
s->token_column = s->column;
s->buf_pos = 0;
/* String literal. */
if (chr(s, '\"')) {
while (!eof(s) && !eol(s) && peek(s) != '\"') {
if (chr(s, '\\')) {
uint8_t o;
if (chr(s, '\\')) buf_append(s, '\\');
else if (chr(s, 'n')) buf_append(s, '\n');
else if (chr(s, 't')) buf_append(s, '\t');
else if (chr(s, 'r')) buf_append(s, '\r');
else if (chr(s, 'b')) buf_append(s, '\b');
else if (chr(s, 'f')) buf_append(s, '\f');
else if (chr(s, 'v')) buf_append(s, '\v');
else if (chr(s, 'e')) buf_append(s, '\033');
else if (oct(s, &o)) buf_append(s, (char) o);
else {
scanner_warn(s, "unknown escape sequence in string literal");
/* Ignore. */
}
} else {
buf_append(s, next(s));
}
}
if (!buf_append(s, '\0') || !chr(s, '\"')) {
scanner_err(s, "unterminated string literal");
return ERROR_TOK;
}
yylval->str = strdup(s->buf);
if (!yylval->str)
return ERROR_TOK;
return STRING;
}
/* Key name literal. */
if (chr(s, '<')) {
while (is_graph(peek(s)) && peek(s) != '>')
buf_append(s, next(s));
if (!buf_append(s, '\0') || !chr(s, '>')) {
scanner_err(s, "unterminated key name literal");
return ERROR_TOK;
}
/* Empty key name literals are allowed. */
yylval->atom = xkb_atom_intern(s->ctx, s->buf, s->buf_pos - 1);
return KEYNAME;
}
/* Operators and punctuation. */
if (chr(s, ';')) return SEMI;
if (chr(s, '{')) return OBRACE;
if (chr(s, '}')) return CBRACE;
if (chr(s, '=')) return EQUALS;
if (chr(s, '[')) return OBRACKET;
if (chr(s, ']')) return CBRACKET;
if (chr(s, '(')) return OPAREN;
if (chr(s, ')')) return CPAREN;
if (chr(s, '.')) return DOT;
if (chr(s, ',')) return COMMA;
if (chr(s, '+')) return PLUS;
if (chr(s, '-')) return MINUS;
if (chr(s, '*')) return TIMES;
if (chr(s, '/')) return DIVIDE;
if (chr(s, '!')) return EXCLAM;
if (chr(s, '~')) return INVERT;
/* Identifier. */
if (is_alpha(peek(s)) || peek(s) == '_') {
s->buf_pos = 0;
while (is_alnum(peek(s)) || peek(s) == '_')
buf_append(s, next(s));
if (!buf_append(s, '\0')) {
scanner_err(s, "identifier too long");
return ERROR_TOK;
}
/* Keyword. */
tok = keyword_to_token(s->buf, s->buf_pos - 1);
if (tok != -1) return tok;
yylval->str = strdup(s->buf);
if (!yylval->str)
return ERROR_TOK;
return IDENT;
}
/* Number literal (hexadecimal / decimal / float). */
if (number(s, &yylval->num, &tok)) {
if (tok == ERROR_TOK) {
scanner_err(s, "malformed number literal");
return ERROR_TOK;
}
return tok;
}
scanner_err(s, "unrecognized token");
return ERROR_TOK;
}
XkbFile *
XkbParseString(struct xkb_context *ctx, const char *string, size_t len,
const char *file_name, const char *map)
{
struct scanner scanner;
scanner_init(&scanner, ctx, string, len, file_name, NULL);
return parse(ctx, &scanner, map);
}
XkbFile *
XkbParseFile(struct xkb_context *ctx, FILE *file,
const char *file_name, const char *map)
{
bool ok;
XkbFile *xkb_file;
char *string;
size_t size;
ok = map_file(file, &string, &size);
if (!ok) {
log_err(ctx, "Couldn't read XKB file %s: %s\n",
file_name, strerror(errno));
return NULL;
}
xkb_file = XkbParseString(ctx, string, size, file_name, map);
unmap_file(string, size);
return xkb_file;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,742 +0,0 @@
/************************************************************
* Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting
* documentation, and that the name of Silicon Graphics not be
* used in advertising or publicity pertaining to distribution
* of the software without specific prior written permission.
* Silicon Graphics makes no representation about the suitability
* of this software for any purpose. It is provided "as is"
* without any express or implied warranty.
*
* SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
* GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
********************************************************/
#include "xkbcomp-priv.h"
#include "text.h"
#include "vmod.h"
#include "expr.h"
#include "include.h"
enum type_field {
TYPE_FIELD_MASK = (1 << 0),
TYPE_FIELD_MAP = (1 << 1),
TYPE_FIELD_PRESERVE = (1 << 2),
TYPE_FIELD_LEVEL_NAME = (1 << 3),
};
typedef struct {
enum type_field defined;
enum merge_mode merge;
xkb_atom_t name;
xkb_mod_mask_t mods;
xkb_level_index_t num_levels;
darray(struct xkb_key_type_entry) entries;
darray(xkb_atom_t) level_names;
} KeyTypeInfo;
typedef struct {
char *name;
int errorCount;
darray(KeyTypeInfo) types;
struct xkb_mod_set mods;
struct xkb_context *ctx;
} KeyTypesInfo;
/***====================================================================***/
static inline const char *
MapEntryTxt(KeyTypesInfo *info, struct xkb_key_type_entry *entry)
{
return ModMaskText(info->ctx, &info->mods, entry->mods.mods);
}
static inline const char *
TypeTxt(KeyTypesInfo *info, KeyTypeInfo *type)
{
return xkb_atom_text(info->ctx, type->name);
}
static inline const char *
TypeMaskTxt(KeyTypesInfo *info, KeyTypeInfo *type)
{
return ModMaskText(info->ctx, &info->mods, type->mods);
}
static inline bool
ReportTypeShouldBeArray(KeyTypesInfo *info, KeyTypeInfo *type,
const char *field)
{
return ReportShouldBeArray(info->ctx, "key type", field,
TypeTxt(info, type));
}
static inline bool
ReportTypeBadType(KeyTypesInfo *info, KeyTypeInfo *type,
const char *field, const char *wanted)
{
return ReportBadType(info->ctx, "key type", field,
TypeTxt(info, type), wanted);
}
/***====================================================================***/
static void
InitKeyTypesInfo(KeyTypesInfo *info, struct xkb_context *ctx,
const struct xkb_mod_set *mods)
{
memset(info, 0, sizeof(*info));
info->ctx = ctx;
info->mods = *mods;
}
static void
ClearKeyTypeInfo(KeyTypeInfo *type)
{
darray_free(type->entries);
darray_free(type->level_names);
}
static void
ClearKeyTypesInfo(KeyTypesInfo *info)
{
free(info->name);
darray_free(info->types);
}
static KeyTypeInfo *
FindMatchingKeyType(KeyTypesInfo *info, xkb_atom_t name)
{
KeyTypeInfo *old;
darray_foreach(old, info->types)
if (old->name == name)
return old;
return NULL;
}
static bool
AddKeyType(KeyTypesInfo *info, KeyTypeInfo *new, bool same_file)
{
KeyTypeInfo *old;
const int verbosity = xkb_context_get_log_verbosity(info->ctx);
old = FindMatchingKeyType(info, new->name);
if (old) {
if (new->merge == MERGE_REPLACE || new->merge == MERGE_OVERRIDE) {
if ((same_file && verbosity > 0) || verbosity > 9) {
log_warn(info->ctx,
"Multiple definitions of the %s key type; "
"Earlier definition ignored\n",
xkb_atom_text(info->ctx, new->name));
}
ClearKeyTypeInfo(old);
*old = *new;
darray_init(new->entries);
darray_init(new->level_names);
return true;
}
if (same_file)
log_vrb(info->ctx, 4,
"Multiple definitions of the %s key type; "
"Later definition ignored\n",
xkb_atom_text(info->ctx, new->name));
ClearKeyTypeInfo(new);
return true;
}
darray_append(info->types, *new);
return true;
}
/***====================================================================***/
static void
MergeIncludedKeyTypes(KeyTypesInfo *into, KeyTypesInfo *from,
enum merge_mode merge)
{
if (from->errorCount > 0) {
into->errorCount += from->errorCount;
return;
}
into->mods = from->mods;
if (into->name == NULL) {
into->name = from->name;
from->name = NULL;
}
if (darray_empty(into->types)) {
into->types = from->types;
darray_init(from->types);
}
else {
KeyTypeInfo *type;
darray_foreach(type, from->types) {
type->merge = (merge == MERGE_DEFAULT ? type->merge : merge);
if (!AddKeyType(into, type, false))
into->errorCount++;
}
}
}
static void
HandleKeyTypesFile(KeyTypesInfo *info, XkbFile *file, enum merge_mode merge);
static bool
HandleIncludeKeyTypes(KeyTypesInfo *info, IncludeStmt *include)
{
KeyTypesInfo included;
InitKeyTypesInfo(&included, info->ctx, &info->mods);
included.name = include->stmt;
include->stmt = NULL;
for (IncludeStmt *stmt = include; stmt; stmt = stmt->next_incl) {
KeyTypesInfo next_incl;
XkbFile *file;
file = ProcessIncludeFile(info->ctx, stmt, FILE_TYPE_TYPES);
if (!file) {
info->errorCount += 10;
ClearKeyTypesInfo(&included);
return false;
}
InitKeyTypesInfo(&next_incl, info->ctx, &included.mods);
HandleKeyTypesFile(&next_incl, file, stmt->merge);
MergeIncludedKeyTypes(&included, &next_incl, stmt->merge);
ClearKeyTypesInfo(&next_incl);
FreeXkbFile(file);
}
MergeIncludedKeyTypes(info, &included, include->merge);
ClearKeyTypesInfo(&included);
return (info->errorCount == 0);
}
/***====================================================================***/
static bool
SetModifiers(KeyTypesInfo *info, KeyTypeInfo *type, ExprDef *arrayNdx,
ExprDef *value)
{
xkb_mod_mask_t mods;
if (arrayNdx)
log_warn(info->ctx,
"The modifiers field of a key type is not an array; "
"Illegal array subscript ignored\n");
if (!ExprResolveModMask(info->ctx, value, MOD_BOTH, &info->mods, &mods)) {
log_err(info->ctx,
"Key type mask field must be a modifier mask; "
"Key type definition ignored\n");
return false;
}
if (type->defined & TYPE_FIELD_MASK) {
log_warn(info->ctx,
"Multiple modifier mask definitions for key type %s; "
"Using %s, ignoring %s\n",
xkb_atom_text(info->ctx, type->name),
TypeMaskTxt(info, type),
ModMaskText(info->ctx, &info->mods, mods));
return false;
}
type->mods = mods;
return true;
}
/***====================================================================***/
static struct xkb_key_type_entry *
FindMatchingMapEntry(KeyTypeInfo *type, xkb_mod_mask_t mods)
{
struct xkb_key_type_entry *entry;
darray_foreach(entry, type->entries)
if (entry->mods.mods == mods)
return entry;
return NULL;
}
static bool
AddMapEntry(KeyTypesInfo *info, KeyTypeInfo *type,
struct xkb_key_type_entry *new, bool clobber, bool report)
{
struct xkb_key_type_entry *old;
old = FindMatchingMapEntry(type, new->mods.mods);
if (old) {
if (report && old->level != new->level) {
log_warn(info->ctx,
"Multiple map entries for %s in %s; "
"Using %d, ignoring %d\n",
MapEntryTxt(info, new), TypeTxt(info, type),
(clobber ? new->level : old->level) + 1,
(clobber ? old->level : new->level) + 1);
}
else {
log_vrb(info->ctx, 10,
"Multiple occurrences of map[%s]= %d in %s; Ignored\n",
MapEntryTxt(info, new), new->level + 1,
TypeTxt(info, type));
return true;
}
if (clobber) {
if (new->level >= type->num_levels)
type->num_levels = new->level + 1;
old->level = new->level;
}
return true;
}
if (new->level >= type->num_levels)
type->num_levels = new->level + 1;
darray_append(type->entries, *new);
return true;
}
static bool
SetMapEntry(KeyTypesInfo *info, KeyTypeInfo *type, ExprDef *arrayNdx,
ExprDef *value)
{
struct xkb_key_type_entry entry;
if (arrayNdx == NULL)
return ReportTypeShouldBeArray(info, type, "map entry");
if (!ExprResolveModMask(info->ctx, arrayNdx, MOD_BOTH, &info->mods,
&entry.mods.mods))
return ReportTypeBadType(info, type, "map entry", "modifier mask");
if (entry.mods.mods & (~type->mods)) {
log_vrb(info->ctx, 1,
"Map entry for unused modifiers in %s; "
"Using %s instead of %s\n",
TypeTxt(info, type),
ModMaskText(info->ctx, &info->mods,
entry.mods.mods & type->mods),
MapEntryTxt(info, &entry));
entry.mods.mods &= type->mods;
}
if (!ExprResolveLevel(info->ctx, value, &entry.level)) {
log_err(info->ctx,
"Level specifications in a key type must be integer; "
"Ignoring malformed level specification\n");
return false;
}
entry.preserve.mods = 0;
return AddMapEntry(info, type, &entry, true, true);
}
/***====================================================================***/
static bool
AddPreserve(KeyTypesInfo *info, KeyTypeInfo *type,
xkb_mod_mask_t mods, xkb_mod_mask_t preserve_mods)
{
struct xkb_key_type_entry *entry;
struct xkb_key_type_entry new;
darray_foreach(entry, type->entries) {
if (entry->mods.mods != mods)
continue;
/* Map exists without previous preserve (or "None"); override. */
if (entry->preserve.mods == 0) {
entry->preserve.mods = preserve_mods;
return true;
}
/* Map exists with same preserve; do nothing. */
if (entry->preserve.mods == preserve_mods) {
log_vrb(info->ctx, 10,
"Identical definitions for preserve[%s] in %s; "
"Ignored\n",
ModMaskText(info->ctx, &info->mods, mods),
TypeTxt(info, type));
return true;
}
/* Map exists with different preserve; latter wins. */
log_vrb(info->ctx, 1,
"Multiple definitions for preserve[%s] in %s; "
"Using %s, ignoring %s\n",
ModMaskText(info->ctx, &info->mods, mods),
TypeTxt(info, type),
ModMaskText(info->ctx, &info->mods, preserve_mods),
ModMaskText(info->ctx, &info->mods, entry->preserve.mods));
entry->preserve.mods = preserve_mods;
return true;
}
/*
* Map does not exist, i.e. preserve[] came before map[].
* Create a map with the specified mask mapping to Level1. The level
* may be overridden later with an explicit map[] statement.
*/
new.level = 0;
new.mods.mods = mods;
new.preserve.mods = preserve_mods;
darray_append(type->entries, new);
return true;
}
static bool
SetPreserve(KeyTypesInfo *info, KeyTypeInfo *type, ExprDef *arrayNdx,
ExprDef *value)
{
xkb_mod_mask_t mods, preserve_mods;
if (arrayNdx == NULL)
return ReportTypeShouldBeArray(info, type, "preserve entry");
if (!ExprResolveModMask(info->ctx, arrayNdx, MOD_BOTH, &info->mods, &mods))
return ReportTypeBadType(info, type, "preserve entry",
"modifier mask");
if (mods & ~type->mods) {
const char *before, *after;
before = ModMaskText(info->ctx, &info->mods, mods);
mods &= type->mods;
after = ModMaskText(info->ctx, &info->mods, mods);
log_vrb(info->ctx, 1,
"Preserve for modifiers not used by the %s type; "
"Index %s converted to %s\n",
TypeTxt(info, type), before, after);
}
if (!ExprResolveModMask(info->ctx, value, MOD_BOTH, &info->mods,
&preserve_mods)) {
log_err(info->ctx,
"Preserve value in a key type is not a modifier mask; "
"Ignoring preserve[%s] in type %s\n",
ModMaskText(info->ctx, &info->mods, mods),
TypeTxt(info, type));
return false;
}
if (preserve_mods & ~mods) {
const char *before, *after;
before = ModMaskText(info->ctx, &info->mods, preserve_mods);
preserve_mods &= mods;
after = ModMaskText(info->ctx, &info->mods, preserve_mods);
log_vrb(info->ctx, 1,
"Illegal value for preserve[%s] in type %s; "
"Converted %s to %s\n",
ModMaskText(info->ctx, &info->mods, mods),
TypeTxt(info, type), before, after);
}
return AddPreserve(info, type, mods, preserve_mods);
}
/***====================================================================***/
static bool
AddLevelName(KeyTypesInfo *info, KeyTypeInfo *type,
xkb_level_index_t level, xkb_atom_t name, bool clobber)
{
/* New name. */
if (level >= darray_size(type->level_names)) {
darray_resize0(type->level_names, level + 1);
goto finish;
}
/* Same level, same name. */
if (darray_item(type->level_names, level) == name) {
log_vrb(info->ctx, 10,
"Duplicate names for level %d of key type %s; Ignored\n",
level + 1, TypeTxt(info, type));
return true;
}
/* Same level, different name. */
if (darray_item(type->level_names, level) != XKB_ATOM_NONE) {
const char *old, *new;
old = xkb_atom_text(info->ctx,
darray_item(type->level_names, level));
new = xkb_atom_text(info->ctx, name);
log_vrb(info->ctx, 1,
"Multiple names for level %d of key type %s; "
"Using %s, ignoring %s\n",
level + 1, TypeTxt(info, type),
(clobber ? new : old), (clobber ? old : new));
if (!clobber)
return true;
}
/* XXX: What about different level, same name? */
finish:
darray_item(type->level_names, level) = name;
return true;
}
static bool
SetLevelName(KeyTypesInfo *info, KeyTypeInfo *type, ExprDef *arrayNdx,
ExprDef *value)
{
xkb_level_index_t level;
xkb_atom_t level_name;
if (arrayNdx == NULL)
return ReportTypeShouldBeArray(info, type, "level name");
if (!ExprResolveLevel(info->ctx, arrayNdx, &level))
return ReportTypeBadType(info, type, "level name", "integer");
if (!ExprResolveString(info->ctx, value, &level_name)) {
log_err(info->ctx,
"Non-string name for level %d in key type %s; "
"Ignoring illegal level name definition\n",
level + 1, xkb_atom_text(info->ctx, type->name));
return false;
}
return AddLevelName(info, type, level, level_name, true);
}
/***====================================================================***/
static bool
SetKeyTypeField(KeyTypesInfo *info, KeyTypeInfo *type,
const char *field, ExprDef *arrayNdx, ExprDef *value)
{
bool ok = false;
enum type_field type_field = 0;
if (istreq(field, "modifiers")) {
type_field = TYPE_FIELD_MASK;
ok = SetModifiers(info, type, arrayNdx, value);
}
else if (istreq(field, "map")) {
type_field = TYPE_FIELD_MAP;
ok = SetMapEntry(info, type, arrayNdx, value);
}
else if (istreq(field, "preserve")) {
type_field = TYPE_FIELD_PRESERVE;
ok = SetPreserve(info, type, arrayNdx, value);
}
else if (istreq(field, "levelname") || istreq(field, "level_name")) {
type_field = TYPE_FIELD_LEVEL_NAME;
ok = SetLevelName(info, type, arrayNdx, value);
} else {
log_err(info->ctx,
"Unknown field %s in key type %s; Definition ignored\n",
field, TypeTxt(info, type));
}
type->defined |= type_field;
return ok;
}
static bool
HandleKeyTypeBody(KeyTypesInfo *info, VarDef *def, KeyTypeInfo *type)
{
bool ok = true;
const char *elem, *field;
ExprDef *arrayNdx;
for (; def; def = (VarDef *) def->common.next) {
ok = ExprResolveLhs(info->ctx, def->name, &elem, &field,
&arrayNdx);
if (!ok)
continue;
if (elem && istreq(elem, "type")) {
log_err(info->ctx,
"Support for changing the default type has been removed; "
"Statement ignored\n");
continue;
}
ok = SetKeyTypeField(info, type, field, arrayNdx, def->value);
}
return ok;
}
static bool
HandleKeyTypeDef(KeyTypesInfo *info, KeyTypeDef *def, enum merge_mode merge)
{
KeyTypeInfo type = {
.defined = 0,
.merge = (def->merge == MERGE_DEFAULT ? merge : def->merge),
.name = def->name,
.mods = 0,
.num_levels = 1,
.entries = darray_new(),
.level_names = darray_new(),
};
if (!HandleKeyTypeBody(info, def->body, &type)) {
info->errorCount++;
return false;
}
if (!AddKeyType(info, &type, true)) {
info->errorCount++;
return false;
}
return true;
}
static void
HandleKeyTypesFile(KeyTypesInfo *info, XkbFile *file, enum merge_mode merge)
{
bool ok;
free(info->name);
info->name = strdup_safe(file->name);
for (ParseCommon *stmt = file->defs; stmt; stmt = stmt->next) {
switch (stmt->type) {
case STMT_INCLUDE:
ok = HandleIncludeKeyTypes(info, (IncludeStmt *) stmt);
break;
case STMT_TYPE:
ok = HandleKeyTypeDef(info, (KeyTypeDef *) stmt, merge);
break;
case STMT_VAR:
log_err(info->ctx,
"Support for changing the default type has been removed; "
"Statement ignored\n");
ok = true;
break;
case STMT_VMOD:
ok = HandleVModDef(info->ctx, &info->mods, (VModDef *) stmt, merge);
break;
default:
log_err(info->ctx,
"Key type files may not include other declarations; "
"Ignoring %s\n", stmt_type_to_string(stmt->type));
ok = false;
break;
}
if (!ok)
info->errorCount++;
if (info->errorCount > 10) {
log_err(info->ctx,
"Abandoning keytypes file \"%s\"\n", file->name);
break;
}
}
}
/***====================================================================***/
static bool
CopyKeyTypesToKeymap(struct xkb_keymap *keymap, KeyTypesInfo *info)
{
unsigned num_types;
struct xkb_key_type *types;
num_types = darray_empty(info->types) ? 1 : darray_size(info->types);
types = calloc(num_types, sizeof(*types));
if (!types)
return false;
/*
* If no types were specified, a default unnamed one-level type is
* used for all keys.
*/
if (darray_empty(info->types)) {
struct xkb_key_type *type = &types[0];
type->mods.mods = 0;
type->num_levels = 1;
type->entries = NULL;
type->num_entries = 0;
type->name = xkb_atom_intern_literal(keymap->ctx, "default");
type->level_names = NULL;
type->num_level_names = 0;
}
else {
for (unsigned i = 0; i < num_types; i++) {
KeyTypeInfo *def = &darray_item(info->types, i);
struct xkb_key_type *type = &types[i];
type->name = def->name;
type->mods.mods = def->mods;
type->num_levels = def->num_levels;
darray_steal(def->level_names, &type->level_names, &type->num_level_names);
darray_steal(def->entries, &type->entries, &type->num_entries);
}
}
keymap->types_section_name = strdup_safe(info->name);
XkbEscapeMapName(keymap->types_section_name);
keymap->num_types = num_types;
keymap->types = types;
keymap->mods = info->mods;
return true;
}
/***====================================================================***/
bool
CompileKeyTypes(XkbFile *file, struct xkb_keymap *keymap,
enum merge_mode merge)
{
KeyTypesInfo info;
InitKeyTypesInfo(&info, keymap->ctx, &keymap->mods);
HandleKeyTypesFile(&info, file, merge);
if (info.errorCount != 0)
goto err_info;
if (!CopyKeyTypesToKeymap(keymap, &info))
goto err_info;
ClearKeyTypesInfo(&info);
return true;
err_info:
ClearKeyTypesInfo(&info);
return false;
}

View File

@ -1,105 +0,0 @@
/************************************************************
* Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting
* documentation, and that the name of Silicon Graphics not be
* used in advertising or publicity pertaining to distribution
* of the software without specific prior written permission.
* Silicon Graphics makes no representation about the suitability
* of this software for any purpose. It is provided "as is"
* without any express or implied warranty.
*
* SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
* GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
********************************************************/
#include "xkbcomp-priv.h"
#include "text.h"
#include "expr.h"
#include "vmod.h"
bool
HandleVModDef(struct xkb_context *ctx, struct xkb_mod_set *mods,
VModDef *stmt, enum merge_mode merge)
{
xkb_mod_index_t i;
struct xkb_mod *mod;
xkb_mod_mask_t mapping;
merge = (merge == MERGE_DEFAULT ? stmt->merge : merge);
if (stmt->value) {
/*
* This is a statement such as 'virtualModifiers NumLock = Mod1';
* it sets the vmod-to-real-mod[s] mapping directly instead of going
* through modifier_map or some such.
*/
if (!ExprResolveModMask(ctx, stmt->value, MOD_REAL, mods, &mapping)) {
log_err(ctx,
"Declaration of %s ignored\n",
xkb_atom_text(ctx, stmt->name));
return false;
}
}
else {
mapping = 0;
}
xkb_mods_enumerate(i, mod, mods) {
if (mod->name == stmt->name) {
if (mod->type != MOD_VIRT) {
log_err(ctx,
"Can't add a virtual modifier named \"%s\"; "
"there is already a non-virtual modifier with this name! Ignored\n",
xkb_atom_text(ctx, mod->name));
return false;
}
if (mod->mapping == mapping)
return true;
if (mod->mapping != 0) {
xkb_mod_mask_t use, ignore;
use = (merge == MERGE_OVERRIDE ? mapping : mod->mapping);
ignore = (merge == MERGE_OVERRIDE ? mod->mapping : mapping);
log_warn(ctx,
"Virtual modifier %s defined multiple times; "
"Using %s, ignoring %s\n",
xkb_atom_text(ctx, stmt->name),
ModMaskText(ctx, mods, use),
ModMaskText(ctx, mods, ignore));
mapping = use;
}
mod->mapping = mapping;
return true;
}
}
if (mods->num_mods >= XKB_MAX_MODS) {
log_err(ctx,
"Too many modifiers defined (maximum %d)\n",
XKB_MAX_MODS);
return false;
}
mods->mods[mods->num_mods].name = stmt->name;
mods->mods[mods->num_mods].type = MOD_VIRT;
mods->mods[mods->num_mods].mapping = mapping;
mods->num_mods++;
return true;
}

View File

@ -1,34 +0,0 @@
/************************************************************
* Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting
* documentation, and that the name of Silicon Graphics not be
* used in advertising or publicity pertaining to distribution
* of the software without specific prior written permission.
* Silicon Graphics makes no representation about the suitability
* of this software for any purpose. It is provided "as is"
* without any express or implied warranty.
*
* SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
* GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
********************************************************/
#ifndef XKBCOMP_VMOD_H
#define XKBCOMP_VMOD_H
bool
HandleVModDef(struct xkb_context *ctx, struct xkb_mod_set *mods,
VModDef *stmt, enum merge_mode merge);
#endif

View File

@ -1,298 +0,0 @@
/*
* Copyright © 2009 Dan Nicholson
* Copyright © 2012 Intel Corporation
* Copyright © 2012 Ran Benita <ran234@gmail.com>
*
* 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 (including the next
* paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
*
* Author: Dan Nicholson <dbn.lists@gmail.com>
* Daniel Stone <daniel@fooishbar.org>
* Ran Benita <ran234@gmail.com>
*/
#include "xkbcomp-priv.h"
static void
ComputeEffectiveMask(struct xkb_keymap *keymap, struct xkb_mods *mods)
{
mods->mask = mod_mask_get_effective(keymap, mods->mods);
}
static void
UpdateActionMods(struct xkb_keymap *keymap, union xkb_action *act,
xkb_mod_mask_t modmap)
{
switch (act->type) {
case ACTION_TYPE_MOD_SET:
case ACTION_TYPE_MOD_LATCH:
case ACTION_TYPE_MOD_LOCK:
if (act->mods.flags & ACTION_MODS_LOOKUP_MODMAP)
act->mods.mods.mods = modmap;
ComputeEffectiveMask(keymap, &act->mods.mods);
break;
default:
break;
}
}
static const struct xkb_sym_interpret default_interpret = {
.sym = XKB_KEY_NoSymbol,
.repeat = true,
.match = MATCH_ANY_OR_NONE,
.mods = 0,
.virtual_mod = XKB_MOD_INVALID,
.action = { .type = ACTION_TYPE_NONE },
};
/**
* Find an interpretation which applies to this particular level, either by
* finding an exact match for the symbol and modifier combination, or a
* generic XKB_KEY_NoSymbol match.
*/
static const struct xkb_sym_interpret *
FindInterpForKey(struct xkb_keymap *keymap, const struct xkb_key *key,
xkb_layout_index_t group, xkb_level_index_t level)
{
const xkb_keysym_t *syms;
int num_syms;
num_syms = xkb_keymap_key_get_syms_by_level(keymap, key->keycode, group,
level, &syms);
if (num_syms == 0)
return NULL;
/*
* There may be multiple matchings interprets; we should always return
* the most specific. Here we rely on compat.c to set up the
* sym_interprets array from the most specific to the least specific,
* such that when we find a match we return immediately.
*/
for (unsigned i = 0; i < keymap->num_sym_interprets; i++) {
const struct xkb_sym_interpret *interp = &keymap->sym_interprets[i];
xkb_mod_mask_t mods;
bool found = false;
if ((num_syms > 1 || interp->sym != syms[0]) &&
interp->sym != XKB_KEY_NoSymbol)
continue;
if (interp->level_one_only && level != 0)
mods = 0;
else
mods = key->modmap;
switch (interp->match) {
case MATCH_NONE:
found = !(interp->mods & mods);
break;
case MATCH_ANY_OR_NONE:
found = (!mods || (interp->mods & mods));
break;
case MATCH_ANY:
found = (interp->mods & mods);
break;
case MATCH_ALL:
found = ((interp->mods & mods) == interp->mods);
break;
case MATCH_EXACTLY:
found = (interp->mods == mods);
break;
}
if (found)
return interp;
}
return &default_interpret;
}
static bool
ApplyInterpsToKey(struct xkb_keymap *keymap, struct xkb_key *key)
{
xkb_mod_mask_t vmodmap = 0;
xkb_layout_index_t group;
xkb_level_index_t level;
/* If we've been told not to bind interps to this key, then don't. */
if (key->explicit & EXPLICIT_INTERP)
return true;
for (group = 0; group < key->num_groups; group++) {
for (level = 0; level < XkbKeyNumLevels(key, group); level++) {
const struct xkb_sym_interpret *interp;
interp = FindInterpForKey(keymap, key, group, level);
if (!interp)
continue;
/* Infer default key behaviours from the base level. */
if (group == 0 && level == 0)
if (!(key->explicit & EXPLICIT_REPEAT) && interp->repeat)
key->repeats = true;
if ((group == 0 && level == 0) || !interp->level_one_only)
if (interp->virtual_mod != XKB_MOD_INVALID)
vmodmap |= (1u << interp->virtual_mod);
if (interp->action.type != ACTION_TYPE_NONE)
key->groups[group].levels[level].action = interp->action;
}
}
if (!(key->explicit & EXPLICIT_VMODMAP))
key->vmodmap = vmodmap;
return true;
}
/**
* This collects a bunch of disparate functions which was done in the server
* at various points that really should've been done within xkbcomp. Turns out
* your actions and types are a lot more useful when any of your modifiers
* other than Shift actually do something ...
*/
static bool
UpdateDerivedKeymapFields(struct xkb_keymap *keymap)
{
struct xkb_key *key;
struct xkb_mod *mod;
struct xkb_led *led;
unsigned int i, j;
/* Find all the interprets for the key and bind them to actions,
* which will also update the vmodmap. */
xkb_keys_foreach(key, keymap)
if (!ApplyInterpsToKey(keymap, key))
return false;
/* Update keymap->mods, the virtual -> real mod mapping. */
xkb_keys_foreach(key, keymap)
xkb_mods_enumerate(i, mod, &keymap->mods)
if (key->vmodmap & (1u << i))
mod->mapping |= key->modmap;
/* Now update the level masks for all the types to reflect the vmods. */
for (i = 0; i < keymap->num_types; i++) {
ComputeEffectiveMask(keymap, &keymap->types[i].mods);
for (j = 0; j < keymap->types[i].num_entries; j++) {
ComputeEffectiveMask(keymap, &keymap->types[i].entries[j].mods);
ComputeEffectiveMask(keymap, &keymap->types[i].entries[j].preserve);
}
}
/* Update action modifiers. */
xkb_keys_foreach(key, keymap)
for (i = 0; i < key->num_groups; i++)
for (j = 0; j < XkbKeyNumLevels(key, i); j++)
UpdateActionMods(keymap, &key->groups[i].levels[j].action,
key->modmap);
/* Update vmod -> led maps. */
xkb_leds_foreach(led, keymap)
ComputeEffectiveMask(keymap, &led->mods);
/* Find maximum number of groups out of all keys in the keymap. */
xkb_keys_foreach(key, keymap)
keymap->num_groups = MAX(keymap->num_groups, key->num_groups);
return true;
}
typedef bool (*compile_file_fn)(XkbFile *file,
struct xkb_keymap *keymap,
enum merge_mode merge);
static const compile_file_fn compile_file_fns[LAST_KEYMAP_FILE_TYPE + 1] = {
[FILE_TYPE_KEYCODES] = CompileKeycodes,
[FILE_TYPE_TYPES] = CompileKeyTypes,
[FILE_TYPE_COMPAT] = CompileCompatMap,
[FILE_TYPE_SYMBOLS] = CompileSymbols,
};
bool
CompileKeymap(XkbFile *file, struct xkb_keymap *keymap, enum merge_mode merge)
{
bool ok;
XkbFile *files[LAST_KEYMAP_FILE_TYPE + 1] = { NULL };
enum xkb_file_type type;
struct xkb_context *ctx = keymap->ctx;
/* Collect section files and check for duplicates. */
for (file = (XkbFile *) file->defs; file;
file = (XkbFile *) file->common.next) {
if (file->file_type < FIRST_KEYMAP_FILE_TYPE ||
file->file_type > LAST_KEYMAP_FILE_TYPE) {
if (file->file_type == FILE_TYPE_GEOMETRY) {
log_vrb(ctx, 1,
"Geometry sections are not supported; ignoring\n");
} else {
log_err(ctx, "Cannot define %s in a keymap file\n",
xkb_file_type_to_string(file->file_type));
}
continue;
}
if (files[file->file_type]) {
log_err(ctx,
"More than one %s section in keymap file; "
"All sections after the first ignored\n",
xkb_file_type_to_string(file->file_type));
continue;
}
files[file->file_type] = file;
}
/*
* Check that all required section were provided.
* Report everything before failing.
*/
ok = true;
for (type = FIRST_KEYMAP_FILE_TYPE;
type <= LAST_KEYMAP_FILE_TYPE;
type++) {
if (files[type] == NULL) {
log_err(ctx, "Required section %s missing from keymap\n",
xkb_file_type_to_string(type));
ok = false;
}
}
if (!ok)
return false;
/* Compile sections. */
for (type = FIRST_KEYMAP_FILE_TYPE;
type <= LAST_KEYMAP_FILE_TYPE;
type++) {
log_dbg(ctx, "Compiling %s \"%s\"\n",
xkb_file_type_to_string(type), files[type]->name);
ok = compile_file_fns[type](files[type], keymap, merge);
if (!ok) {
log_err(ctx, "Failed to compile %s\n",
xkb_file_type_to_string(type));
return false;
}
}
return UpdateDerivedKeymapFields(keymap);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,124 +0,0 @@
/************************************************************
* Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting
* documentation, and that the name of Silicon Graphics not be
* used in advertising or publicity pertaining to distribution
* of the software without specific prior written permission.
* Silicon Graphics makes no representation about the suitability
* of this software for any purpose. It is provided "as is"
* without any express or implied warranty.
*
* SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
* GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
********************************************************/
#ifndef XKBCOMP_PRIV_H
#define XKBCOMP_PRIV_H
#include "keymap.h"
#include "ast.h"
struct xkb_component_names {
char *keycodes;
char *types;
char *compat;
char *symbols;
};
char *
text_v1_keymap_get_as_string(struct xkb_keymap *keymap);
XkbFile *
XkbParseFile(struct xkb_context *ctx, FILE *file,
const char *file_name, const char *map);
XkbFile *
XkbParseString(struct xkb_context *ctx,
const char *string, size_t len,
const char *file_name, const char *map);
void
FreeXkbFile(XkbFile *file);
XkbFile *
XkbFileFromComponents(struct xkb_context *ctx,
const struct xkb_component_names *kkctgs);
bool
CompileKeycodes(XkbFile *file, struct xkb_keymap *keymap,
enum merge_mode merge);
bool
CompileKeyTypes(XkbFile *file, struct xkb_keymap *keymap,
enum merge_mode merge);
bool
CompileCompatMap(XkbFile *file, struct xkb_keymap *keymap,
enum merge_mode merge);
bool
CompileSymbols(XkbFile *file, struct xkb_keymap *keymap,
enum merge_mode merge);
bool
CompileKeymap(XkbFile *file, struct xkb_keymap *keymap,
enum merge_mode merge);
/***====================================================================***/
static inline bool
ReportNotArray(struct xkb_context *ctx, const char *type, const char *field,
const char *name)
{
log_err(ctx,
"The %s %s field is not an array; "
"Ignoring illegal assignment in %s\n",
type, field, name);
return false;
}
static inline bool
ReportShouldBeArray(struct xkb_context *ctx, const char *type,
const char *field, const char *name)
{
log_err(ctx,
"Missing subscript for %s %s; "
"Ignoring illegal assignment in %s\n",
type, field, name);
return false;
}
static inline bool
ReportBadType(struct xkb_context *ctx, const char *type, const char *field,
const char *name, const char *wanted)
{
log_err(ctx, "The %s %s field must be a %s; "
"Ignoring illegal assignment in %s\n",
type, field, wanted, name);
return false;
}
static inline bool
ReportBadField(struct xkb_context *ctx, const char *type, const char *field,
const char *name)
{
log_err(ctx,
"Unknown %s field %s in %s; "
"Ignoring assignment to unknown field in %s\n",
type, field, name, name);
return false;
}
#endif

View File

@ -1,139 +0,0 @@
/*
* Copyright © 2009 Dan Nicholson
* Copyright © 2012 Intel Corporation
* Copyright © 2012 Ran Benita <ran234@gmail.com>
*
* 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 (including the next
* paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
*
* Authors: Dan Nicholson <dbn.lists@gmail.com>
* Ran Benita <ran234@gmail.com>
* Daniel Stone <daniel@fooishbar.org>
*/
#include "xkbcomp-priv.h"
#include "rules.h"
static bool
compile_keymap_file(struct xkb_keymap *keymap, XkbFile *file)
{
if (file->file_type != FILE_TYPE_KEYMAP) {
log_err(keymap->ctx,
"Cannot compile a %s file alone into a keymap\n",
xkb_file_type_to_string(file->file_type));
return false;
}
if (!CompileKeymap(file, keymap, MERGE_OVERRIDE)) {
log_err(keymap->ctx,
"Failed to compile keymap\n");
return false;
}
return true;
}
static bool
text_v1_keymap_new_from_names(struct xkb_keymap *keymap,
const struct xkb_rule_names *rmlvo)
{
bool ok;
struct xkb_component_names kccgst;
XkbFile *file;
log_dbg(keymap->ctx,
"Compiling from RMLVO: rules '%s', model '%s', layout '%s', "
"variant '%s', options '%s'\n",
rmlvo->rules, rmlvo->model, rmlvo->layout, rmlvo->variant,
rmlvo->options);
ok = xkb_components_from_rules(keymap->ctx, rmlvo, &kccgst);
if (!ok) {
log_err(keymap->ctx,
"Couldn't look up rules '%s', model '%s', layout '%s', "
"variant '%s', options '%s'\n",
rmlvo->rules, rmlvo->model, rmlvo->layout, rmlvo->variant,
rmlvo->options);
return false;
}
log_dbg(keymap->ctx,
"Compiling from KcCGST: keycodes '%s', types '%s', "
"compat '%s', symbols '%s'\n",
kccgst.keycodes, kccgst.types, kccgst.compat, kccgst.symbols);
file = XkbFileFromComponents(keymap->ctx, &kccgst);
free(kccgst.keycodes);
free(kccgst.types);
free(kccgst.compat);
free(kccgst.symbols);
if (!file) {
log_err(keymap->ctx,
"Failed to generate parsed XKB file from components\n");
return false;
}
ok = compile_keymap_file(keymap, file);
FreeXkbFile(file);
return ok;
}
static bool
text_v1_keymap_new_from_string(struct xkb_keymap *keymap,
const char *string, size_t len)
{
bool ok;
XkbFile *xkb_file;
xkb_file = XkbParseString(keymap->ctx, string, len, "(input string)", NULL);
if (!xkb_file) {
log_err(keymap->ctx, "Failed to parse input xkb string\n");
return NULL;
}
ok = compile_keymap_file(keymap, xkb_file);
FreeXkbFile(xkb_file);
return ok;
}
static bool
text_v1_keymap_new_from_file(struct xkb_keymap *keymap, FILE *file)
{
bool ok;
XkbFile *xkb_file;
xkb_file = XkbParseFile(keymap->ctx, file, "(unknown file)", NULL);
if (!xkb_file) {
log_err(keymap->ctx, "Failed to parse input xkb file\n");
return false;
}
ok = compile_keymap_file(keymap, xkb_file);
FreeXkbFile(xkb_file);
return ok;
}
const struct xkb_keymap_format_ops text_v1_keymap_format_ops = {
.keymap_new_from_names = text_v1_keymap_new_from_names,
.keymap_new_from_string = text_v1_keymap_new_from_string,
.keymap_new_from_file = text_v1_keymap_new_from_file,
.keymap_get_as_string = text_v1_keymap_get_as_string,
};

View File

@ -1,98 +0,0 @@
/*
* Copyright © 2012 Daniel Stone
*
* 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 (including the next
* paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
*
* Author: Daniel Stone <daniel@fooishbar.org>
*/
#ifndef _XKBCOMMON_COMPAT_H
#define _XKBCOMMON_COMPAT_H
/**
* Renamed keymap API.
*/
#define xkb_group_index_t xkb_layout_index_t
#define xkb_group_mask_t xkb_layout_mask_t
#define xkb_map_compile_flags xkb_keymap_compile_flags
#define XKB_GROUP_INVALID XKB_LAYOUT_INVALID
#define XKB_STATE_DEPRESSED \
(XKB_STATE_MODS_DEPRESSED | XKB_STATE_LAYOUT_DEPRESSED)
#define XKB_STATE_LATCHED \
(XKB_STATE_MODS_LATCHED | XKB_STATE_LAYOUT_LATCHED)
#define XKB_STATE_LOCKED \
(XKB_STATE_MODS_LOCKED | XKB_STATE_LAYOUT_LOCKED)
#define XKB_STATE_EFFECTIVE \
(XKB_STATE_DEPRESSED | XKB_STATE_LATCHED | XKB_STATE_LOCKED | \
XKB_STATE_MODS_EFFECTIVE | XKB_STATE_LAYOUT_EFFECTIVE)
#define xkb_map_new_from_names(context, names, flags) \
xkb_keymap_new_from_names(context, names, flags)
#define xkb_map_new_from_file(context, file, format, flags) \
xkb_keymap_new_from_file(context, file, format, flags)
#define xkb_map_new_from_string(context, string, format, flags) \
xkb_keymap_new_from_string(context, string, format, flags)
#define xkb_map_get_as_string(keymap) \
xkb_keymap_get_as_string(keymap, XKB_KEYMAP_FORMAT_TEXT_V1)
#define xkb_map_ref(keymap) xkb_keymap_ref(keymap)
#define xkb_map_unref(keymap) xkb_keymap_unref(keymap)
#define xkb_map_num_mods(keymap) xkb_keymap_num_mods(keymap)
#define xkb_map_mod_get_name(keymap, idx) xkb_keymap_mod_get_name(keymap, idx)
#define xkb_map_mod_get_index(keymap, str) xkb_keymap_mod_get_index(keymap, str)
#define xkb_key_mod_index_is_consumed(state, key, mod) \
xkb_state_mod_index_is_consumed(state, key, mod)
#define xkb_key_mod_mask_remove_consumed(state, key, modmask) \
xkb_state_mod_mask_remove_consumed(state, key, modmask)
#define xkb_map_num_groups(keymap) xkb_keymap_num_layouts(keymap)
#define xkb_key_num_groups(keymap, key) \
xkb_keymap_num_layouts_for_key(keymap, key)
#define xkb_map_group_get_name(keymap, idx) \
xkb_keymap_layout_get_name(keymap, idx)
#define xkb_map_group_get_index(keymap, str) \
xkb_keymap_layout_get_index(keymap, str)
#define xkb_map_num_leds(keymap) xkb_keymap_num_leds(keymap)
#define xkb_map_led_get_name(keymap, idx) xkb_keymap_led_get_name(keymap, idx)
#define xkb_map_led_get_index(keymap, str) \
xkb_keymap_led_get_index(keymap, str)
#define xkb_key_repeats(keymap, key) xkb_keymap_key_repeats(keymap, key)
#define xkb_key_get_syms(state, key, syms_out) \
xkb_state_key_get_syms(state, key, syms_out)
#define xkb_state_group_name_is_active(state, name, type) \
xkb_state_layout_name_is_active(state, name, type)
#define xkb_state_group_index_is_active(state, idx, type) \
xkb_state_layout_index_is_active(state, idx, type)
#define xkb_state_serialize_group(state, component) \
xkb_state_serialize_layout(state, component)
#define xkb_state_get_map(state) xkb_state_get_keymap(state)
/* Not needed anymore, since there's NO_FLAGS. */
#define XKB_MAP_COMPILE_PLACEHOLDER XKB_KEYMAP_COMPILE_NO_FLAGS
#define XKB_MAP_COMPILE_NO_FLAGS XKB_KEYMAP_COMPILE_NO_FLAGS
#endif

View File

@ -1,493 +0,0 @@
/*
* Copyright © 2013 Ran Benita
*
* 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 (including the next
* paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
*/
#ifndef _XKBCOMMON_COMPOSE_H
#define _XKBCOMMON_COMPOSE_H
#include <xkbcommon/xkbcommon.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @file
* libxkbcommon Compose API - support for Compose and dead-keys.
*/
/**
* @defgroup compose Compose and dead-keys support
* Support for Compose and dead-keys.
* @since 0.5.0
*
* @{
*/
/**
* @page compose-overview Overview
* @parblock
*
* Compose and dead-keys are a common feature of many keyboard input
* systems. They extend the range of the keysysm that can be produced
* directly from a keyboard by using a sequence of key strokes, instead
* of just one.
*
* Here are some example sequences, in the libX11 Compose file format:
*
* <dead_acute> <a> : "á" aacute # LATIN SMALL LETTER A WITH ACUTE
* <Multi_key> <A> <T> : "@" at # COMMERCIAL AT
*
* When the user presses a key which produces the `<dead_acute>` keysym,
* nothing initially happens (thus the key is dubbed a "dead-key"). But
* when the user enters `<a>`, "á" is "composed", in place of "a". If
* instead the user had entered a keysym which does not follow
* `<dead_acute>` in any compose sequence, the sequence is said to be
* "cancelled".
*
* Compose files define many such sequences. For a description of the
* common file format for Compose files, see the Compose(5) man page.
*
* A successfuly-composed sequence has two results: a keysym and a UTF-8
* string. At least one of the two is defined for each sequence. If only
* a keysym is given, the keysym's string representation is used for the
* result string (using xkb_keysym_to_utf8()).
*
* This library provides low-level support for Compose file parsing and
* processing. Higher-level APIs (such as libX11's `Xutf8LookupString`(3))
* may be built upon it, or it can be used directly.
*
* @endparblock
*/
/**
* @page compose-conflicting Conflicting Sequences
* @parblock
*
* To avoid ambiguity, a sequence is not allowed to be a prefix of another.
* In such a case, the conflict is resolved thus:
*
* 1. A longer sequence overrides a shorter one.
* 2. An equal sequence overrides an existing one.
* 3. A shorter sequence does not override a longer one.
*
* Sequences of length 1 are allowed.
*
* @endparblock
*/
/**
* @page compose-cancellation Cancellation Behavior
* @parblock
*
* What should happen when a sequence is cancelled? For example, consider
* there are only the above sequences, and the input keysyms are
* `<dead_acute> <b>`. There are a few approaches:
*
* 1. Swallow the cancelling keysym; that is, no keysym is produced.
* This is the approach taken by libX11.
* 2. Let the cancelling keysym through; that is, `<b>` is produced.
* 3. Replay the entire sequence; that is, `<dead_acute> <b>` is produced.
* This is the approach taken by Microsoft Windows (approximately;
* instead of `<dead_acute>`, the underlying key is used. This is
* difficult to simulate with XKB keymaps).
*
* You can program whichever approach best fits users' expectations.
*
* @endparblock
*/
/**
* @struct xkb_compose_table
* Opaque Compose table object.
*
* The compose table holds the definitions of the Compose sequences, as
* gathered from Compose files. It is immutable.
*/
struct xkb_compose_table;
/**
* @struct xkb_compose_state
* Opaque Compose state object.
*
* The compose state maintains state for compose sequence matching, such
* as which possible sequences are being matched, and the position within
* these sequences. It acts as a simple state machine wherein keysyms are
* the input, and composed keysyms and strings are the output.
*
* The compose state is usually associated with a keyboard device.
*/
struct xkb_compose_state;
/** Flags affecting Compose file compilation. */
enum xkb_compose_compile_flags {
/** Do not apply any flags. */
XKB_COMPOSE_COMPILE_NO_FLAGS = 0
};
/** The recognized Compose file formats. */
enum xkb_compose_format {
/** The classic libX11 Compose text format, described in Compose(5). */
XKB_COMPOSE_FORMAT_TEXT_V1 = 1
};
/**
* @page compose-locale Compose Locale
* @parblock
*
* Compose files are locale dependent:
* - Compose files are written for a locale, and the locale is used when
* searching for the appropriate file to use.
* - Compose files may reference the locale internally, with directives
* such as \%L.
*
* As such, functions like xkb_compose_table_new_from_locale() require
* a `locale` parameter. This will usually be the current locale (see
* locale(7) for more details). You may also want to allow the user to
* explicitly configure it, so he can use the Compose file of a given
* locale, but not use that locale for other things.
*
* You may query the current locale as follows:
* @code
* const char *locale;
* locale = setlocale(LC_CTYPE, NULL);
* @endcode
*
* This will only give useful results if the program had previously set
* the current locale using setlocale(3), with `LC_CTYPE` or `LC_ALL`
* and a non-NULL argument.
*
* If you prefer not to use the locale system of the C runtime library,
* you may nevertheless obtain the user's locale directly using
* environment variables, as described in locale(7). For example,
* @code
* const char *locale;
* locale = getenv("LC_ALL");
* if (!locale || !*locale)
* locale = getenv("LC_CTYPE");
* if (!locale || !*locale)
* locale = getenv("LANG");
* if (!locale || !*locale)
* locale = "C";
* @endcode
*
* Note that some locales supported by the C standard library may not
* have a Compose file assigned.
*
* @endparblock
*/
/**
* Create a compose table for a given locale.
*
* The locale is used for searching the file-system for an appropriate
* Compose file. The search order is described in Compose(5). It is
* affected by the following environment variables:
*
* 1. `XCOMPOSEFILE` - see Compose(5).
* 2. `HOME` - see Compose(5).
* 3. `XLOCALEDIR` - if set, used as the base directory for the system's
* X locale files, e.g. `/usr/share/X11/locale`, instead of the
* preconfigured directory.
*
* @param context
* The library context in which to create the compose table.
* @param locale
* The current locale. See @ref compose-locale.\n
*
* The value is copied, so it is safe to pass the result of getenv(3)
* (or similar) without fear of it being invalidated by a subsequent
* setenv(3) (or similar).
* @param flags
* Optional flags for the compose table, or 0.
*
* @returns A compose table for the given locale, or NULL if the
* compilation failed or a Compose file was not found.
*
* @memberof xkb_compose_table
*/
struct xkb_compose_table *
xkb_compose_table_new_from_locale(struct xkb_context *context,
const char *locale,
enum xkb_compose_compile_flags flags);
/**
* Create a new compose table from a Compose file.
*
* @param context
* The library context in which to create the compose table.
* @param file
* The Compose file to compile.
* @param locale
* The current locale. See @ref compose-locale.
* @param format
* The text format of the Compose file to compile.
* @param flags
* Optional flags for the compose table, or 0.
*
* @returns A compose table compiled from the given file, or NULL if
* the compilation failed.
*
* @memberof xkb_compose_table
*/
struct xkb_compose_table *
xkb_compose_table_new_from_file(struct xkb_context *context,
FILE *file,
const char *locale,
enum xkb_compose_format format,
enum xkb_compose_compile_flags flags);
/**
* Create a new compose table from a memory buffer.
*
* This is just like xkb_compose_table_new_from_file(), but instead of
* a file, gets the table as one enormous string.
*
* @see xkb_compose_table_new_from_file()
* @memberof xkb_compose_table
*/
struct xkb_compose_table *
xkb_compose_table_new_from_buffer(struct xkb_context *context,
const char *buffer, size_t length,
const char *locale,
enum xkb_compose_format format,
enum xkb_compose_compile_flags flags);
/**
* Take a new reference on a compose table.
*
* @returns The passed in object.
*
* @memberof xkb_compose_table
*/
struct xkb_compose_table *
xkb_compose_table_ref(struct xkb_compose_table *table);
/**
* Release a reference on a compose table, and possibly free it.
*
* @param table The object. If it is NULL, this function does nothing.
*
* @memberof xkb_compose_table
*/
void
xkb_compose_table_unref(struct xkb_compose_table *table);
/** Flags for compose state creation. */
enum xkb_compose_state_flags {
/** Do not apply any flags. */
XKB_COMPOSE_STATE_NO_FLAGS = 0
};
/**
* Create a new compose state object.
*
* @param table
* The compose table the state will use.
* @param flags
* Optional flags for the compose state, or 0.
*
* @returns A new compose state, or NULL on failure.
*
* @memberof xkb_compose_state
*/
struct xkb_compose_state *
xkb_compose_state_new(struct xkb_compose_table *table,
enum xkb_compose_state_flags flags);
/**
* Take a new reference on a compose state object.
*
* @returns The passed in object.
*
* @memberof xkb_compose_state
*/
struct xkb_compose_state *
xkb_compose_state_ref(struct xkb_compose_state *state);
/**
* Release a reference on a compose state object, and possibly free it.
*
* @param state The object. If NULL, do nothing.
*
* @memberof xkb_compose_state
*/
void
xkb_compose_state_unref(struct xkb_compose_state *state);
/**
* Get the compose table which a compose state object is using.
*
* @returns The compose table which was passed to xkb_compose_state_new()
* when creating this state object.
*
* This function does not take a new reference on the compose table; you
* must explicitly reference it yourself if you plan to use it beyond the
* lifetime of the state.
*
* @memberof xkb_compose_state
*/
struct xkb_compose_table *
xkb_compose_state_get_compose_table(struct xkb_compose_state *state);
/** Status of the Compose sequence state machine. */
enum xkb_compose_status {
/** The initial state; no sequence has started yet. */
XKB_COMPOSE_NOTHING,
/** In the middle of a sequence. */
XKB_COMPOSE_COMPOSING,
/** A complete sequence has been matched. */
XKB_COMPOSE_COMPOSED,
/** The last sequence was cancelled due to an unmatched keysym. */
XKB_COMPOSE_CANCELLED
};
/** The effect of a keysym fed to xkb_compose_state_feed(). */
enum xkb_compose_feed_result {
/** The keysym had no effect - it did not affect the status. */
XKB_COMPOSE_FEED_IGNORED,
/** The keysym started, advanced or cancelled a sequence. */
XKB_COMPOSE_FEED_ACCEPTED
};
/**
* Feed one keysym to the Compose sequence state machine.
*
* This function can advance into a compose sequence, cancel a sequence,
* start a new sequence, or do nothing in particular. The resulting
* status may be observed with xkb_compose_state_get_status().
*
* Some keysyms, such as keysyms for modifier keys, are ignored - they
* have no effect on the status or otherwise.
*
* The following is a description of the possible status transitions, in
* the format CURRENT STATUS => NEXT STATUS, given a non-ignored input
* keysym `keysym`:
*
@verbatim
NOTHING or CANCELLED or COMPOSED =>
NOTHING if keysym does not start a sequence.
COMPOSING if keysym starts a sequence.
COMPOSED if keysym starts and terminates a single-keysym sequence.
COMPOSING =>
COMPOSING if keysym advances any of the currently possible
sequences but does not terminate any of them.
COMPOSED if keysym terminates one of the currently possible
sequences.
CANCELLED if keysym does not advance any of the currently
possible sequences.
@endverbatim
*
* The current Compose formats do not support multiple-keysyms.
* Therefore, if you are using a function such as xkb_state_key_get_syms()
* and it returns more than one keysym, consider feeding XKB_KEY_NoSymbol
* instead.
*
* @param state
* The compose state object.
* @param keysym
* A keysym, usually obtained after a key-press event, with a
* function such as xkb_state_key_get_one_sym().
*
* @returns Whether the keysym was ignored. This is useful, for example,
* if you want to keep a record of the sequence matched thus far.
*
* @memberof xkb_compose_state
*/
enum xkb_compose_feed_result
xkb_compose_state_feed(struct xkb_compose_state *state,
xkb_keysym_t keysym);
/**
* Reset the Compose sequence state machine.
*
* The status is set to XKB_COMPOSE_NOTHING, and the current sequence
* is discarded.
*
* @memberof xkb_compose_state
*/
void
xkb_compose_state_reset(struct xkb_compose_state *state);
/**
* Get the current status of the compose state machine.
*
* @see xkb_compose_status
* @memberof xkb_compose_state
**/
enum xkb_compose_status
xkb_compose_state_get_status(struct xkb_compose_state *state);
/**
* Get the result Unicode/UTF-8 string for a composed sequence.
*
* See @ref compose-overview for more details. This function is only
* useful when the status is XKB_COMPOSE_COMPOSED.
*
* @param[in] state
* The compose state.
* @param[out] buffer
* A buffer to write the string into.
* @param[in] size
* Size of the buffer.
*
* @warning If the buffer passed is too small, the string is truncated
* (though still NUL-terminated).
*
* @returns
* The number of bytes required for the string, excluding the NUL byte.
* If the sequence is not complete, or does not have a viable result
* string, returns 0, and sets `buffer` to the empty string (if possible).
* @returns
* You may check if truncation has occurred by comparing the return value
* with the size of `buffer`, similarly to the `snprintf`(3) function.
* You may safely pass NULL and 0 to `buffer` and `size` to find the
* required size (without the NUL-byte).
*
* @memberof xkb_compose_state
**/
int
xkb_compose_state_get_utf8(struct xkb_compose_state *state,
char *buffer, size_t size);
/**
* Get the result keysym for a composed sequence.
*
* See @ref compose-overview for more details. This function is only
* useful when the status is XKB_COMPOSE_COMPOSED.
*
* @returns The result keysym. If the sequence is not complete, or does
* not specify a result keysym, returns XKB_KEY_NoSymbol.
*
* @memberof xkb_compose_state
**/
xkb_keysym_t
xkb_compose_state_get_one_sym(struct xkb_compose_state *state);
/** @} */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* _XKBCOMMON_COMPOSE_H */

File diff suppressed because it is too large Load Diff

View File

@ -1,45 +0,0 @@
/*
* Copyright © 2012 Intel Corporation
*
* 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 (including the next
* paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
*
* Author: Daniel Stone <daniel@fooishbar.org>
*/
#ifndef _XKBCOMMON_NAMES_H
#define _XKBCOMMON_NAMES_H
/**
* @file
* @brief Predefined names for common modifiers and LEDs.
*/
#define XKB_MOD_NAME_SHIFT "Shift"
#define XKB_MOD_NAME_CAPS "Lock"
#define XKB_MOD_NAME_CTRL "Control"
#define XKB_MOD_NAME_ALT "Mod1"
#define XKB_MOD_NAME_NUM "Mod2"
#define XKB_MOD_NAME_LOGO "Mod4"
#define XKB_LED_NAME_CAPS "Caps Lock"
#define XKB_LED_NAME_NUM "Num Lock"
#define XKB_LED_NAME_SCROLL "Scroll Lock"
#endif

View File

@ -1,244 +0,0 @@
/*
* Copyright © 2013 Ran Benita
*
* 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 (including the next
* paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
*/
#ifndef _XKBCOMMON_X11_H
#define _XKBCOMMON_X11_H
#include <xcb/xcb.h>
#include <xkbcommon/xkbcommon.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @file
* libxkbcommon-x11 API - Additional X11 support for xkbcommon.
*/
/**
* @defgroup x11 X11 support
* Additional X11 support for xkbcommon.
* @since 0.4.0
*
* @{
*/
/**
* @page x11-overview Overview
* @parblock
*
* The xkbcommon-x11 module provides a means for creating an xkb_keymap
* corresponding to the currently active keymap on the X server. To do
* so, it queries the XKB X11 extension using the xcb-xkb library. It
* can be used as a replacement for Xlib's keyboard handling.
*
* Following is an example workflow using xkbcommon-x11. A complete
* example may be found in the test/interactive-x11.c file in the
* xkbcommon source repository. On startup:
*
* 1. Connect to the X server using xcb_connect().
* 2. Setup the XKB X11 extension. You can do this either by using the
* xcb_xkb_use_extension() request directly, or by using the
* xkb_x11_setup_xkb_extension() helper function.
*
* The XKB extension supports using separate keymaps and states for
* different keyboard devices. The devices are identified by an integer
* device ID and are managed by another X11 extension, XInput. The
* original X11 protocol only had one keyboard device, called the "core
* keyboard", which is still supported as a "virtual device".
*
* 3. We will use the core keyboard as an example. To get its device ID,
* use either the xcb_xkb_get_device_info() request directly, or the
* xkb_x11_get_core_keyboard_device_id() helper function.
* 4. Create an initial xkb_keymap for this device, using the
* xkb_x11_keymap_new_from_device() function.
* 5. Create an initial xkb_state for this device, using the
* xkb_x11_state_new_from_device() function.
*
* @note At this point, you may consider setting various XKB controls and
* XKB per-client flags. For example, enabling detectable autorepeat: \n
* https://www.x.org/releases/current/doc/kbproto/xkbproto.html#Detectable_Autorepeat
*
* Next, you need to react to state changes (e.g. a modifier was pressed,
* the layout was changed) and to keymap changes (e.g. a tool like xkbcomp,
* setxkbmap or xmodmap was used):
*
* 6. Select to listen to at least the following XKB events:
* NewKeyboardNotify, MapNotify, StateNotify; using the
* xcb_xkb_select_events_aux() request.
* 7. When NewKeyboardNotify or MapNotify are received, recreate the
* xkb_keymap and xkb_state as described above.
* 8. When StateNotify is received, update the xkb_state accordingly
* using the xkb_state_update_mask() function.
*
* @note It is also possible to use the KeyPress/KeyRelease @p state
* field to find the effective modifier and layout state, instead of
* using XkbStateNotify: \n
* https://www.x.org/releases/current/doc/kbproto/xkbproto.html#Computing_A_State_Field_from_an_XKB_State
* \n However, XkbStateNotify is more accurate.
*
* @note There is no need to call xkb_state_update_key(); the state is
* already synchronized.
*
* Finally, when a key event is received, you can use ordinary xkbcommon
* functions, like xkb_state_key_get_one_sym() and xkb_state_key_get_utf8(),
* as you normally would.
*
* @endparblock
*/
/**
* The minimal compatible major version of the XKB X11 extension which
* this library can use.
*/
#define XKB_X11_MIN_MAJOR_XKB_VERSION 1
/**
* The minimal compatible minor version of the XKB X11 extension which
* this library can use (for the minimal major version).
*/
#define XKB_X11_MIN_MINOR_XKB_VERSION 0
/** Flags for the xkb_x11_setup_xkb_extension() function. */
enum xkb_x11_setup_xkb_extension_flags {
/** Do not apply any flags. */
XKB_X11_SETUP_XKB_EXTENSION_NO_FLAGS = 0
};
/**
* Setup the XKB X11 extension for this X client.
*
* The xkbcommon-x11 library uses various XKB requests. Before doing so,
* an X client must notify the server that it will be using the extension.
* This function (or an XCB equivalent) must be called before any other
* function in this library is used.
*
* Some X servers may not support or disable the XKB extension. If you
* want to support such servers, you need to use a different fallback.
*
* You may call this function several times; it is idempotent.
*
* @param connection
* An XCB connection to the X server.
* @param major_xkb_version
* See @p minor_xkb_version.
* @param minor_xkb_version
* The XKB extension version to request. To operate correctly, you
* must have (major_xkb_version, minor_xkb_version) >=
* (XKB_X11_MIN_MAJOR_XKB_VERSION, XKB_X11_MIN_MINOR_XKB_VERSION),
* though this is not enforced.
* @param flags
* Optional flags, or 0.
* @param[out] major_xkb_version_out
* See @p minor_xkb_version_out.
* @param[out] minor_xkb_version_out
* Backfilled with the compatible XKB extension version numbers picked
* by the server. Can be NULL.
* @param[out] base_event_out
* Backfilled with the XKB base (also known as first) event code, needed
* to distinguish XKB events. Can be NULL.
* @param[out] base_error_out
* Backfilled with the XKB base (also known as first) error code, needed
* to distinguish XKB errors. Can be NULL.
*
* @returns 1 on success, or 0 on failure.
*/
int
xkb_x11_setup_xkb_extension(xcb_connection_t *connection,
uint16_t major_xkb_version,
uint16_t minor_xkb_version,
enum xkb_x11_setup_xkb_extension_flags flags,
uint16_t *major_xkb_version_out,
uint16_t *minor_xkb_version_out,
uint8_t *base_event_out,
uint8_t *base_error_out);
/**
* Get the keyboard device ID of the core X11 keyboard.
*
* @param connection An XCB connection to the X server.
*
* @returns A device ID which may be used with other xkb_x11_* functions,
* or -1 on failure.
*/
int32_t
xkb_x11_get_core_keyboard_device_id(xcb_connection_t *connection);
/**
* Create a keymap from an X11 keyboard device.
*
* This function queries the X server with various requests, fetches the
* details of the active keymap on a keyboard device, and creates an
* xkb_keymap from these details.
*
* @param context
* The context in which to create the keymap.
* @param connection
* An XCB connection to the X server.
* @param device_id
* An XInput device ID (in the range 0-127) with input class KEY.
* Passing values outside of this range is an error (the XKB protocol
* predates the XInput2 protocol, which first allowed IDs > 127).
* @param flags
* Optional flags for the keymap, or 0.
*
* @returns A keymap retrieved from the X server, or NULL on failure.
*
* @memberof xkb_keymap
*/
struct xkb_keymap *
xkb_x11_keymap_new_from_device(struct xkb_context *context,
xcb_connection_t *connection,
int32_t device_id,
enum xkb_keymap_compile_flags flags);
/**
* Create a new keyboard state object from an X11 keyboard device.
*
* This function is the same as xkb_state_new(), only pre-initialized
* with the state of the device at the time this function is called.
*
* @param keymap
* The keymap for which to create the state.
* @param connection
* An XCB connection to the X server.
* @param device_id
* An XInput 1 device ID (in the range 0-255) with input class KEY.
* Passing values outside of this range is an error.
*
* @returns A new keyboard state object, or NULL on failure.
*
* @memberof xkb_state
*/
struct xkb_state *
xkb_x11_state_new_from_device(struct xkb_keymap *keymap,
xcb_connection_t *connection,
int32_t device_id);
/** @} */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* _XKBCOMMON_X11_H */

File diff suppressed because it is too large Load Diff

View File

@ -647,24 +647,24 @@ template<> class QTypeInfo<A> : public QTypeInfoMerger<A, B, C, D> {};
//! [52]
struct Foo {
void overloadedFunction();
void overloadedFunction(int, QString);
void overloadedFunction(int, const QString &);
};
... qOverload<>(&Foo::overloadedFunction)
... qOverload<int, QString>(&Foo::overloadedFunction)
... qOverload<int, const QString &>(&Foo::overloadedFunction)
//! [52]
//! [53]
... QOverload<>::of(&Foo::overloadedFunction)
... QOverload<int, QString>::of(&Foo::overloadedFunction)
... QOverload<int, const QString &>::of(&Foo::overloadedFunction)
//! [53]
//! [54]
struct Foo {
void overloadedFunction(int, QString);
void overloadedFunction(int, QString) const;
void overloadedFunction(int, const QString &);
void overloadedFunction(int, const QString &) const;
};
... qConstOverload<int, QString>(&Foo::overloadedFunction)
... qNonConstOverload<int, QString>(&Foo::overloadedFunction)
... qConstOverload<int, const QString &>(&Foo::overloadedFunction)
... qNonConstOverload<int, const QString &>(&Foo::overloadedFunction)
//! [54]
//! [qlikely]

View File

@ -162,17 +162,17 @@ Float qbswapFloatHelper(Float source)
return qFromUnaligned<Float>(&temp);
}
template <> inline qfloat16 qbswap<qfloat16>(qfloat16 source)
inline qfloat16 qbswap(qfloat16 source)
{
return qbswapFloatHelper(source);
}
template <> inline float qbswap<float>(float source)
inline float qbswap(float source)
{
return qbswapFloatHelper(source);
}
template <> inline double qbswap<double>(double source)
inline double qbswap(double source)
{
return qbswapFloatHelper(source);
}
@ -185,7 +185,7 @@ template <> inline double qbswap<double>(double source)
*/
template <typename T> inline void qbswap(const T src, void *dest)
{
qToUnaligned<T>(qbswap<T>(src), dest);
qToUnaligned<T>(qbswap(src), dest);
}
template <int Size> void *qbswap(const void *source, qsizetype count, void *dest) noexcept;
@ -223,9 +223,9 @@ template <typename T> inline void qFromLittleEndian(const void *source, qsizetyp
#else // Q_LITTLE_ENDIAN
template <typename T> inline Q_DECL_CONSTEXPR T qToBigEndian(T source)
{ return qbswap<T>(source); }
{ return qbswap(source); }
template <typename T> inline Q_DECL_CONSTEXPR T qFromBigEndian(T source)
{ return qbswap<T>(source); }
{ return qbswap(source); }
template <typename T> inline Q_DECL_CONSTEXPR T qToLittleEndian(T source)
{ return source; }
template <typename T> inline Q_DECL_CONSTEXPR T qFromLittleEndian(T source)

View File

@ -58,14 +58,21 @@
#if defined(Q_CC_MSVC)
# include <intrin.h>
#endif
#if defined(Q_CC_MSVC)
#include <float.h>
# include <float.h>
# if defined(Q_PROCESSOR_X86_64) || defined(Q_PROCESSOR_ARM_64)
# define Q_INTRINSIC_MUL_OVERFLOW64
# define Q_UMULH(v1, v2) __umulh(v1, v2);
# define Q_SMULH(v1, v2) __mulh(v1, v2);
# pragma intrinsic(__umulh)
# pragma intrinsic(__mulh)
# endif
#endif
# if defined(Q_OS_INTEGRITY) && defined(Q_PROCESSOR_ARM_64)
#include <arm64_ghs.h>
# define Q_INTRINSIC_MUL_OVERFLOW64
# define Q_UMULH(v1, v2) __MULUH64(v1, v2);
# define Q_SMULH(v1, v2) __MULSH64(v1, v2);
#endif
#if !defined(Q_CC_MSVC) && (defined(Q_OS_QNX) || defined(Q_CC_INTEL))
@ -327,26 +334,26 @@ mul_overflow(T v1, T v2, T *r)
return lr > std::numeric_limits<T>::max() || lr < std::numeric_limits<T>::min();
}
# if defined(Q_OS_INTEGRITY) && defined(Q_PROCESSOR_ARM_64)
# if defined(Q_INTRINSIC_MUL_OVERFLOW64)
template <> inline bool mul_overflow(quint64 v1, quint64 v2, quint64 *r)
{
*r = v1 * v2;
return __MULUH64(v1, v2);
return Q_UMULH(v1, v2);
}
template <> inline bool mul_overflow(qint64 v1, qint64 v2, qint64 *r)
{
qint64 high = __MULSH64(v1, v2);
if (high == 0) {
*r = v1 * v2;
return *r < 0;
}
if (high == -1) {
*r = v1 * v2;
return *r >= 0;
}
return true;
// This is slightly more complex than the unsigned case above: the sign bit
// of 'low' must be replicated as the entire 'high', so the only valid
// values for 'high' are 0 and -1. Use unsigned multiply since it's the same
// as signed for the low bits and use a signed right shift to verify that
// 'high' is nothing but sign bits that match the sign of 'low'.
qint64 high = __mulh(v1, v2);
*r = qint64(quint64(v1) * quint64(v2));
return (*r >> 63) != high;
}
# if defined(Q_OS_INTEGRITY) && defined(Q_PROCESSOR_ARM_64)
template <> inline bool mul_overflow(uint64_t v1, uint64_t v2, uint64_t *r)
{
return mul_overflow<quint64>(v1,v2,reinterpret_cast<quint64*>(r));
@ -356,8 +363,8 @@ template <> inline bool mul_overflow(int64_t v1, int64_t v2, int64_t *r)
{
return mul_overflow<qint64>(v1,v2,reinterpret_cast<qint64*>(r));
}
#endif
# endif // OS_INTEGRITY ARM64
# endif // Q_INTRINSIC_MUL_OVERFLOW64
# if defined(Q_CC_MSVC) && defined(Q_PROCESSOR_X86)
// We can use intrinsics for the unsigned operations with MSVC
@ -369,37 +376,8 @@ template <> inline bool add_overflow(unsigned v1, unsigned v2, unsigned *r)
# if defined(Q_PROCESSOR_X86_64)
template <> inline bool add_overflow(quint64 v1, quint64 v2, quint64 *r)
{ return _addcarry_u64(0, v1, v2, reinterpret_cast<unsigned __int64 *>(r)); }
# pragma intrinsic(_umul128)
template <> inline bool mul_overflow(quint64 v1, quint64 v2, quint64 *r)
{
// use 128-bit multiplication with the _umul128 intrinsic
// https://msdn.microsoft.com/en-us/library/3dayytw9.aspx
quint64 high;
*r = _umul128(v1, v2, &high);
return high;
}
# pragma intrinsic(_mul128)
template <> inline bool mul_overflow(qint64 v1, qint64 v2, qint64 *r)
{
// Use 128-bit multiplication with the _mul128 intrinsic
// https://msdn.microsoft.com/en-us/library/82cxdw50.aspx
// This is slightly more complex than the unsigned case above: the sign bit
// of 'low' must be replicated as the entire 'high', so the only valid
// values for 'high' are 0 and -1.
qint64 high;
*r = _mul128(v1, v2, &high);
if (high == 0)
return *r < 0;
if (high == -1)
return *r >= 0;
return true;
}
# endif // x86-64
# endif // MSVC x86
# endif // MSVC X86
#endif // !GCC
}
#endif // Q_CLANG_QDOC

View File

@ -89,7 +89,7 @@ public:
QAppleRefCounted(QAppleRefCounted &&other) : value(other.value) { other.value = T(); }
QAppleRefCounted(const QAppleRefCounted &other) : value(other.value) { if (value) RetainFunction(value); }
~QAppleRefCounted() { if (value) ReleaseFunction(value); }
operator T() { return value; }
operator T() const { return value; }
void swap(QAppleRefCounted &other) Q_DECL_NOEXCEPT_EXPR(noexcept(qSwap(value, other.value)))
{ qSwap(value, other.value); }
QAppleRefCounted &operator=(const QAppleRefCounted &other)

View File

@ -341,7 +341,7 @@ inline QMetaObject::Connection QObjectPrivate::connect(const typename QtPrivate:
Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatible<typename SlotType::ReturnType, typename SignalType::ReturnType>::value),
"Return type of the slot is not compatible with the return type of the signal.");
const int *types = 0;
const int *types = nullptr;
if (type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection)
types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types();

View File

@ -168,11 +168,11 @@ int QElfParser::parse(const char *dataStart, ulong fdlen, const QString &library
parseSectionHeader(dataStart + soff, &strtab);
m_stringTableFileOffset = strtab.offset;
if ((quint32)(m_stringTableFileOffset + e_shentsize) >= fdlen || m_stringTableFileOffset == 0) {
if ((quint32)(strtab.offset + strtab.size) > fdlen || strtab.offset == 0) {
if (lib)
lib->errorString = QLibrary::tr("'%1' is an invalid ELF object (%2)")
.arg(library, QLibrary::tr("string table seems to be at %1")
.arg(QString::number(soff, 16)));
.arg(QString::number(strtab.offset, 16)));
return Corrupt;
}

View File

@ -4112,7 +4112,8 @@ ushort QByteArray::toUShort(bool *ok, int base) const
/*!
Returns the byte array converted to a \c double value.
Returns 0.0 if the conversion fails.
Returns an infinity if the conversion overflows or 0.0 if the
conversion fails for other reasons (e.g. underflow).
If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
to \c false, and success by setting *\a{ok} to \c true.
@ -4147,7 +4148,8 @@ double QByteArray::toDouble(bool *ok) const
/*!
Returns the byte array converted to a \c float value.
Returns 0.0 if the conversion fails.
Returns an infinity if the conversion overflows or 0.0 if the
conversion fails for other reasons (e.g. underflow).
If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
to \c false, and success by setting *\a{ok} to \c true.

View File

@ -1371,8 +1371,10 @@ qulonglong QLocale::toULongLong(const QString &s, bool *ok) const
}
/*!
Returns the float represented by the localized string \a s, or 0.0
if the conversion failed.
Returns the float represented by the localized string \a s.
Returns an infinity if the conversion overflows or 0.0 if the
conversion fails for any other reason (e.g. underflow).
If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
to \c false, and success by setting *\a{ok} to \c true.
@ -1391,8 +1393,10 @@ float QLocale::toFloat(const QString &s, bool *ok) const
}
/*!
Returns the double represented by the localized string \a s, or
0.0 if the conversion failed.
Returns the double represented by the localized string \a s.
Returns an infinity if the conversion overflows or 0.0 if the
conversion fails for any other reason (e.g. underflow).
If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
to \c false, and success by setting *\a{ok} to \c true.
@ -1538,8 +1542,10 @@ qulonglong QLocale::toULongLong(const QStringRef &s, bool *ok) const
}
/*!
Returns the float represented by the localized string \a s, or 0.0
if the conversion failed.
Returns the float represented by the localized string \a s.
Returns an infinity if the conversion overflows or 0.0 if the
conversion fails for any other reason (e.g. underflow).
If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
to \c false, and success by setting *\a{ok} to \c true.
@ -1560,8 +1566,10 @@ float QLocale::toFloat(const QStringRef &s, bool *ok) const
}
/*!
Returns the double represented by the localized string \a s, or
0.0 if the conversion failed.
Returns the double represented by the localized string \a s.
Returns an infinity if the conversion overflows or 0.0 if the
conversion fails for any other reason (e.g. underflow).
If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
to \c false, and success by setting *\a{ok} to \c true.
@ -1710,8 +1718,10 @@ qulonglong QLocale::toULongLong(QStringView s, bool *ok) const
}
/*!
Returns the float represented by the localized string \a s, or 0.0
if the conversion failed.
Returns the float represented by the localized string \a s.
Returns an infinity if the conversion overflows or 0.0 if the
conversion fails for any other reason (e.g. underflow).
If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
to \c false, and success by setting *\a{ok} to \c true.
@ -1729,8 +1739,10 @@ float QLocale::toFloat(QStringView s, bool *ok) const
}
/*!
Returns the double represented by the localized string \a s, or
0.0 if the conversion failed.
Returns the double represented by the localized string \a s.
Returns an infinity if the conversion overflows or 0.0 if the
conversion fails for any other reason (e.g. underflow).
If \a ok is not \c nullptr, failure is reported by setting *\a{ok}
to \c false, and success by setting *\a{ok} to \c true.

View File

@ -251,7 +251,16 @@ public:
if (std::fabs(d) > std::numeric_limits<float>::max()) {
if (ok != 0)
*ok = false;
return 0.0f;
const float huge = std::numeric_limits<float>::infinity();
return d < 0 ? -huge : huge;
}
if (std::fabs(d) >= std::numeric_limits<double>::min() // i.e. d != 0
&& std::fabs(d) < std::numeric_limits<float>::min()) {
// Values smaller than std::numeric_limits<double>::min() have
// failed already; match them.
if (ok != 0)
*ok = false;
return 0;
}
return float(d);
}

View File

@ -354,7 +354,7 @@ double qt_asciiToDouble(const char *num, int numLen, bool &ok, int &processed,
ok = false;
for (int i = 0; i < processed; ++i) {
char c = num[i];
if ((c < '0' || c > '9') && c != '.' && c != '-' && c != '+' && c != 'e') {
if ((c < '0' || c > '9') && c != '.' && c != '-' && c != '+' && c != 'e' && c != 'E') {
// Garbage found
processed = 0;
return 0.0;

Some files were not shown because too many files have changed in this diff Show More