mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-19 00:37:25 +01:00
[unicode] Use unicode when dealing with chars - Part 2
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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] = ' ';
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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++] = ' ';
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user