[BRLTTY] Low-level BrlAPI questions
Aura Kelloniemi
kaura.dev at sange.fi
Thu Apr 15 09:34:24 EDT 2021
On 2021-04-15 at 08:55 -0400, Dave Mielke <Dave at mielke.cc> wrote:
> [quoted lines by Aura Kelloniemi on 2021/04/15 at 15:36 +0300]
> >If brlapi__writeTextUtf8 is added so that it does not rely on the
> >NUL-terminator but has a size parameter, I am done with this discussion.
> Well, I think it should be easy to write a UTF-8 string, and easy shouldn't require the programmer to have to calculate the UTF-8 character count. The programmer should, in the simple case, still be able to pass nothing more than a quoted string.
Size is a dreaded word in this discussion because of its ambiguity. In the
paragraph quoted above, I used the word size to mean the size of the text
string in bytes, and not the number of Unicode code points it contains.
Anyways, for a C programmer it certainly is easiest to pass in a quoted
string, and let the library to call strlen on it. But a binding writer needs
to copy the user-supplied string to a newly allocated memory location in heap,
append the NUL byte, and then call the write function, if the write function
does not provide a size argument.
I paste here my implementation of brlapi__writeText which is quite complex,
because it avoids copying the input string, if it contains the right number of
characters. This works, but is inefficient. In the code below, write_generic
calls brlapi__write with parameter and result value marshalling. Self is the
wrapped BrlAPI connection object.
pub fn write_text<S: AsRef<str>>(&self, text: S, cursor: Cursor) -> Result<()> {
let text = text.as_ref(); // Allow passing in a String object or a string reference
let size = self.get_display_size_cells()?; // cols * rows
// Find the number of characters in text and the last index that will fit the display.
let mut chars = 0;
let mut end_index = None;
for (idx, ch) in text.char_indices() {
chars += 1;
if chars == size {
end_index = Some(idx + ch.len_utf8());
break;
}
}
if chars < size {
// The text is too short for the display, and needs to be padded
let missing = size - chars;
// Copy text to an a 8-bit integer vector and pad it to fill the whole display
let bytes_size = text.len() + missing;
let mut bytes = Vec::with_capacity(bytes_size); // Allocate vector
bytes.extend_from_slice(text.as_bytes()); // Do the copy
bytes.resize(bytes_size, b' '); // Pad text. Th character used here does not really matter
// Use and_mask to hide all characters after the end of text
let mut and_mask = Vec::with_capacity(size); // Allocate andMask
and_mask.resize(chars, 0b1111_1111); // Pass all user text as is
and_mask.resize(size, 0); // Mask away everything after the real text ends
self.write_generic(
None, // Display number
0, // regionBegin
size, // regionSize
Some(&bytes), // text and textSize
Some(&and_mask), // andMask
None, // orMask
cursor, // Cursor position
Some("utf-8"), // Character set
)
} else {
// Text either fit exactly or is too long. Pass a substring to BrlAPI.
let end_index = end_index.unwrap_or_else(|| text.len()); // Choose the last showable character's index or the text's length
self.write_generic(
None, // Display number
0, // regionBegin
chars, // regionSize
Some(&text.as_bytes()[..end_index]), // text and textSize
None, // andMask
None, // orMask
cursor, // Cursor position
Some("utf-8"), // Character set
)
}
}
--
Aura
More information about the BRLTTY
mailing list