static int getUnicodeCharacter (DataFile *file, wchar_t *character, const char *description) { DataOperand string; if (getDataOperand(file, &string, description)) { if (string.length > 2) { if ((string.characters[0] == WC_C('U')) && (string.characters[1] == WC_C('+'))) { const wchar_t *digit = &string.characters[2]; int length = string.length - 2; *character = 0; while (length) { int value; int shift; if (!isHexadecimalDigit(*digit++, &value, &shift)) break; *character <<= shift; *character |= value; length -= 1; } if (!length) return 1; } } reportDataError(file, "invalid Unicode character: %.*" PRIws, string.length, string.characters); } return 0; }
int isOctalDigit (wchar_t character, int *value, int *shift) { if ((character < WC_C('0')) || (character > WC_C('7'))) return 0; *value = character - WC_C('0'); *shift = 3; return 1; }
static void renderCoordinatesAlphabetic (unsigned char *cell, int column, int row) { /* the coordinates are presented as an underlined letter as the Alva DOS TSR */ if (!SCR_COORDINATES_OK(column, row)) { *cell = convertCharacterToDots(textTable, WC_C('z')); } else { const int32_t height = 25; const int32_t frequency = row / height; if (frequency) { const int32_t interval = NSECS_PER_SEC / (frequency * 2); TimeValue time; getMonotonicTime(&time); scheduleUpdateIn("alva status field", (((interval - (time.nanoseconds % interval)) / NSECS_PER_MSEC) + 1)); if (!((time.nanoseconds / interval) % 2)) { *cell = 0; return; } } *cell = convertCharacterToDots(textTable, ((row % height) + WC_C('a'))) | ((column / textCount) << 6); } }
static void renderCoordinatesAlphabetic (unsigned char *cell, int column, int row) { /* the coordinates are presented as an underlined letter as the Alva DOS TSR */ *cell = !SCR_COORDINATES_OK(column, row)? convertCharacterToDots(textTable, WC_C('z')): ((updateIntervals / 16) % (row / 25 + 1))? 0: convertCharacterToDots(textTable, (row % 25 + WC_C('a'))) | ((column / textCount) << 6); }
static int rstBeginElement (unsigned int level, void *data) { RestructuredTextData *rst = data; static const wchar_t bullets[] = { WC_C('*'), WC_C('+'), WC_C('o') }; rst->elementLevel = level; rst->elementBullet = bullets[level - 1]; if (!rstAddBlankLine(rst)) return 0; return 1; }
static int putKeyName (ListGenerationData *lgd, const KeyValue *value) { const KeyNameEntry *kne = findKeyNameEntry(lgd, value); if (kne) return putUtf8String(lgd, kne->name); if (value->key != KTB_KEY_ANY) { const KeyValue anyKey = { .set = value->set, .key = KTB_KEY_ANY }; if ((kne = findKeyNameEntry(lgd, &anyKey))) { if (!putUtf8String(lgd, kne->name)) return 0; if (!putCharacter(lgd, WC_C('.'))) return 0; if (!putNumber(lgd, value->key+1)) return 0; return 1; } } return putUtf8String(lgd, "?"); } static int putKeyCombination (ListGenerationData *lgd, const KeyCombination *combination) { wchar_t delimiter = 0; { unsigned char index; for (index=0; index<combination->modifierCount; index+=1) { if (!delimiter) { delimiter = WC_C('+'); } else if (!putCharacter(lgd, delimiter)) { return 0; } if (!putKeyName(lgd, &combination->modifierKeys[combination->modifierPositions[index]])) return 0; } } if (combination->flags & KCF_IMMEDIATE_KEY) { if (delimiter) if (!putCharacter(lgd, delimiter)) return 0; if (!putKeyName(lgd, &combination->immediateKey)) return 0; } return 1; }
static int putKeyCombination (ListGenerationData *lgd, const KeyCombination *combination) { wchar_t delimiter = 0; { unsigned char index; for (index=0; index<combination->modifierCount; index+=1) { if (!delimiter) { delimiter = WC_C('+'); } else if (!putCharacter(lgd, delimiter)) { return 0; } if (!putKeyName(lgd, &combination->modifierKeys[combination->modifierPositions[index]])) return 0; } } if (combination->flags & KCF_IMMEDIATE_KEY) { if (delimiter) if (!putCharacter(lgd, delimiter)) return 0; if (!putKeyName(lgd, &combination->immediateKey)) return 0; } return 1; }
static int readCharacters_HelpScreen (const ScreenBox *box, ScreenCharacter *buffer) { const HelpPageEntry *page = getPage(); if (page) { if (validateScreenBox(box, page->lineLength, page->lineCount)) { ScreenCharacter *character = buffer; int row; for (row=0; row<box->height; row+=1) { const HelpLineEntry *line = &page->lineTable[box->top + row]; int column; for (column=0; column<box->width; column+=1) { int index = box->left + column; if (index < line->length) { character->text = line->characters[index]; } else { character->text = WC_C(' '); } character->attributes = SCR_COLOUR_DEFAULT; character += 1; } } return 1; } } return 0; }
void fillStatusSeparator (wchar_t *text, unsigned char *dots) { if ((prefs.statusSeparator != ssNone) && (statusCount > 0)) { int onRight = statusStart > 0; unsigned int column = (onRight? statusStart: textStart) - 1; wchar_t textSeparator; #ifdef HAVE_WCHAR_H const wchar_t textSeparator_left = 0X23B8; /* LEFT VERTICAL BOX LINE */ const wchar_t textSeparator_right = 0X23B9; /* RIGHT VERTICAL BOX LINE */ const wchar_t textSeparator_block = 0X2503; /* BOX DRAWINGS HEAVY VERTICAL */ #else /* HAVE_WCHAR_H */ const wchar_t textSeparator_left = 0X5B; /* LEFT SQUARE BRACKET */ const wchar_t textSeparator_right = 0X5D; /* RIGHT SQUARE BRACKET */ const wchar_t textSeparator_block = 0X7C; /* VERTICAL LINE */ #endif /* HAVE_WCHAR_H */ unsigned char dotsSeparator; const unsigned char dotsSeparator_left = BRL_DOT1 | BRL_DOT2 | BRL_DOT3 | BRL_DOT7; const unsigned char dotsSeparator_right = BRL_DOT4 | BRL_DOT5 | BRL_DOT6 | BRL_DOT8; const unsigned char dotsSeparator_block = dotsSeparator_left | dotsSeparator_right; text += column; dots += column; switch (prefs.statusSeparator) { case ssBlock: textSeparator = textSeparator_block; dotsSeparator = dotsSeparator_block; break; case ssStatusSide: textSeparator = onRight? textSeparator_right: textSeparator_left; dotsSeparator = onRight? dotsSeparator_right: dotsSeparator_left; break; case ssTextSide: textSeparator = onRight? textSeparator_left: textSeparator_right; dotsSeparator = onRight? dotsSeparator_left: dotsSeparator_right; break; default: textSeparator = WC_C(' '); dotsSeparator = 0; break; } { unsigned int row; for (row=0; row<brl.textRows; row+=1) { *text = textSeparator; text += brl.textColumns; *dots = dotsSeparator; dots += brl.textColumns; } } } }
int cpbRectangularCopy (int column, int row) { int copied = 0; size_t length; wchar_t *buffer = cpbReadScreen(&length, beginColumn, beginRow, column, row); if (buffer) { { const wchar_t *from = buffer; const wchar_t *end = from + length; wchar_t *to = buffer; int spaces = 0; while (from != end) { wchar_t character = *from++; switch (character) { case WC_C(' '): spaces += 1; continue; case WC_C('\r'): spaces = 0; default: break; } while (spaces) { *to++ = WC_C(' '); spaces -= 1; } *to++ = character; } length = to - buffer; } if (cpbEndOperation(buffer, length)) copied = 1; free(buffer); } return copied; }
int isHexadecimalDigit (wchar_t character, int *value, int *shift) { if ((character >= WC_C('0')) && (character <= WC_C('9'))) { *value = character - WC_C('0'); } else if ((character >= WC_C('a')) && (character <= WC_C('f'))) { *value = character - WC_C('a') + 10; } else if ((character >= WC_C('A')) && (character <= WC_C('F'))) { *value = character - WC_C('A') + 10; } else { return 0; } *shift = 4; return 1; }
static int rstWriteLine (const wchar_t *line, void *data) { RestructuredTextData *rst = data; const unsigned int indent = 2; const unsigned int count = indent * rst->elementLevel; size_t length = wcslen(line); wchar_t buffer[count + length + 1]; if (rst->elementLevel > 0) { wmemset(buffer, WC_C(' '), count); buffer[count - indent] = rst->elementBullet; rst->elementBullet = WC_C(' '); wmemcpy(&buffer[count], line, (length + 1)); line = buffer; } return rstAddLine(line, rst); }
static int writeCharacter (const wchar_t *character, mbstate_t *state) { char bytes[0X1000]; size_t result = wcrtomb(bytes, (character? *character: WC_C('\0')), state); if (result == (size_t)-1) return 0; if (!character) result -= 1; fwrite(bytes, 1, result, outputStream); return !ferror(outputStream); }
static wchar_t * cpbReadScreen (size_t *length, int fromColumn, int fromRow, int toColumn, int toRow) { wchar_t *newBuffer = NULL; int columns = toColumn - fromColumn + 1; int rows = toRow - fromRow + 1; if ((columns >= 1) && (rows >= 1) && (beginOffset >= 0)) { wchar_t fromBuffer[rows * columns]; if (readScreenText(fromColumn, fromRow, columns, rows, fromBuffer)) { wchar_t toBuffer[rows * (columns + 1)]; wchar_t *toAddress = toBuffer; const wchar_t *fromAddress = fromBuffer; int row; for (row=fromRow; row<=toRow; row+=1) { int column; for (column=fromColumn; column<=toColumn; column+=1) { wchar_t character = *fromAddress++; if (iswcntrl(character) || iswspace(character)) character = WC_C(' '); *toAddress++ = character; } if (row != toRow) *toAddress++ = WC_C('\r'); } /* make a new permanent buffer of just the right size */ { size_t newLength = toAddress - toBuffer; if ((newBuffer = cpbAllocateCharacters(newLength))) { wmemcpy(newBuffer, toBuffer, (*length = newLength)); } } } } return newBuffer; }
static int brl_writeWindow (BrailleDisplay *brl, const wchar_t *text) { if (text) { if (wmemcmp(text, textCharacters, brailleCount) != 0) { const wchar_t *address = text; int count = brailleCount; writeString("Visual \""); while (count-- > 0) { wchar_t character = *address++; switch (character) { case WC_C('"'): case WC_C('\\'): writeCharacter(WC_C('\\')); default: writeCharacter(character); break; } } writeString("\""); writeLine(); wmemcpy(textCharacters, text, brailleCount); } } if (cellsHaveChanged(brailleCells, brl->buffer, brailleCount, NULL, NULL, NULL)) { writeString("Braille \""); writeDots(brl->buffer, brailleCount); writeString("\""); writeLine(); } 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 wchar_t getCharacter (BrailleDisplay *brl) { for (;;) { switch (getByte()) { default: break; case BNI_CHARACTER: return convertDotsToCharacter(textTable, translateInputCell(getByte())); case BNI_SPACE: switch (getByte()) { default: break; case BNC_SPACE: return WC_C(' '); } break; case BNI_BACKSPACE: switch (getByte() & 0X3F) { default: break; case BNC_SPACE: return WC_C('\b'); } break; case BNI_ENTER: switch (getByte()) { default: break; case BNC_SPACE: return WC_C('\r'); } break; } refreshCells(brl); } }
static int processCharacters (const wchar_t *characters, size_t count, wchar_t end, void *data) { if (opt_reformatText && count) { if (iswspace(characters[0])) if (!flushCharacters('\n', data)) return 0; { unsigned int spaces = !inputLength? 0: 1; size_t newLength = inputLength + spaces + count; if (newLength > inputSize) { size_t newSize = newLength | 0XFF; wchar_t *newBuffer = calloc(newSize, sizeof(*newBuffer)); if (!newBuffer) { noMemory(data); return 0; } wmemcpy(newBuffer, inputBuffer, inputLength); free(inputBuffer); inputBuffer = newBuffer; inputSize = newSize; } while (spaces) { inputBuffer[inputLength++] = WC_C(' '); spaces -= 1; } wmemcpy(&inputBuffer[inputLength], characters, count); inputLength += count; } if (end != '\n') { if (!flushCharacters(0, data)) return 0; if (!putCharacter(end, data)) return 0; } } else { if (!flushCharacters('\n', data)) return 0; if (!writeCharacters(characters, count, data)) return 0; if (!putCharacter(end, data)) return 0; } return 1; }
static void renderStatusField_stateLetter (unsigned char *cells) { *cells = convertCharacterToDots(textTable, ses->displayMode? WC_C('a'): isHelpScreen() ? WC_C('h'): isMenuScreen() ? WC_C('m'): isFrozenScreen()? WC_C('f'): ses->trackCursor? WC_C('t'): WC_C(' ')); }
static void renderStatusField_stateLetter (unsigned char *cells) { *cells = convertCharacterToDots(textTable, ses->displayMode ? WC_C('a'): isSpecialScreen(SCR_HELP) ? WC_C('h'): isSpecialScreen(SCR_MENU) ? WC_C('m'): isSpecialScreen(SCR_FROZEN) ? WC_C('f'): ses->trackScreenCursor ? WC_C('t'): WC_C(' ')); }
/* Opens a connection with BrlAPI's server */ static int brl_construct(BrailleDisplay *brl, char **parameters, const char *device) { brlapi_connectionSettings_t settings; settings.host = parameters[PARM_HOST]; settings.auth = parameters[PARM_AUTH]; CHECK((brlapi_openConnection(&settings, &settings)>=0), out); logMessage(LOG_CATEGORY(BRAILLE_DRIVER), "Connected to %s using %s", settings.host, settings.auth); CHECK((brlapi_enterTtyModeWithPath(NULL, 0, NULL)>=0), out0); logMessage(LOG_CATEGORY(BRAILLE_DRIVER), "Got tty successfully"); CHECK((brlapi_getDisplaySize(&brl->textColumns, &brl->textRows)==0), out1); logMessage(LOG_CATEGORY(BRAILLE_DRIVER), "Found out display size: %dx%d", brl->textColumns, brl->textRows); displaySize = brl->textColumns * brl->textRows; brl->hideCursor = 1; prevData = malloc(displaySize); CHECK((prevData!=NULL), out1); memset(prevData, 0, displaySize); prevText = malloc(displaySize * sizeof(wchar_t)); CHECK((prevText!=NULL), out2); wmemset(prevText, WC_C(' '), displaySize); prevShown = 0; prevCursor = BRL_NO_CURSOR; restart = 0; logMessage(LOG_CATEGORY(BRAILLE_DRIVER), "Memory allocated, returning 1"); return 1; out2: free(prevData); out1: brlapi_leaveTtyMode(); out0: brlapi_closeConnection(); out: logMessage(LOG_CATEGORY(BRAILLE_DRIVER), "Something went wrong, returning 0"); return 0; }
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; }
void speakCharacters (const ScreenCharacter *characters, size_t count, int spell) { int immediate = 1; if (isAllSpaceCharacters(characters, count)) { switch (prefs.whitespaceIndicator) { default: case wsNone: if (immediate) muteSpeech("white space"); break; case wsSaySpace: { wchar_t buffer[0X100]; size_t length = convertTextToWchars(buffer, gettext("space"), ARRAY_COUNT(buffer)); sayWideCharacters(buffer, NULL, length, immediate); break; } } } else if (count == 1) { wchar_t character = characters[0].text; const char *prefix = NULL; int restorePitch = 0; int restorePunctuation = 0; if (iswupper(character)) { switch (prefs.uppercaseIndicator) { default: case ucNone: break; case ucSayCap: // "cap" here, used during speech output, is short for "capital". // It is spoken just before an uppercase letter, e.g. "cap A". prefix = gettext("cap"); break; case ucRaisePitch: if (canSetSpeechPitch()) { unsigned char pitch = prefs.speechPitch + 7; if (pitch > SPK_PITCH_MAXIMUM) pitch = SPK_PITCH_MAXIMUM; if (pitch != prefs.speechPitch) { setSpeechPitch(pitch, 0); restorePitch = 1; } } break; } } if (canSetSpeechPunctuation()) { unsigned char punctuation = SPK_PUNCTUATION_ALL; if (punctuation != prefs.speechPunctuation) { setSpeechPunctuation(punctuation, 0); restorePunctuation = 1; } } if (prefix) { wchar_t buffer[0X100]; size_t length = convertTextToWchars(buffer, prefix, ARRAY_COUNT(buffer)); buffer[length++] = WC_C(' '); buffer[length++] = character; sayWideCharacters(buffer, NULL, length, immediate); } else { sayWideCharacters(&character, NULL, 1, immediate); } if (restorePunctuation) setSpeechPunctuation(prefs.speechPunctuation, 0); if (restorePitch) setSpeechPitch(prefs.speechPitch, 0); } else if (spell) { wchar_t string[count * 2]; size_t length = 0; unsigned int index = 0; while (index < count) { string[length++] = characters[index++].text; string[length++] = WC_C(' '); } string[length] = WC_C('\0'); sayWideCharacters(string, NULL, length, immediate); } else { sayScreenCharacters(characters, count, immediate); } }
static int dimensionsChanged (BrailleDisplay *brl) { int ok = 1; const char *word; int columns1; int rows1; int columns2 = 0; int rows2 = 0; if ((word = nextWord())) { if (isInteger(&columns1, word) && (columns1 > 0)) { rows1 = 1; if ((word = nextWord())) { if (isInteger(&rows1, word) && (rows1 > 0)) { if ((word = nextWord())) { if (isInteger(&columns2, word) && (columns2 > 0)) { rows2 = 0; if ((word = nextWord())) { if (isInteger(&rows2, word) && (rows2 > 0)) { } else { logMessage(LOG_WARNING, "invalid status row count: %s", word); ok = 0; } } } else { logMessage(LOG_WARNING, "invalid status column count: %s", word); ok = 0; } } } else { logMessage(LOG_WARNING, "invalid text row count: %s", word); ok = 0; } } } else { logMessage(LOG_WARNING, "invalid text column count: %s", word); ok = 0; } } else { logMessage(LOG_WARNING, "missing text column count"); ok = 0; } if (ok) { int count1 = columns1 * rows1; int count2 = columns2 * rows2; unsigned char *braille; wchar_t *text; unsigned char *status; if ((braille = calloc(count1, sizeof(*braille)))) { if ((text = calloc(count1, sizeof(*text)))) { if ((status = calloc(count2, sizeof(*status)))) { brailleColumns = columns1; brailleRows = rows1; brailleCount = count1; statusColumns = columns2; statusRows = rows2; statusCount = count2; if (brailleCells) free(brailleCells); brailleCells = braille; memset(brailleCells, 0, count1); if (textCharacters) free(textCharacters); textCharacters = text; wmemset(textCharacters, WC_C(' '), count1); if (statusCells) free(statusCells); statusCells = status; memset(statusCells, 0, count2); memset(genericCells, 0, GSC_COUNT); brl->textColumns = brailleColumns; brl->textRows = brailleRows; brl->statusColumns = statusColumns; brl->statusRows = statusRows; return 1; } free(text); } free(braille); } } return 0; }
static void setBefore (void) { before = (src == srcmin)? WC_C(' '): src[-1]; }
static void setAfter (int length) { after = (src + length < srcmax)? src[length]: WC_C(' '); }
static int clearVisualText (BrailleDisplay *brl) { wmemset(visualText, WC_C(' '), brl->textColumns); return writeVisualText(brl); }
int cpbLinearCopy (int column, int row) { int copied = 0; ScreenDescription screen; describeScreen(&screen); { int rightColumn = screen.cols - 1; size_t length; wchar_t *buffer = cpbReadScreen(&length, 0, beginRow, rightColumn, row); if (buffer) { if (column < rightColumn) { wchar_t *start = buffer + length; while (start != buffer) { if (*--start == WC_C('\r')) { start += 1; break; } } { int adjustment = (column + 1) - (buffer + length - start); if (adjustment < 0) length += adjustment; } } if (beginColumn) { wchar_t *start = wmemchr(buffer, WC_C('\r'), length); if (!start) start = buffer + length; if ((start - buffer) > beginColumn) start = buffer + beginColumn; if (start != buffer) wmemmove(buffer, start, (length -= start - buffer)); } { const wchar_t *from = buffer; const wchar_t *end = from + length; wchar_t *to = buffer; int spaces = 0; int newlines = 0; while (from != end) { wchar_t character = *from++; switch (character) { case WC_C(' '): spaces += 1; continue; case WC_C('\r'): newlines += 1; continue; default: break; } if (newlines) { if ((newlines > 1) || (spaces > 0)) spaces = 1; newlines = 0; } while (spaces) { *to++ = WC_C(' '); spaces -= 1; } *to++ = character; } length = to - buffer; } if (cpbEndOperation(buffer, length)) copied = 1; free(buffer); } } return copied; }
struct DataFileStruct { const char *name; int line; DataProcessor *processor; void *data; Queue *variables; const wchar_t *start; const wchar_t *end; }; const wchar_t brlDotNumbers[BRL_DOT_COUNT] = { WC_C('1'), WC_C('2'), WC_C('3'), WC_C('4'), WC_C('5'), WC_C('6'), WC_C('7'), WC_C('8') }; const unsigned char brlDotBits[BRL_DOT_COUNT] = { BRL_DOT1, BRL_DOT2, BRL_DOT3, BRL_DOT4, BRL_DOT5, BRL_DOT6, BRL_DOT7, BRL_DOT8 }; int brlDotNumberToIndex (wchar_t number, int *index) { const wchar_t *character = wmemchr(brlDotNumbers, number, ARRAY_COUNT(brlDotNumbers)); if (!character) return 0; *index = character - brlDotNumbers; return 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; }