diff --git a/.build/preproc/ctags_target_for_gcc_minus_e.cpp b/.build/preproc/ctags_target_for_gcc_minus_e.cpp index c8f442e3a3bfc234fe3ac9ef0b7c4803b9387270..dccc70e4a9a19cd8254d3a4610a25afaab148835 100644 --- a/.build/preproc/ctags_target_for_gcc_minus_e.cpp +++ b/.build/preproc/ctags_target_for_gcc_minus_e.cpp @@ -8,46 +8,45 @@ void setup() // Initialisieren der seriellen Verbindung Serial.begin(115200); - // Definieren der Kopfzeilen und Spaltenbreiten für 8 Spalten - const char *headers[] = {"Vorname", "Nachname", "Alter", "Stadt", "Beruf", "Unternehmen", "Hobby", "Bemerkung"}; - int columnWidths[] = {10, 15, 5, 10, 10, 15, 10, 20}; + // Definieren der Kopfzeilen und Spaltenbreiten für 8 Spalten + const char *headers[] = {"Vorname", "Nachname", "Alter", "Stadt", "Beruf", "Unternehmen", "Hobby", "Bemerkung"}; + int columnWidths[] = {10, 15, 5, 10, 10, 15, 10, 20}; - SerialTable table(headers, columnWidths, 8, true, true); - table.printHeader(); + SerialTable table(headers, columnWidths, 8, true, true); + table.printHeader(); - // Erstellen von 20 Zeilen mit unterschiedlichen Einträgen - char *rows[20][8] = { - {"Alice", "Wonderland", "30", "Köln", "Ingenieur", "FirmaX", "Schwimmen", "Keine"}, - {"Bob", "Builder\nJr", "35", "Berlin", "Architekt", "Architektur AG", "Bauen", "Sehr erfahren"}, - {"Charlie", "Brown", "28", "Hamburg", "Designer", "Die Design", "Zeichnen", "Mag Karikaturen"}, - {"David", "Tennant", "40", "München", "Schauspieler", "Freiberufler", "Lesen", "Doktor gewesen"}, - {"Emma", "Watson", "33", "Frankfurt", "Schauspielerin", "Independent", "Yoga", "Bekannt aus Filmen"}, - {"Frank", "Herbert", "45", "Stuttgart", "Autor", "Ein Verlag", "Schreiben", "Bücher geschrieben"}, - {"Grace", "Hopper", "50", "Berlin", "Programmiererin", "Tech Corp", "Informatik", "Pionierin"}, - {"Hugo", "Strange", "60", "Leipzig", "Psychiater", "Gesundheits GmbH", "Philosophie", "Ruhestand"}, - {"Irene", "Adler", "29", "Dresden", "Detektivin", "Privat", "Abenteuer", "Scharfsinnig"}, - {"John", "Doe", "49", "Bremen", "Buchhalter", "Kontorechner", "Radfahren", "Gewissenhaft"}, - {"Klara", "Kühn", "39", "Hannover", "Lehrerin", "Schule ABC", "Lesen", "Einfühlsam"}, - {"Lenny", "Small", "25", "Koblenz", "Musiker", "Orchester", "Gitarre", "Kreativ"}, - {"Mona", "Lisa", "33", "Siegen", "Malerin", "Kunsthaus", "Kunst", "Geheimnisvoll"}, - {"Nina", "Simone", "30", "Essen", "Sängerin", "Soul Musik", "Musik", "Talentiert"}, - {"Oliver", "Twist", "19", "Potsdam", "Student", "Uni XY", "Fußball", "Engagiert"}, - {"Pam", "Beesly", "32", "Wuppertal", "Sekretärin", "Dunder Mifflin", "Malen", "Freundlich"}, - {"Quinn", "Fabray", "26", "Magdeburg", "Designer", "Agentur XYZ", "Tanzen", "Kreativ"}, - {"Ron", "Swanson", "55", "Bielefeld", "Verwalter", "Rathaus", "Holzarbeiten", "Direkt"}, - {"Sophia", "Loren", "70", "Osnabrück", "Schauspielerin", "Independent", "Kochen", "Ikonisch"}, - {"Tom", "Hanson", "36", "Regensburg", "Polizist", "Polizei", "Jagen", "Schützend"}, - }; - - // Drucke die Zeilen - for (int i = 0; i < 20; ++i) - { - table.printRow(rows[i]); - } + // Erstellen von 20 Zeilen mit unterschiedlichen Einträgen + char *rows[20][8] = { + {"Alice", "Wonderland", "30", "Köln", "Ingenieur", "FirmaX", "Schwimmen", "Keine"}, + {"Bob", "Builder\nJr", "35", "Berlin", "Architekt", "Architektur AG", "Bauen", "Sehr erfahren"}, + {"Charlie", "Brown", "28", "Hamburg", "Designer", "Die Design", "Zeichnen", "Mag Karikaturen"}, + {"David", "Tennant", "40", "München", "Schauspieler", "Freiberufler", "Lesen", "Doktor gewesen"}, + {"Emma", "Watson", "33", "Frankfurt", "Schauspielerin", "Independent", "Yoga", "Bekannt aus Filmen"}, + {"Frank", "Herbert", "45", "Stuttgart", "Autor", "Ein Verlag", "Schreiben", "Bücher geschrieben"}, + {"Grace", "Hopper", "50", "Berlin", "Programmiererin", "Tech Corp", "Informatik", "Pionierin"}, + {"Hugo", "Strange", "60", "Leipzig", "Psychiater", "Gesundheits GmbH", "Philosophie", "Ruhestand"}, + {"Irene", "Adler", "29", "Dresden", "Detektivin", "Privat", "Abenteuer", "Scharfsinnig"}, + {"John", "Doe", "49", "Bremen", "Buchhalter", "Kontorechner", "Radfahren", "Gewissenhaft"}, + {"Klara", "Kühn", "39", "Hannover", "Lehrerin", "Schule ABC", "Lesen", "Einfühlsam"}, + {"Lenny", "Small", "25", "Koblenz", "Musiker", "Orchester", "Gitarre", "Kreativ"}, + {"Mona", "Lisa", "33", "Siegen", "Malerin", "Kunsthaus", "Kunst", "Geheimnisvoll"}, + {"Nina", "Simone", "30", "Essen", "Sängerin", "Soul Musik", "Musik", "Talentiert"}, + {"Oliver", "Twist", "19", "Potsdam", "Student", "Uni XY", "Fußball", "Engagiert"}, + {"Pam", "Beesly", "32", "Wuppertal", "Sekretärin", "Dunder Mifflin", "Malen", "Freundlich"}, + {"Quinn", "Fabray", "26", "Magdeburg", "Designer", "Agentur XYZ", "Tanzen", "Kreativ"}, + {"Ron", "Swanson", "55", "Bielefeld", "Verwalter", "Rathaus", "Holzarbeiten", "Direkt"}, + {"Sophia", "Loren", "70", "Osnabrück", "Schauspielerin", "Independent", "Kochen", "Ikonisch"}, + {"Tom", "Hanson", "36", "Regensburg", "Polizist", "Polizei", "Jagen", "Schützend"}, + }; + // Drucke die Zeilen + for (int i = 0; i < 20; ++i) + { + table.printRow(rows[i]); + } } void loop() { - //TestRunner::run(); + // TestRunner::run(); } diff --git a/SerialTable.h b/SerialTable.h index 11b48b8335d8e230dddb1a8c0d281582e75bbdf3..2893d52a15421c762198f8397749b885bd60b98c 100644 --- a/SerialTable.h +++ b/SerialTable.h @@ -18,107 +18,89 @@ public: String buildHeader() { - return buildLine('-') + buildRow(const_cast<char **>(headers), '='); // Kopfzeile mit '=' + return buildLine('-') + buildRow(headers, '='); // Kopfzeile mit '=' } + //const_cast<char **>(...) - void printRow(char **t_row) + void printRow(const char **t_row) { String row = buildRow(t_row); Serial.print(row); } - String buildRow(char **t_row, char line = '-') + String buildRow(const char **t_row, char line = '-') { String output; - char buffer[256]; + char buffer[MAX_STRING_SIZE]; int maxLines = 1; // Maximale Anzahl Zeilen über alle Spalten - - // Erste Phase: Teile jede Zelle in Zeilen und finde maximale Zeilenzahl + char tempBuffers[size][MAX_STRING_SIZE]; // Array to store processed strings + + // Erste Phase: Verarbeite jede Zelle und finde maximale Zeilenzahl for (size_t i = 0; i < size; ++i) { - if (doReplaceUmlauts) - replaceUmlauts(t_row[i]); - safeStringCopy(buffer, t_row[i], sizeof(buffer)); - + + if (doReplaceUmlauts) + replaceUmlauts(buffer); + if (doTruncateText) - { - truncateToColumnWidth(buffer, columnWidths[i], buffer); - } + truncateToColumnWidth(buffer, columnWidths[i], tempBuffers[i]); else - { - splitStringByLength(buffer, columnWidths[i], buffer); - } - + splitStringByLength(buffer, columnWidths[i], tempBuffers[i]); + // Zähle Zeilen in dieser Zelle int lineCount = 1; - for (size_t j = 0; j < displayLength(buffer); j++) + for (size_t j = 0; j < displayLength(tempBuffers[i]); j++) { - if (buffer[j] == '\n') + if (tempBuffers[i][j] == '\n') lineCount++; } if (lineCount > maxLines) maxLines = lineCount; } - + // Zweite Phase: Baue die Zeilen auf - for (int line = 0; line < maxLines; line++) + for (int lineNum = 0; lineNum < maxLines; lineNum++) { output += "|"; - + // Gehe durch jede Spalte for (size_t col = 0; col < size; ++col) { - if (replaceUmlauts) - { - safeStringCopy(buffer, t_row[col], sizeof(buffer)); - replaceUmlauts(buffer); - } - else - { - safeStringCopy(buffer, t_row[col], sizeof(buffer)); - } - - if (doTruncateText) - { - truncateToColumnWidth(t_row[col], columnWidths[col], buffer); - } - else - { - splitStringByLength(t_row[col], columnWidths[col], buffer); - } - // Finde die aktuelle Zeile für diese Spalte - char *currentLine = buffer; + char *currentLine = tempBuffers[col]; int currentLineNum = 0; - char tempBuffer[256] = ""; - - while (currentLineNum < line) + + // Navigiere zur gewünschten Zeile + while (currentLineNum < lineNum) { char *newline = strchr(currentLine, '\n'); if (newline == NULL) { - currentLine = ""; + // Keine weitere Zeile vorhanden, leere Zeile verwenden + static char emptyBuffer[1] = {'\0'}; + currentLine = emptyBuffer; break; } currentLine = newline + 1; currentLineNum++; } - + // Extrahiere die Zeile bis zum nächsten \n oder Ende + char lineToPrint[MAX_STRING_SIZE] = ""; int j = 0; while (currentLine[j] && currentLine[j] != '\n') { - tempBuffer[j] = currentLine[j]; + lineToPrint[j] = currentLine[j]; j++; } - tempBuffer[j] = '\0'; - + lineToPrint[j] = '\0'; + // Berechne die tatsächliche Anzeigelänge - int printedLength = displayLength(tempBuffer); - + int printedLength = displayLength(lineToPrint); + // Füge den Inhalt und die fehlenden Leerzeichen hinzu - output += tempBuffer; + output += lineToPrint; int spacesToAdd = columnWidths[col] - printedLength; for (int k = 0; k < spacesToAdd; k++) { @@ -128,7 +110,7 @@ public: } output += "\n"; } - + // Füge die Trennlinie hinzu output += buildLine(line); return output; @@ -147,11 +129,12 @@ public: public: // private: //public für UnitTests! const char **headers; const int *columnWidths; + const int MAX_STRING_SIZE = 256; size_t size; bool doTruncateText = false; bool doReplaceUmlauts = false; - static int displayLength(const char *text) + static unsigned int displayLength(const char *text) { int length = 0; for (int i = 0; text[i] != '\0'; ++i) @@ -202,8 +185,8 @@ public: // private: //public für UnitTests! if (!buffer) return; - int k = 0; // Position im Ausgabepuffer - int i = 0; // Position im Eingabetext + unsigned int k = 0; // Position im Ausgabepuffer + unsigned int i = 0; // Position im Eingabetext while (text[i] != '\0') { @@ -241,7 +224,6 @@ public: // private: //public für UnitTests! free(buffer); } - // Neue Version von splitStringByLength static void splitStringByLength(const char *input, int L, char *output) { int len = strlen(input); @@ -315,7 +297,7 @@ public: // private: //public für UnitTests! return maxLines; } - const char *getRowSegment(const char *text, int width, size_t line, char *buffer) + const char *getRowSegment(const char *text, unsigned int width, size_t line, char *buffer) { size_t textLength = strlen(text); size_t lineStart = 0; diff --git a/UnitTests.h b/UnitTests.h index 8d67725577d202525c4eefd8a92f2ce52abb0c4b..b96973b6ef9f7ecc191d1b3a7fbadf3a2a9d1b10 100644 --- a/UnitTests.h +++ b/UnitTests.h @@ -13,16 +13,16 @@ test(SplitStringNoNewlines) // Überprüfung der Länge der Strings assertEqual(strlen(expectedOutput), strlen(actualOutput)); -/* - // Zusätzliche Debug-Ausgabe, um Hex-Werte zu sehen - for (size_t i = 0; i < strlen(actualOutput); ++i) - { - Serial.print("Expected: "); - Serial.print((int)expectedOutput[i]); - Serial.print(", Actual: "); - Serial.println((int)actualOutput[i]); - } -*/ + + // // Zusätzliche Debug-Ausgabe, um Hex-Werte zu sehen + // for (size_t i = 0; i < strlen(actualOutput); ++i) + // { + // Serial.print("Expected: "); + // Serial.print((int)expectedOutput[i]); + // Serial.print(", Actual: "); + // Serial.println((int)actualOutput[i]); + // } + assertEqual(String(expectedOutput), String(actualOutput)); } @@ -113,7 +113,7 @@ test(truncateTextTest) // Fall: Text wird abgeschnitten strcpy(buffer, "HelloWorld!"); table.truncateToColumnWidth(buffer, 5, buffer); - assertEqual("He...", buffer); + assertEqual("Hel..", buffer); } test(buildHeaderTest1) @@ -210,7 +210,7 @@ test(buildRowTest) const int columnWidths[] = {10, 5, 10}; SerialTable table(headers, columnWidths, 3); - char *rows[] = {"Alice", "30", "Wonderland"}; + const char *rows[] = {"Alice", "30", "Wonderland"}; // Verwende buildRow, um den Zeilen-String zu bekommen String rowOutput = table.buildRow(rows); @@ -234,7 +234,7 @@ test(printRowWithMultipleLinesTest) const int columnWidths[] = {10, 5, 5}; SerialTable table(headers, columnWidths, 3); - char *rows[] = {"Alice", "30", "Wonderland"}; + const char *rows[] = {"Alice", "30", "Wonderland"}; // Verwende buildRow, um den Zeilen-String zu bekommen String rowOutput = table.buildRow(rows); @@ -259,7 +259,7 @@ test(printRowWithLongTextTest) const int columnWidths[] = {10, 5, 10}; SerialTable table(headers, columnWidths, 3); - char *rows[] = {"A very long name", "12345", "A very long city name"}; + const char *rows[] = {"A very long name", "12345", "A very long city name"}; // Verwende buildRow, um den Zeilen-String zu bekommen String rowOutput = table.buildRow(rows); @@ -285,7 +285,7 @@ test(printEmptyRowTest) const int columnWidths[] = {10, 5, 10}; SerialTable table(headers, columnWidths, 3); - char *rows[] = {"", "", ""}; + const char *rows[] = {"", "", ""}; // Verwende buildRow, um den Zeilen-String zu bekommen String rowOutput = table.buildRow(rows); @@ -304,39 +304,39 @@ test(printEmptyRowTest) } test(DisplayLengthBasic) { - assertEqual(5, SerialTable::displayLength("Hello")); + assertEqual((unsigned int)5, SerialTable::displayLength("Hello")); } test(DisplayLengthWithSpace) { - assertEqual(11, SerialTable::displayLength("Hello World")); + assertEqual((unsigned int)11, SerialTable::displayLength("Hello World")); } test(DisplayLengthWithUmlauts) { // "Müller" in UTF-8 hat eine Länge von 6 Zeichen (ä zählt als 1 Zeichen) - assertEqual(6, SerialTable::displayLength("Müller")); + assertEqual((unsigned int)6, SerialTable::displayLength("Müller")); } test(DisplayLengthOnlyUmlauts) { // "äöü" in UTF-8 sollten jeweils als ein Zeichen zählen - assertEqual(3, SerialTable::displayLength("äöü")); + assertEqual((unsigned int)3, SerialTable::displayLength("äöü")); } test(DisplayLengthUTF8Emojis) { // "😀😃😄" Emojis können mehrere Bytes haben, prüfen ob jedes nur als ein Zeichen gezählt wird - assertEqual(3, SerialTable::displayLength("😀😃😄")); + assertEqual((unsigned int)3, SerialTable::displayLength("😀😃😄")); } test(DisplayLengthWithNewline) { // "Hello\nWorld" hat eine Länge von 11 Zeichen, da \n als einzelnes Zeichen zählt - assertEqual(11, SerialTable::displayLength("Hello\nWorld")); + assertEqual((unsigned int)11, SerialTable::displayLength("Hello\nWorld")); } test(DisplayLengthEmptyString) { // Ein leerer String sollte eine Länge von 0 haben - assertEqual(0, SerialTable::displayLength("")); + assertEqual((unsigned int)0, SerialTable::displayLength("")); } test(DisplayLengthSpaces) { // " " hat eine Länge von 3 Leerzeichen - assertEqual(3, SerialTable::displayLength(" ")); + assertEqual((unsigned int)3, SerialTable::displayLength(" ")); } diff --git a/examples/serialTable/serialTable.ino b/examples/serialTable/serialTable.ino index 0a927d279838e3e37587f60fdcdac427e899905a..336f232661baab2be2f8045785a7332dee921f01 100644 --- a/examples/serialTable/serialTable.ino +++ b/examples/serialTable/serialTable.ino @@ -6,47 +6,46 @@ void setup() { // Initialisieren der seriellen Verbindung Serial.begin(115200); - - // Definieren der Kopfzeilen und Spaltenbreiten für 8 Spalten - const char *headers[] = {"Vorname", "Nachname", "Alter", "Stadt", "Beruf", "Unternehmen", "Hobby", "Bemerkung"}; - int columnWidths[] = {10, 15, 5, 10, 10, 15, 10, 20}; - SerialTable table(headers, columnWidths, 8, true, true); - table.printHeader(); + // Definieren der Kopfzeilen und Spaltenbreiten für 8 Spalten + const char *headers[] = {"Vorname", "Nachname", "Alter", "Stadt", "Beruf", "Unternehmen", "Hobby", "Bemerkung"}; + int columnWidths[] = {10, 15, 5, 10, 10, 15, 10, 20}; - // Erstellen von 20 Zeilen mit unterschiedlichen Einträgen - char *rows[20][8] = { - {"Alice", "Wonderland", "30", "Köln", "Ingenieur", "FirmaX", "Schwimmen", "Keine"}, - {"Bob", "Builder\nJr", "35", "Berlin", "Architekt", "Architektur AG", "Bauen", "Sehr erfahren"}, - {"Charlie", "Brown", "28", "Hamburg", "Designer", "Die Design", "Zeichnen", "Mag Karikaturen"}, - {"David", "Tennant", "40", "München", "Schauspieler", "Freiberufler", "Lesen", "Doktor gewesen"}, - {"Emma", "Watson", "33", "Frankfurt", "Schauspielerin", "Independent", "Yoga", "Bekannt aus Filmen"}, - {"Frank", "Herbert", "45", "Stuttgart", "Autor", "Ein Verlag", "Schreiben", "Bücher geschrieben"}, - {"Grace", "Hopper", "50", "Berlin", "Programmiererin", "Tech Corp", "Informatik", "Pionierin"}, - {"Hugo", "Strange", "60", "Leipzig", "Psychiater", "Gesundheits GmbH", "Philosophie", "Ruhestand"}, - {"Irene", "Adler", "29", "Dresden", "Detektivin", "Privat", "Abenteuer", "Scharfsinnig"}, - {"John", "Doe", "49", "Bremen", "Buchhalter", "Kontorechner", "Radfahren", "Gewissenhaft"}, - {"Klara", "Kühn", "39", "Hannover", "Lehrerin", "Schule ABC", "Lesen", "Einfühlsam"}, - {"Lenny", "Small", "25", "Koblenz", "Musiker", "Orchester", "Gitarre", "Kreativ"}, - {"Mona", "Lisa", "33", "Siegen", "Malerin", "Kunsthaus", "Kunst", "Geheimnisvoll"}, - {"Nina", "Simone", "30", "Essen", "Sängerin", "Soul Musik", "Musik", "Talentiert"}, - {"Oliver", "Twist", "19", "Potsdam", "Student", "Uni XY", "Fußball", "Engagiert"}, - {"Pam", "Beesly", "32", "Wuppertal", "Sekretärin", "Dunder Mifflin", "Malen", "Freundlich"}, - {"Quinn", "Fabray", "26", "Magdeburg", "Designer", "Agentur XYZ", "Tanzen", "Kreativ"}, - {"Ron", "Swanson", "55", "Bielefeld", "Verwalter", "Rathaus", "Holzarbeiten", "Direkt"}, - {"Sophia", "Loren", "70", "Osnabrück", "Schauspielerin", "Independent", "Kochen", "Ikonisch"}, - {"Tom", "Hanson", "36", "Regensburg", "Polizist", "Polizei", "Jagen", "Schützend"}, - }; + SerialTable table(headers, columnWidths, 8, true, true); + table.printHeader(); - // Drucke die Zeilen - for (int i = 0; i < 20; ++i) - { - table.printRow(rows[i]); - } - + // Erstellen von 20 Zeilen mit unterschiedlichen Einträgen + char *rows[20][8] = { + {"Alice", "Wonderland", "30", "Köln", "Ingenieur", "FirmaX", "Schwimmen", "Keine"}, + {"Bob", "Builder\nJr", "35", "Berlin", "Architekt", "Architektur AG", "Bauen", "Sehr erfahren"}, + {"Charlie", "Brown", "28", "Hamburg", "Designer", "Die Design", "Zeichnen", "Mag Karikaturen"}, + {"David", "Tennant", "40", "München", "Schauspieler", "Freiberufler", "Lesen", "Doktor gewesen"}, + {"Emma", "Watson", "33", "Frankfurt", "Schauspielerin", "Independent", "Yoga", "Bekannt aus Filmen"}, + {"Frank", "Herbert", "45", "Stuttgart", "Autor", "Ein Verlag", "Schreiben", "Bücher geschrieben"}, + {"Grace", "Hopper", "50", "Berlin", "Programmiererin", "Tech Corp", "Informatik", "Pionierin"}, + {"Hugo", "Strange", "60", "Leipzig", "Psychiater", "Gesundheits GmbH", "Philosophie", "Ruhestand"}, + {"Irene", "Adler", "29", "Dresden", "Detektivin", "Privat", "Abenteuer", "Scharfsinnig"}, + {"John", "Doe", "49", "Bremen", "Buchhalter", "Kontorechner", "Radfahren", "Gewissenhaft"}, + {"Klara", "Kühn", "39", "Hannover", "Lehrerin", "Schule ABC", "Lesen", "Einfühlsam"}, + {"Lenny", "Small", "25", "Koblenz", "Musiker", "Orchester", "Gitarre", "Kreativ"}, + {"Mona", "Lisa", "33", "Siegen", "Malerin", "Kunsthaus", "Kunst", "Geheimnisvoll"}, + {"Nina", "Simone", "30", "Essen", "Sängerin", "Soul Musik", "Musik", "Talentiert"}, + {"Oliver", "Twist", "19", "Potsdam", "Student", "Uni XY", "Fußball", "Engagiert"}, + {"Pam", "Beesly", "32", "Wuppertal", "Sekretärin", "Dunder Mifflin", "Malen", "Freundlich"}, + {"Quinn", "Fabray", "26", "Magdeburg", "Designer", "Agentur XYZ", "Tanzen", "Kreativ"}, + {"Ron", "Swanson", "55", "Bielefeld", "Verwalter", "Rathaus", "Holzarbeiten", "Direkt"}, + {"Sophia", "Loren", "70", "Osnabrück", "Schauspielerin", "Independent", "Kochen", "Ikonisch"}, + {"Tom", "Hanson", "36", "Regensburg", "Polizist", "Polizei", "Jagen", "Schützend"}, + }; + + // Drucke die Zeilen + for (int i = 0; i < 20; ++i) + { + table.printRow(rows[i]); + } } void loop() { - //TestRunner::run(); + // TestRunner::run(); } \ No newline at end of file