[unicode] Use unicode when dealing with chars - Part 2

This commit is contained in:
Léa Saviot
2019-01-29 16:51:28 +01:00
committed by Émilie Feral
parent 68db4620ba
commit a214bbdc5a
20 changed files with 186 additions and 127 deletions

View File

@@ -3,6 +3,7 @@
#include "code_icon.h"
#include <apps/i18n.h>
#include "helpers.h"
#include <ion/unicode/utf8_helper.h>
namespace Code {
@@ -47,7 +48,7 @@ bool App::Snapshot::lockOnConsole() const {
void App::Snapshot::setOpt(const char * name, char * value) {
if (strcmp(name, "script") == 0) {
m_scriptStore.deleteAllScripts();
char * separator = strchr(value, ':');
char * separator = const_cast<char *>(UTF8Helper::CodePointSearch(value, ':'));
if (!separator) {
return;
}

View File

@@ -69,17 +69,10 @@ bool EditorController::textAreaDidReceiveEvent(TextArea * textArea, Ion::Events:
if (event == Ion::Events::Backspace) {
/* If the cursor is on the left of the text of a line, backspace one
* indentation space at a time. */
char * text = const_cast<char *>(textArea->text());
const char * charBeforeCursorPointer = textArea->cursorLocation()-1;
int indentationSize = 0;
while (charBeforeCursorPointer >= text && *charBeforeCursorPointer == ' ') {
charBeforeCursorPointer--;
indentationSize++;
}
if (charBeforeCursorPointer >= text
&& *charBeforeCursorPointer == '\n'
&& indentationSize >= k_indentationSpacesNumber)
{
const char * text = textArea->text();
const char * firstNonSpace = UTF8Helper::NotCodePointSearch(text, ' ', true, textArea->cursorLocation());
assert(firstNonSpace >= text);
if (UTF8Helper::CodePointIs(firstNonSpace, '\n') && ((text - firstNonSpace)/UTF8Decoder::CharSizeOfCodePoint(' ')) >= k_indentationSpacesNumber) {
for (int i = 0; i < k_indentationSpacesNumber; i++) {
textArea->removeCodePoint();
}
@@ -88,12 +81,11 @@ bool EditorController::textAreaDidReceiveEvent(TextArea * textArea, Ion::Events:
} else if (event == Ion::Events::Space) {
/* If the cursor is on the left of the text of a line, a space triggers an
* indentation. */
char * text = const_cast<char *>(textArea->text());
const char * charBeforeCursorPointer = textArea->cursorLocation()-1;
while (charBeforeCursorPointer >= text && *charBeforeCursorPointer == ' ') {
charBeforeCursorPointer--;
}
if (charBeforeCursorPointer >= text && *charBeforeCursorPointer == '\n') {
const char * text = textArea->text();
const char * firstNonSpace = UTF8Helper::NotCodePointSearch(text, ' ', true, textArea->cursorLocation());
assert(firstNonSpace >= text);
if (UTF8Helper::CodePointIs(firstNonSpace, '\n')) {
assert(UTF8Decoder::CharSizeOfCodePoint(' ') == 1);
char indentationBuffer[k_indentationSpacesNumber+1];
for (int i = 0; i < k_indentationSpacesNumber; i++) {
indentationBuffer[i] = ' ';

View File

@@ -5,6 +5,7 @@
#include <assert.h>
#include <escher/metric.h>
#include <ion/events.h>
#include <ion/unicode/utf8_decoder.h>
namespace Code {
@@ -303,16 +304,18 @@ bool MenuController::textFieldDidReceiveEvent(TextField * textField, Ion::Events
bool MenuController::textFieldDidFinishEditing(TextField * textField, const char * text, Ion::Events::Event event) {
const char * newName;
static constexpr int bufferSize = Script::k_defaultScriptNameMaxSize + 1 + ScriptStore::k_scriptExtensionLength; //"script99" + "." + "py"
char numberedDefaultName[bufferSize];
if (strlen(text) > 1 + strlen(ScriptStore::k_scriptExtension)) {
newName = text;
} else {
// The user entered an empty name. Use a numbered default script name.
bool foundDefaultName = Script::DefaultName(numberedDefaultName, Script::k_defaultScriptNameMaxSize);
int defaultNameLength = strlen(numberedDefaultName);
assert(defaultNameLength < bufferSize);
assert(UTF8Decoder::CharSizeOfCodePoint('.') == 1);
numberedDefaultName[defaultNameLength++] = '.';
strlcpy(&numberedDefaultName[defaultNameLength], ScriptStore::k_scriptExtension, bufferSize - defaultNameLength);
strlcpy(numberedDefaultName + defaultNameLength, ScriptStore::k_scriptExtension, bufferSize - defaultNameLength);
/* If there are already scripts named script1.py, script2.py,... until
* Script::k_maxNumberOfDefaultScriptNames, we want to write the last tried
* default name and let the user modify it. */

View File

@@ -328,9 +328,12 @@ bool PythonToolbox::handleEvent(Ion::Events::Event event) {
if (Toolbox::handleEvent(event)) {
return true;
}
if (event.hasText() && strlen(event.text()) == 1) {
scrollToLetter(event.text()[0]);
return true;
if (event.hasText() && strlen(event.text()) == 1 ) {
char c = event.text()[0];
if (UTF8Helper::CodePointIsLetter(c)) {
scrollToLetter(c);
return true;
}
}
return false;
}
@@ -387,24 +390,24 @@ int PythonToolbox::maxNumberOfDisplayedRows() {
}
void PythonToolbox::scrollToLetter(char letter) {
assert(UTF8Helper::CodePointIsLetter(letter));
/* We look for a child MessageTree that starts with the wanted letter. If we
* do not find one, we scroll to the first child MessageTree that starts with
* a letter higher than the wanted letter. */
char lowerLetter = tolower(letter);
// We look for a child MessageTree that starts with the wanted letter.
int index = -1;
for (int i = 0; i < m_messageTreeModel->numberOfChildren(); i++) {
char currentFirstLetterLowered = tolower(I18n::translate(m_messageTreeModel->children(i)->label())[0]);
if (currentFirstLetterLowered == lowerLetter) {
scrollToAndSelectChild(i);
return;
char l = tolower(I18n::translate(m_messageTreeModel->children(i)->label())[0]);
if (l == lowerLetter) {
index = i;
break;
}
if (index < 0 && l >= lowerLetter && UTF8Helper::CodePointIsLowerCaseLetter(l)) {
index = i;
}
}
// We did not find a child MessageTree that starts with the wanted letter.
// We scroll to the first child MessageTree that starts with a letter higher
// than the wanted letter.
for (int i = 0; i < m_messageTreeModel->numberOfChildren(); i++) {
char currentFirstLetterLowered = tolower(I18n::translate(m_messageTreeModel->children(i)->label())[0]);
if (currentFirstLetterLowered >= lowerLetter && currentFirstLetterLowered <= 'z') {
scrollToAndSelectChild(i);
return;
}
if (index >= 0) {
scrollToAndSelectChild(index);
}
}

View File

@@ -5,8 +5,8 @@ namespace Code {
static inline void intToText(int i, char * buffer, int bufferSize) {
// We only support integers from 0 to 99.
assert(i>=0);
assert(i<100);
assert(i >= 0);
assert(i < 100);
assert(bufferSize >= 3);
if (i/10 == 0) {
buffer[0] = i+'0';
@@ -37,13 +37,6 @@ bool Script::DefaultName(char buffer[], size_t bufferSize) {
return false;
}
bool isSmallLetterOrUnderscoreChar(const char c) {
return (c >= 'a' && c <= 'z') || c == '_';
}
bool isNumberChar(const char c) {
return c >= '0' && c <= '9';
}
bool Script::nameCompliant(const char * name) {
/* We allow here the empty script name ".py", because it is the name used to
* create a new empty script. When naming or renaming a script, we check
@@ -53,20 +46,21 @@ bool Script::nameCompliant(const char * name) {
* We do not allow upper cases in the script names because script names are
* used in the URLs of the NumWorks workshop website and we do not want
* problems with case sensitivity. */
const char * c = name;
if (*c == 0 || (!isSmallLetterOrUnderscoreChar(*c) && *c != '.')) {
UTF8Decoder decoder(name);
CodePoint c = decoder.nextCodePoint();
if (c == UCodePointNull || !(UTF8Helper::CodePointIsLowerCaseLetter(c) || c == '_' || c == '.')) {
/* The name cannot be empty. Its first letter must be in [a-z_] or the
* extension dot. */
return false;
}
while (*c != 0) {
if (*c == '.' && strcmp(c+1, ScriptStore::k_scriptExtension) == 0) {
while (c != UCodePointNull) {
if (c == '.' && strcmp(decoder.stringPosition(), ScriptStore::k_scriptExtension) == 0) {
return true;
}
if (!isSmallLetterOrUnderscoreChar(*c) && !isNumberChar(*c)) {
if (!(UTF8Helper::CodePointIsLowerCaseLetter(c) || c == '_' || UTF8Helper::CodePointIsNumber(c))) {
return false;
}
c++;
c = decoder.nextCodePoint();
}
return false;
}
@@ -86,7 +80,7 @@ void Script::toggleImportationStatus() {
const char * Script::readContent() const {
assert(!isNull());
Data d = value();
return (const char *)d.buffer+k_importationStatusSize;
return (const char *)d.buffer + k_importationStatusSize;
}
}

View File

@@ -6,6 +6,7 @@
#include <assert.h>
#include <escher/buffer_text_view.h>
#include <escher/palette.h>
#include <ion/unicode/utf8_helper.h>
#include <string.h>
namespace Code {
@@ -41,7 +42,7 @@ static bool shouldAddObject(const char * name, int maxLength) {
return false;
}
assert(name != nullptr);
if (name[0] == '_') {
if (UTF8Helper::CodePointIs(name, '_')) {
return false;
}
return true;

View File

@@ -23,6 +23,8 @@ using namespace Shared;
namespace Probability {
static inline int minInt(int x, int y) { return x < y ? x : y; }
CalculationController::ContentView::ContentView(SelectableTableView * selectableTableView, Law * law, Calculation * calculation) :
m_titleView(KDFont::SmallFont, I18n::Message::ComputeProbability, 0.5f, 0.5f, Palette::GreyDark, Palette::WallScreen),
m_selectableTableView(selectableTableView),
@@ -285,17 +287,17 @@ void CalculationController::updateTitle() {
if (currentChar >= k_maxNumberOfTitleCharacters) {
break;
}
const size_t bufferSize = PrintFloat::bufferSizeForFloatsWithPrecision(Constant::ShortNumberOfSignificantDigits);
constexpr size_t bufferSize = PrintFloat::bufferSizeForFloatsWithPrecision(Constant::ShortNumberOfSignificantDigits);
char buffer[bufferSize];
PrintFloat::convertFloatToText<double>(m_law->parameterValueAtIndex(index), buffer, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::ShortNumberOfSignificantDigits), Constant::ShortNumberOfSignificantDigits, Preferences::PrintFloatMode::Decimal);
PrintFloat::convertFloatToText<double>(m_law->parameterValueAtIndex(index), buffer, bufferSize, Constant::ShortNumberOfSignificantDigits, Preferences::PrintFloatMode::Decimal);
strlcpy(m_titleBuffer+currentChar, buffer, k_maxNumberOfTitleCharacters - currentChar);
currentChar += strlen(buffer);
if (currentChar >= k_maxNumberOfTitleCharacters) {
break;
}
m_titleBuffer[currentChar++] = ' ';
currentChar += UTF8Decoder::CodePointToChars(' ', m_titleBuffer + currentChar, k_maxNumberOfTitleCharacters - currentChar);
}
m_titleBuffer[currentChar-1] = 0;
m_titleBuffer[minInt(currentChar, k_maxNumberOfTitleCharacters) - 1] = 0;
}
}

View File

@@ -127,6 +127,7 @@ void GraphController::reloadBannerView() {
}
numberOfChar += strlcpy(buffer, legend, bufferSize);
numberOfChar += PoincareHelpers::ConvertFloatToText<double>(x, buffer+numberOfChar, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::MediumNumberOfSignificantDigits), Constant::MediumNumberOfSignificantDigits);
assert(UTF8Decoder::CharSizeOfCodePoint(' ') == 1);
for (int i = numberOfChar; i < k_maxLegendLength; i++) {
buffer[numberOfChar++] = ' ';
}

View File

@@ -4,6 +4,7 @@
#include <poincare/derivative.h>
#include <poincare/integral.h>
#include <escher/palette.h>
#include <ion/unicode/utf8_decoder.h>
#include <float.h>
#include <cmath>
@@ -64,16 +65,17 @@ StorageCartesianFunction StorageCartesianFunction::NewModel(Ion::Storage::Record
}
int StorageCartesianFunction::derivativeNameWithArgument(char * buffer, size_t bufferSize, char arg) {
// Fill buffer with f(x). Keep one char for derivative sign.
int numberOfChars = nameWithArgument(buffer, bufferSize-1, arg);
assert(numberOfChars + 1 < bufferSize);
char * lastChar = buffer+numberOfChars;
do {
*(lastChar+1) = *lastChar;
lastChar--;
} while (*(lastChar+1) != '(' && lastChar >= buffer);
*(lastChar+1) = '\'';
return numberOfChars+1;
// Fill buffer with f(x). Keep one char foderivativeSizer derivative sign.
int derivativeSize = UTF8Decoder::CharSizeOfCodePoint('\'');
int numberOfChars = nameWithArgument(buffer, bufferSize - derivativeSize, arg);
assert(numberOfChars + derivativeSize < bufferSize);
char * firstParenthesis = const_cast<char *>(UTF8Helper::CodePointSearch(buffer, '('));
if (!UTF8Helper::CodePointIs(firstParenthesis, '(')) {
return numberOfChars;
}
memmove(firstParenthesis + derivativeSize, firstParenthesis, buffer + numberOfChars - firstParenthesis);
UTF8Decoder::CodePointToChars('\'', firstParenthesis, derivativeSize);
return numberOfChars + derivativeSize;
}
bool StorageCartesianFunction::displayDerivative() const {

View File

@@ -1,7 +1,10 @@
#include "storage_function.h"
#include "poincare_helpers.h"
#include <poincare/serialization_helper.h>
#include <poincare/symbol.h>
#include "poincare/src/parsing/parser.h"
#include <ion/unicode/utf8_helper.h>
#include <ion/unicode/utf8_decoder.h>
#include <string.h>
#include <cmath>
#include <assert.h>
@@ -14,7 +17,10 @@ constexpr char StorageFunction::k_parenthesedArgument[];
bool StorageFunction::BaseNameCompliant(const char * baseName, NameNotCompliantError * error) {
assert(baseName[0] != 0);
if (baseName[0] >= '0' && baseName[0] <= '9') {
UTF8Decoder decoder(baseName);
CodePoint c = decoder.nextCodePoint();
if (UTF8Helper::CodePointIsNumber(c)) {
// The name cannot start with a number
if (error != nullptr) {
*error = NameNotCompliantError::NameCannotStartWithNumber;
@@ -22,21 +28,19 @@ bool StorageFunction::BaseNameCompliant(const char * baseName, NameNotCompliantE
return false;
}
const char * currentChar = baseName;
// The name should only have allowed characters
while (*currentChar != 0) {
if (!((*currentChar >= 'A' && *currentChar <= 'Z')
|| (*currentChar >= 'a' && *currentChar <= 'z')
|| (*currentChar >= '0' && *currentChar <= '9')
|| *currentChar == '_'))
while (c != UCodePointNull) {
if (!(UTF8Helper::CodePointIsUpperCaseLetter(c)
|| UTF8Helper::CodePointIsLowerCaseLetter(c)
|| UTF8Helper::CodePointIsNumber(c))
|| c == '_')
{
if (error != nullptr) {
*error = NameNotCompliantError::CharacterNotAllowed;
}
return false;
}
currentChar++;
c = decoder.nextCodePoint();
}
// The name should not be a reserved name
@@ -76,7 +80,9 @@ T StorageFunction::templatedApproximateAtAbscissa(T x, Poincare::Context * conte
if (isCircularlyDefined(context)) {
return NAN;
}
const char unknownX[2] = {Poincare::Symbol::UnknownX, 0};
constexpr int bufferSize = CodePoint::MaxCodePointCharLength + 1;
char unknownX[bufferSize];
Poincare::SerializationHelper::CodePoint(unknownX, bufferSize, Poincare::Symbol::UnknownX);
return PoincareHelpers::ApproximateWithValueForSymbol(expressionReduced(context), unknownX, x, *context);
}

View File

@@ -33,45 +33,49 @@ void TextToInsertForCommandMessage(I18n::Message message, char * buffer, int buf
}
void TextToInsertForCommandText(const char * command, char * buffer, int bufferSize, bool replaceArgsWithEmptyChar) {
int currentNewTextIndex = 0;
int index = 0;
int numberOfOpenParentheses = 0;
int numberOfOpenBrackets = 0;
bool insideQuote = false;
bool argumentAlreadyReplaced = false;
size_t commandLength = strlen(command);
for (size_t i = 0; i < commandLength; i++) {
if (command[i] == ')') {
UTF8Decoder decoder(command);
CodePoint codePoint = decoder.nextCodePoint();
while (codePoint != UCodePointNull) {
if (codePoint == ')') {
numberOfOpenParentheses--;
}
if (command[i] == ']') {
} else if (codePoint == ']') {
numberOfOpenBrackets--;
}
if (((numberOfOpenParentheses == 0 && numberOfOpenBrackets == 0)
|| command[i] == ','
|| (numberOfOpenBrackets > 0 && (command[i] == ',' || command[i] == '[' || command[i] == ']')))
&& (!insideQuote || command[i] == '\'')) {
assert(currentNewTextIndex < bufferSize);
if ((!insideQuote || codePoint == '\'')
&& ((numberOfOpenParentheses == 0 && numberOfOpenBrackets == 0)
|| codePoint == ','
|| (numberOfOpenBrackets > 0
&& (codePoint == ','
|| codePoint == '['
|| codePoint == ']'))))
{
assert(index < bufferSize);
if (argumentAlreadyReplaced) {
argumentAlreadyReplaced = false;
}
buffer[currentNewTextIndex++] = command[i];
index += UTF8Decoder::CodePointToChars(codePoint, buffer + index, bufferSize - index);
} else {
if (replaceArgsWithEmptyChar && !argumentAlreadyReplaced) {
currentNewTextIndex += UTF8Decoder::CodePointToChars(UCodePointEmpty, buffer + currentNewTextIndex, bufferSize - currentNewTextIndex);
index += UTF8Decoder::CodePointToChars(UCodePointEmpty, buffer + index, bufferSize - index);
argumentAlreadyReplaced = true;
}
}
if (command[i] == '(') {
if (codePoint == '(') {
numberOfOpenParentheses++;
}
if (command[i] == '[') {
} else if (codePoint == '[') {
numberOfOpenBrackets++;
}
if (command[i] == '\'') {
} else if (codePoint == '\'') {
insideQuote = !insideQuote;
}
codePoint = decoder.nextCodePoint();
}
buffer[currentNewTextIndex] = 0;
buffer[index] = 0;
}
}

View File

@@ -14,12 +14,10 @@ ValuesFunctionParameterController::ValuesFunctionParameterController(char symbol
const char * ValuesFunctionParameterController::title() {
strlcpy(m_pageTitle, I18n::translate(I18n::Message::FunctionColumn), k_maxNumberOfCharsInTitle);
for (int currentChar = 0; currentChar < k_maxNumberOfCharsInTitle-1; currentChar++) {
if (m_pageTitle[currentChar] == '(') {
m_pageTitle[currentChar-1] = *m_function->name();
m_pageTitle[currentChar+1] = m_symbol;
break;
}
char * parenthesis = const_cast<char *>(UTF8Helper::CodePointSearch(m_pageTitle, '('));
if (UTF8Helper::CodePointIs(parenthesis, '(') && parenthesis > m_pageTitle && parenthesis < m_pageTitle + k_maxNumberOfCharsInTitle) {
*(m_pageTitle - 1) = *m_function->name();
*(m_pageTitle + 1) = m_symbol;
}
return m_pageTitle;
}

View File

@@ -115,10 +115,8 @@ void ListController::didEnterResponderChain(Responder * previousFirstResponder)
}
bool textRepresentsAnEquality(const char * text) {
if (strchr(text, '=')) {
return true;
}
return false;
char equal = '=';
return UTF8Helper::CodePointIs(UTF8Helper::CodePointSearch(text, equal), equal);
}
bool layoutRepresentsAnEquality(Poincare::Layout l) {

View File

@@ -51,11 +51,13 @@ void BoxController::reloadBannerView() {
m_view.editableBannerView()->setMessageAtIndex(calculationName[selectedQuantile], 1);
// Set calculation result
char buffer[PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits) + 1];
assert(UTF8Decoder::CharSizeOfCodePoint(' ') == 1);
constexpr int bufferSize = PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits) + 1;
char buffer[bufferSize];
CalculPointer calculationMethods[5] = {&Store::minValue, &Store::firstQuartile, &Store::median, &Store::thirdQuartile,
&Store::maxValue};
double calculation = (m_store->*calculationMethods[selectedQuantile])(selectedSeriesIndex());
int numberOfChar = PoincareHelpers::ConvertFloatToText<double>(calculation, buffer, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits);
int numberOfChar = PoincareHelpers::ConvertFloatToText<double>(calculation, buffer, bufferSize - 1, Constant::LargeNumberOfSignificantDigits);
buffer[numberOfChar++] = ' ';
buffer[numberOfChar] = 0;
m_view.editableBannerView()->setLegendAtIndex(buffer, 2);

View File

@@ -94,7 +94,7 @@ void HistogramController::reloadBannerView() {
if (selectedSeriesIndex() < 0) {
return;
}
const size_t bufferSize = k_maxNumberOfCharacters+ PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)*2;
const size_t bufferSize = k_maxNumberOfCharacters + PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)*2;
char buffer[bufferSize];
int numberOfChar = 0;
@@ -110,18 +110,18 @@ void HistogramController::reloadBannerView() {
numberOfChar += PoincareHelpers::ConvertFloatToText<double>(lowerBound, buffer+numberOfChar, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits);
}
buffer[numberOfChar++] = ';';
numberOfChar+= UTF8Decoder::CodePointToChars(';', buffer + numberOfChar, bufferSize - numberOfChar);
// Add upper bound
if (selectedSeriesIndex() >= 0) {
double upperBound = m_store->endOfBarAtIndex(selectedSeriesIndex(), *m_selectedBarIndex);
numberOfChar += PoincareHelpers::ConvertFloatToText<double>(upperBound, buffer+numberOfChar, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits);
}
buffer[numberOfChar++] = '[';
numberOfChar+= UTF8Decoder::CodePointToChars('[', buffer + numberOfChar, bufferSize - numberOfChar);
// Padding
for (int i = numberOfChar; i < k_maxIntervalLegendLength; i++) {
buffer[numberOfChar++] = ' ';
numberOfChar+= UTF8Decoder::CodePointToChars(' ', buffer + numberOfChar, bufferSize - numberOfChar);
}
buffer[k_maxIntervalLegendLength] = 0;
m_view.editableBannerView()->setLegendAtIndex(buffer, 1);
@@ -139,7 +139,7 @@ void HistogramController::reloadBannerView() {
}
// Padding
for (int i = numberOfChar; i < k_maxLegendLength; i++) {
buffer[numberOfChar++] = ' ';
numberOfChar+= UTF8Decoder::CodePointToChars(' ', buffer + numberOfChar, bufferSize - numberOfChar);
}
buffer[k_maxLegendLength] = 0;
m_view.editableBannerView()->setLegendAtIndex(buffer, 3);
@@ -156,7 +156,7 @@ void HistogramController::reloadBannerView() {
}
// Padding
for (int i = numberOfChar; i < k_maxLegendLength; i++) {
buffer[numberOfChar++] = ' ';
numberOfChar+= UTF8Decoder::CodePointToChars(' ', buffer + numberOfChar, bufferSize - numberOfChar);
}
buffer[k_maxLegendLength] = 0;
m_view.editableBannerView()->setLegendAtIndex(buffer, 5);

View File

@@ -200,11 +200,11 @@ bool VariableBoxController::selectLeaf(int selectedRow) {
if (m_currentPage == Page::Function) {
// Add parentheses to a function name
assert(nameLength < nameToHandleMaxSize);
nameToHandle[nameLength++] = '(';
nameLength += UTF8Decoder::CodePointToChars('(', nameToHandle+nameLength, nameToHandleMaxSize - nameLength);
assert(nameLength < nameToHandleMaxSize);
nameLength+= UTF8Decoder::CodePointToChars(UCodePointEmpty, nameToHandle+nameLength, nameToHandleMaxSize - nameLength);
assert(nameLength < nameToHandleMaxSize);
nameToHandle[nameLength++] = ')';
nameLength += UTF8Decoder::CodePointToChars(')', nameToHandle+nameLength, nameToHandleMaxSize - nameLength);
assert(nameLength < nameToHandleMaxSize);
nameToHandle[nameLength] = 0;
}

View File

@@ -192,10 +192,12 @@ void TextArea::Text::insertSpacesAtLocation(int numberOfSpaces, char * location)
assert(strlen(m_buffer) + numberOfSpaces < m_bufferSize);
size_t sizeToMove = strlen(location) + 1;
assert(location + numberOfSpaces + sizeToMove <= m_buffer + m_bufferSize);
memmove(location + numberOfSpaces, location, sizeToMove);
size_t spaceCharSize = UTF8Decoder::CharSizeOfCodePoint(' ');
size_t spacesSize = numberOfSpaces * spaceCharSize;
assert(location + spacesSize + sizeToMove <= m_buffer + m_bufferSize);
memmove(location + spacesSize, location, sizeToMove);
for (int i = 0; i < numberOfSpaces; i++) {
*(location+i) = ' ';
UTF8Decoder::CodePointToChars(' ', location+i*spaceCharSize, (m_buffer + m_bufferSize) - location);
}
}

View File

@@ -13,6 +13,10 @@ int CountOccurrences(const char * s, CodePoint c);
* null terminating char otherwise. */
const char * CodePointSearch(const char * s, CodePoint c);
/* Returns the first occurence of a code point that is not c in a string,
* stopping at the null-terminating char or the start of string. */
const char * NotCodePointSearch(const char * s, CodePoint c, bool goingLeft, const char * initialPosition);
/* Copy src into dst while removing all code points c. Also update an index
* that should be lower if code points where removed before it. Ensure null-
* termination of dst. */
@@ -28,24 +32,29 @@ size_t CopyUntilCodePoint(char * dst, size_t dstSize, const char * src, CodePoin
* done for *(initial position) even if it matches c.
* The return value is the first address for which we did not perform an action.
*
* r = return value
* x = actionCodePoint is performed
* o = actionOtherCodePoint is performed
* Going right == true: s = stoppingCodePoint
* o o o o x x o o x o
* | | | | |c |c | | |c | |s | | |c |
* ^start of string
* ^start of string ^r
*
* Going right == false:
* o o o o x x o o
* | |c | |s |c |c | | |c | | |c | | |
* ^start of string ^initialPosition
* x x o o
* | |c | | |c | |s |c |c | | |c | | |
* ^start of string ^r ^initialPosition
*
* */
typedef void (*CodePointAction)(int codePointOffset, void * contextPointer, int contextInt);
const char * PerformAtCodePoints(const char * string, CodePoint c, CodePointAction actionCodePoint, CodePointAction actionOtherCodePoint, void * contextPointer, int contextInt, CodePoint stoppingCodePoint = UCodePointNull, bool goingRight = true, const char * initialPosition = nullptr);
const char * PerformAtCodePoints(const char * string, CodePoint c, CodePointAction actionCodePoint, CodePointAction actionOtherCodePoint, void * contextPointer, int contextInt, CodePoint stoppingCodePoint = UCodePointNull, bool goingRight = true, const char * initialPosition = nullptr);
bool PreviousCodePointIs(const char * buffer, const char * location, CodePoint c);
bool CodePointIs(const char * location, CodePoint c);
bool CodePointIsLetter(CodePoint c);
bool CodePointIsLowerCaseLetter(CodePoint c);
bool CodePointIsUpperCaseLetter(CodePoint c);
bool CodePointIsNumber(CodePoint c);
// Shift the buffer and return the number of bytes removed.
int RemovePreviousCodePoint(const char * text, char * location, CodePoint * c);

View File

@@ -54,6 +54,32 @@ const char * CodePointSearch(const char * s, CodePoint c) {
return currentPointer;
}
const char * NotCodePointSearch(const char * s, CodePoint c, bool goingLeft, const char * initialPosition) {
if (goingLeft) {
assert(initialPosition != nullptr);
if (initialPosition == s) {
return s;
}
UTF8Decoder decoder(s, initialPosition);
CodePoint codePoint = decoder.previousCodePoint();
const char * codePointPointer = decoder.stringPosition();
while (codePointPointer > s && codePoint == c) {
codePoint = decoder.previousCodePoint();
codePointPointer = decoder.stringPosition();
}
return codePointPointer;
}
assert(!goingLeft && initialPosition == nullptr);
UTF8Decoder decoder(s);
const char * codePointPointer = decoder.stringPosition();
CodePoint codePoint = decoder.nextCodePoint();
while (codePoint != UCodePointNull && codePoint == c) {
codePointPointer = decoder.stringPosition();
codePoint = decoder.nextCodePoint();
}
return codePointPointer;
}
void CopyAndRemoveCodePoint(char * dst, size_t dstSize, const char * src, CodePoint c, const char * * pointerToUpdate) {
if (dstSize <= 0) {
return;
@@ -189,6 +215,22 @@ bool CodePointIs(const char * location, CodePoint c) {
return decoder.nextCodePoint() == c;
}
bool CodePointIsLetter(CodePoint c) {
return CodePointIsLowerCaseLetter(c) || CodePointIsUpperCaseLetter(c);
}
bool CodePointIsLowerCaseLetter(CodePoint c) {
return c >= 'a' && c <= 'z';
}
bool CodePointIsUpperCaseLetter(CodePoint c) {
return c >= 'A' && c <= 'Z';
}
bool CodePointIsNumber(CodePoint c) {
return c >= '0' && c <= '9';
}
int RemovePreviousCodePoint(const char * text, char * location, CodePoint * c) {
assert(c != nullptr);
if (location <= text) {

View File

@@ -169,8 +169,7 @@ int IntegralLayoutNode::serialize(char * buffer, int bufferSize, Preferences::Pr
for (uint8_t i = 0; i < sizeof(argLayouts)/sizeof(argLayouts[0]); i++) {
if (i != 0) {
// Write the comma
buffer[numberOfChar++] = ',';
numberOfChar += SerializationHelper::CodePoint(buffer + numberOfChar, bufferSize - numberOfChar, '(');
numberOfChar += SerializationHelper::CodePoint(buffer + numberOfChar, bufferSize - numberOfChar, ',');
if (numberOfChar >= bufferSize-1) { return bufferSize-1; }
}