static int listKeyBinding (ListGenerationData *lgd, const KeyBinding *binding, int longPress, const wchar_t *keysPrefix) { const BoundCommand *cmd = longPress? &binding->secondaryCommand: &binding->primaryCommand; size_t keysOffset; if (cmd->value == BRL_CMD_NOOP) return 1; if (!putCommandDescription(lgd, cmd, !binding->keyCombination.anyKeyCount)) return 0; if (!putCharacterString(lgd, WS_C(": "))) return 0; keysOffset = lgd->line.length; if (keysPrefix) { if (!putCharacterString(lgd, keysPrefix)) return 0; if (!putCharacterString(lgd, WS_C(", "))) return 0; } if (longPress) { if (!putCharacterString(lgd, WS_C("long "))) return 0; } if (!putKeyCombination(lgd, &binding->keyCombination)) return 0; if ((cmd->value & BRL_MSK_BLK) == BRL_BLK_CONTEXT) { const KeyContext *c = getKeyContext(lgd->keyTable, (KTB_CTX_DEFAULT + (cmd->value & BRL_MSK_ARG))); if (!c) return 0; { size_t length = lgd->line.length - keysOffset; wchar_t keys[length + 1]; wmemcpy(keys, &lgd->line.characters[keysOffset], length); keys[length] = 0; lgd->line.length = 0; if (isTemporaryKeyContext(lgd->keyTable, c)) { if (!listKeyContext(lgd, c, keys)) return 0; } else { if (!putCharacterString(lgd, WS_C("switch to "))) return 0; if (!putCharacterString(lgd, c->title)) return 0; if (!putCharacterString(lgd, WS_C(": "))) return 0; if (!putCharacterString(lgd, keys)) return 0; if (!endLine(lgd)) return 0; } } } else { if (!endLine(lgd)) return 0; } return 1; }
ScreenCharacterType getScreenCharacterType (const ScreenCharacter *character) { if (iswspace(character->text)) return SCT_SPACE; if (iswalnum(character->text)) return SCT_WORD; if (wcschr(WS_C("_"), character->text)) return SCT_WORD; return SCT_NONWORD; }
static DATA_OPERANDS_PROCESSOR(processUcsBlockOperands) { DataOperand action; if (getDataOperand(file, &action, "UCS block action")) { const wchar_t *expected = inUcsBlock? WS_C("END"): WS_C("START"); if (isKeyword(expected, action.characters, action.length)) { inUcsBlock = !inUcsBlock; } else { reportDataError(file, "unexpected UCS block action: %.*" PRIws " (expecting %" PRIws ")", action.length, action.characters, expected); } } return 1; }
static int putCharacters (ListGenerationData *lgd, const wchar_t *characters, size_t count) { size_t newLength = lgd->lineLength + count; if (lgd->sectionTitle) { if (!handleLine(lgd, WS_C(""))) return 0; if (!handleLine(lgd, lgd->sectionTitle)) return 0; lgd->sectionTitle = NULL; } if (newLength > lgd->lineSize) { size_t newSize = (newLength | 0X3F) + 1; wchar_t *newCharacters = realloc(lgd->lineCharacters, ARRAY_SIZE(newCharacters, newSize)); if (!newCharacters) { logSystemError("realloc"); return 0; } lgd->lineCharacters = newCharacters; lgd->lineSize = newSize; } wmemcpy(&lgd->lineCharacters[lgd->lineLength], characters, count); lgd->lineLength = newLength; return 1; }
static int doListKeyTable (ListGenerationData *lgd) { if (!putUtf8String(lgd, gettext("Key Table"))) return 0; if (lgd->keyTable->title) { if (!putCharacterString(lgd, WS_C(": "))) return 0; if (!putCharacterString(lgd, lgd->keyTable->title)) return 0; if (!endLine(lgd)) return 0; } if (lgd->keyTable->noteCount) { unsigned int noteIndex; if (!endLine(lgd)) return 0; for (noteIndex=0; noteIndex<lgd->keyTable->noteCount; noteIndex+=1) { if (!putCharacterString(lgd, lgd->keyTable->noteTable[noteIndex])) return 0; if (!endLine(lgd)) return 0; } } { static const unsigned char contexts[] = { KTB_CTX_DEFAULT, KTB_CTX_MENU }; const unsigned char *context = contexts; unsigned int count = ARRAY_COUNT(contexts); while (count) { const KeyContext *ctx = getKeyContext(lgd->keyTable, *context); if (ctx) { lgd->sectionTitle = ctx->title; if (!listKeyContext(lgd, ctx, NULL)) return 0; } context += 1, count -= 1; } } { unsigned int context; for (context=KTB_CTX_DEFAULT+1; context<lgd->keyTable->keyContextCount; context+=1) { const KeyContext *ctx = getKeyContext(lgd->keyTable, context); if (ctx && !isTemporaryKeyContext(lgd->keyTable, ctx)) { lgd->sectionTitle = ctx->title; if (!listKeyContext(lgd, ctx, NULL)) return 0; } } } return 1; }
static DATA_OPERANDS_PROCESSOR(processEncodingOperands) { DataOperand encoding; if (getDataOperand(file, &encoding, "character encoding name")) { if (!isKeyword(WS_C("UTF-8"), encoding.characters, encoding.length)) { reportDataError(file, "unsupported character encoding: %.*" PRIws, encoding.length, encoding.characters); } } return 1; }
static int processEncodingOperands (DataFile *file, void *data) { DataOperand encoding; if (getDataOperand(file, &encoding, "character encoding name")) { if (!isKeyword(WS_C("UTF-8"), encoding.characters, encoding.length)) { reportDataError(file, "unsupported character encoding: %.*" PRIws, encoding.length, encoding.characters); } } return 1; }
static int rstWriteHeader (const wchar_t *text, unsigned int level, void *data) { RestructuredTextData *rst = data; if (rst->headerLevel < level) { while (++rst->headerLevel < level) { if (!rstAddHeader(WS_C("\\ "), rst)) return 0; } } else if (rst->headerLevel > level) { rst->headerLevel = level; } return rstAddHeader(text, rst); }
static int listKeyboardFunctions (ListGenerationData *lgd, const KeyContext *ctx) { const char *prefix = "braille keyboard "; { unsigned int index; for (index=0; index<ctx->mappedKeyCount; index+=1) { const MappedKeyEntry *map = &ctx->mappedKeyTable[index]; const KeyboardFunction *kbf = map->keyboardFunction; if (!putUtf8String(lgd, prefix)) return 0; if (!putUtf8String(lgd, kbf->name)) return 0; if (!putCharacterString(lgd, WS_C(": "))) return 0; if (!putKeyName(lgd, &map->keyValue)) return 0; if (!endLine(lgd)) return 0; } } { const KeyboardFunction *kbf = keyboardFunctionTable; const KeyboardFunction *end = kbf + keyboardFunctionCount; while (kbf < end) { if (ctx->superimposedBits & kbf->bit) { if (!putUtf8String(lgd, prefix)) return 0; if (!putUtf8String(lgd, kbf->name)) return 0; if (!putCharacterString(lgd, WS_C(": superimposed"))) return 0; if (!endLine(lgd)) return 0; } kbf += 1; } } return 1; }
static DATA_OPERANDS_PROCESSOR(processDelegateOperands) { DataOperand type; if (getDataOperand(file, &type, "delegate type")) { if (isKeyword(WS_C("FILE"), type.characters, type.length)) { DataOperand name; if (getDataOperand(file, &name, "file name")) { return includeDataFile(file, name.characters, name.length); } } else { return includeDataFile(file, type.characters, type.length); } } return 1; }
static int processDelegateOperands (DataFile *file, void *data) { DataOperand type; if (getDataOperand(file, &type, "delegate type")) { if (isKeyword(WS_C("FILE"), type.characters, type.length)) { DataOperand name; if (getDataOperand(file, &name, "file name")) { return includeDataFile(file, name.characters, name.length); } } else { return includeDataFile(file, type.characters, type.length); } } return 1; }
static int listHotkeyEvent (ListGenerationData *lgd, const KeyValue *keyValue, const char *event, int command) { if (command != BRL_CMD_NOOP) { if ((command & BRL_MSK_BLK) == BRL_BLK_CONTEXT) { const KeyContext *c = getKeyContext(lgd->keyTable, (KTB_CTX_DEFAULT + (command & BRL_MSK_ARG))); if (!c) return 0; if (!putUtf8String(lgd, "switch to ")) return 0; if (!putCharacterString(lgd, c->title)) return 0; } else { if (!putCommandDescription(lgd, command, (keyValue->key != KTB_KEY_ANY))) return 0; } if (!putCharacterString(lgd, WS_C(": "))) return 0; if (!putUtf8String(lgd, event)) return 0; if (!putCharacter(lgd, WC_C(' '))) return 0; if (!putKeyName(lgd, keyValue)) return 0; if (!endLine(lgd)) return 0; } return 1; }
static int rstAddHeader (const wchar_t *text, RestructuredTextData *rst) { static const wchar_t characters[] = { WC_C('='), WC_C('-'), WC_C('~') }; int isTitle = rst->headerLevel == 0; size_t length = wcslen(text); wchar_t underline[length + 1]; wmemset(underline, characters[rst->headerLevel], length); underline[length] = 0; if (!rstAddLine(text, rst)) return 0; if (!rstAddLine(underline, rst)) return 0; if (!rstAddBlankLine(rst)) return 0; if (isTitle) { if (!rstAddLine(WS_C(".. contents::"), rst)) return 0; if (!rstAddBlankLine(rst)) return 0; } return 1; }
static int listKeyContext (ListGenerationData *lgd, const KeyContext *ctx, const wchar_t *keysPrefix) { { const HotkeyEntry *hotkey = ctx->hotkeyTable; unsigned int count = ctx->hotkeyCount; while (count) { if (!(hotkey->flags & HKF_HIDDEN)) { if (!listHotkeyEvent(lgd, &hotkey->keyValue, "press", hotkey->pressCommand)) return 0; if (!listHotkeyEvent(lgd, &hotkey->keyValue, "release", hotkey->releaseCommand)) return 0; } hotkey += 1, count -= 1; } } { const KeyBinding *binding = ctx->keyBindingTable; unsigned int count = ctx->keyBindingCount; while (count) { if (!(binding->flags & KBF_HIDDEN)) { size_t keysOffset; if (!putCommandDescription(lgd, binding->command, !binding->combination.anyKeyCount)) return 0; if (!putCharacterString(lgd, WS_C(": "))) return 0; keysOffset = lgd->lineLength; if (keysPrefix) { if (!putCharacterString(lgd, keysPrefix)) return 0; if (!putCharacterString(lgd, WS_C(", "))) return 0; } if (!putKeyCombination(lgd, &binding->combination)) return 0; if ((binding->command & BRL_MSK_BLK) == BRL_BLK_CONTEXT) { const KeyContext *c = getKeyContext(lgd->keyTable, (KTB_CTX_DEFAULT + (binding->command & BRL_MSK_ARG))); if (!c) return 0; { size_t length = lgd->lineLength - keysOffset; wchar_t keys[length + 1]; wmemcpy(keys, &lgd->lineCharacters[keysOffset], length); keys[length] = 0; lgd->lineLength = 0; if (isTemporaryKeyContext(lgd->keyTable, c)) { if (!listKeyContext(lgd, c, keys)) return 0; } else { if (!putCharacterString(lgd, WS_C("switch to "))) return 0; if (!putCharacterString(lgd, c->title)) return 0; if (!putCharacterString(lgd, WS_C(": "))) return 0; if (!putCharacterString(lgd, keys)) return 0; if (!endLine(lgd)) return 0; } } } else { if (!endLine(lgd)) return 0; } } binding += 1, count -= 1; } } if (!listKeyboardFunctions(lgd, ctx)) return 0; return 1; }
if (getCharacterOperand(file, &character)) { unsigned char dots; if (getDotsOperand(file, &dots)) { if (!setTextTableGlyph(ttd, character, dots)) return 0; } } return 1; } static int processTextTableLine (DataFile *file, void *data) { static const DataProperty properties[] = { {.name=WS_C("char"), .processor=processCharOperands}, {.name=WS_C("glyph"), .processor=processGlyphOperands}, {.name=WS_C("byte"), .processor=processByteOperands}, DATA_NESTING_PROPERTIES, {.name=NULL, .processor=NULL} }; return processPropertyOperand(file, properties, "text table directive", data); } TextTableData * processTextTableStream (FILE *stream, const char *name) { return processTextTableLines(stream, name, processTextTableLine); } TextTable * compileTextTable (const char *name) {
static int rstAddBlankLine (RestructuredTextData *rst) { return rstAddLine(WS_C(""), rst); }
#include <stdio.h> #include <string.h> #include <errno.h> #include "log.h" #include "file.h" #include "ctb.h" #include "ctb_internal.h" #include "datafile.h" #include "dataarea.h" #include "brldots.h" #include "hostcmd.h" static const wchar_t *const characterClassNames[] = { WS_C("space"), WS_C("letter"), WS_C("digit"), WS_C("punctuation"), WS_C("uppercase"), WS_C("lowercase"), NULL }; struct CharacterClass { struct CharacterClass *next; ContractionTableCharacterAttributes attribute; BYTE length; wchar_t name[1]; };
static int getDotsOperand (DataFile *file, unsigned char *dots) { if (findDataOperand(file, "cell")) { wchar_t character; if (getDataCharacter(file, &character)) { int noDots = 0; wchar_t enclosed = (character == WC_C('('))? WC_C(')'): 0; *dots = 0; if (!enclosed) { if (wcschr(WS_C("0"), character)) { noDots = 1; } else { ungetDataCharacters(file, 1); } } while (getDataCharacter(file, &character)) { int space = iswspace(character); if (enclosed) { if (character == enclosed) { enclosed = 0; break; } if (space) continue; } else if (space) { ungetDataCharacters(file, 1); break; } { int dot; if (noDots || !brlDotNumberToIndex(character, &dot)) { reportDataError(file, "invalid dot number: %.1" PRIws, &character); return 0; } { unsigned char bit = brlDotBits[dot]; if (*dots & bit) { reportDataError(file, "duplicate dot number: %.1" PRIws, &character); return 0; } *dots |= bit; } } } if (enclosed) { reportDataError(file, "incomplete cell"); return 0; } return 1; } } return 0; }
} static DATA_OPERANDS_PROCESSOR(processIfSetOperands) { return processConfigurationDirectiveTestOperands(file, 1, data); } static DATA_OPERANDS_PROCESSOR(processIfNotSetOperands) { return processConfigurationDirectiveTestOperands(file, 0, data); } static DATA_OPERANDS_PROCESSOR(processConfigurationLine) { BEGIN_DATA_DIRECTIVE_TABLE DATA_NESTING_DIRECTIVES, DATA_VARIABLE_DIRECTIVES, DATA_CONDITION_DIRECTIVES, {.name=WS_C("ifset"), .processor=processIfSetOperands}, {.name=WS_C("ifnotset"), .processor=processIfNotSetOperands}, {.name=NULL, .processor=processConfigurationOperands}, END_DATA_DIRECTIVE_TABLE return processDirectiveOperand(file, &directives, "configuration file directive", data); } static void freeConfigurationDirectives (ConfigurationFileProcessingData *conf) { while (conf->directive.count > 0) free(conf->directive.table[--conf->directive.count]); } static int addConfigurationDirectives (ConfigurationFileProcessingData *conf) { for (unsigned int optionIndex=0; optionIndex<conf->info->optionCount; optionIndex+=1) {