• Hallo liebe Userinnen und User,

    nach bereits längeren Planungen und Vorbereitungen sind wir nun von vBulletin auf Xenforo umgestiegen. Die Umstellung musste leider aufgrund der Serverprobleme der letzten Tage notgedrungen vorverlegt werden. Das neue Forum ist soweit voll funktionsfähig, allerdings sind noch nicht alle der gewohnten Funktionen vorhanden. Nach Möglichkeit werden wir sie in den nächsten Wochen nachrüsten. Dafür sollte es nun einige der Probleme lösen, die wir in den letzten Tagen, Wochen und Monaten hatten. Auch der Server ist nun potenter als bei unserem alten Hoster, wodurch wir nun langfristig den Tank mit Bytes vollgetankt haben.

    Anfangs mag die neue Boardsoftware etwas ungewohnt sein, aber man findet sich recht schnell ein. Wir wissen, dass ihr alle Gewohnheitstiere seid, aber gebt dem neuen Board eine Chance.
    Sollte etwas der neuen oder auch gewohnten Funktionen unklar sein, könnt ihr den "Wo issn da der Button zu"-Thread im Feedback nutzen. Bugs meldet ihr bitte im Bugtracker, es wird sicher welche geben die uns noch nicht aufgefallen sind. Ich werde das dann versuchen, halbwegs im Startbeitrag übersichtlich zu halten, was an Arbeit noch aussteht.

    Neu ist, dass die Boardsoftware deutlich besser für Mobiltelefone und diverse Endgeräte geeignet ist und nun auch im mobilen Style alle Funktionen verfügbar sind. Am Desktop findet ihr oben rechts sowohl den Umschalter zwischen hellem und dunklem Style. Am Handy ist der Hell-/Dunkelschalter am Ende der Seite. Damit sollte zukünftig jeder sein Board so konfigurieren können, wie es ihm am liebsten ist.


    Die restlichen Funktionen sollten eigentlich soweit wie gewohnt funktionieren. Einfach mal ein wenig damit spielen oder bei Unklarheiten im Thread nachfragen. Viel Spaß im ngb 2.0.

IT-Talents.de Code Competitions

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.677
  • Thread Starter Thread Starter
  • #61
Gar nicht, aber was hat das mit einer Lizenz zu tun die es dir erlaubt den Code kommerziell zu nutzen, aber Änderungen an den Urheber zu bringen (müssen) bzw. das "Copyright" in Ordnung zu lassen? - Ich verstehe dich gerade nicht.
 

drfuture

Zeitreisender
Teammitglied

Registriert
14 Juli 2013
Beiträge
8.798
Ort
in der Zukunft
Ich finde auch das es total egal ist ob 0 Personen 5 oder 1000 etwas kopieren, benutzen oder nur lesen - wenn ich etwas veröffentliche gebe ich meine Spielregeln > Lizenzbedingungen dazu bekannt.
Wenn es keiner nutzt oder liest schadet das den Bedingungen nicht und sonst auch keinem.
Für den Fall das es jemand nutzen möchte - komplett egal wie warscheinlich das ist - dann wäre ich als Programmierer schliecht froh zu wissen ob ich das benutzen darf.
Im Kommerziellen Umfeld ist es mir nicht nur einmal so gegangen das ich einen coolen *kniff* irgendwo gesehen habe - ihn aber nicht mit ruhigem gewissen nutzen konnte da nicht klar war ob der Code verwendet werden darf - und die Gefahr möchte ich dann nicht eingehen.

Und könntet ihr nun so langsam schlicht wieder zum Thema zurück kommen?
 

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.677
  • Thread Starter Thread Starter
  • #63
Ich will auch nicht in die gleiche Kerbe hauen und danke auch für die Unterstützung @ drfutrue...

Vielleicht kann man aber daraus auch ein Thema machen hier im Forum, "Lizenzen im Open Source Bereich", weil es nicht eindeutig klar ist um was es manchen Menschen geht dabei... glaube ich.
Und auch das es nicht um Patente geht.

Vielleicht lerne ich dann auch noch was dabei... :cool:
 
Zuletzt bearbeitet:

Larius

OutOfOrder

Registriert
12 Juli 2013
Beiträge
5.792
Ich verstehe auch beide Seiten. Einerseits ist das NGB so klein und "unbekannt", das niemand hier wohl n Teil von einem Sourcecode klaut und irgendwo da draußen in der Welt weiterverwendet. Aber wenn Split ihn unter eine Lizenz stellen will bevor ers veröffentlicht dann ist das einfach sein gutes Recht.

Jetzt habt euch wieder lieb, sonst dürft ihr bei mir Dokumente scannen!

Und ja, Thread bzgl. Lizenzsierungsdiskussion könnt ihr gerne machen.
 

Brother John

(schein)heilig
Veteran

Registriert
1 Aug. 2013
Beiträge
235
Lizenzen hin oder her, schon zum Vergleichen wäre es sehr interessant, von allen den Quellcode zumindest zum Lesen zur Verfügung zu haben. Hey, eine Aufgabe und drei grundverschiedene Ansätze. Besser kanns doch nicht laufen.

Ich bin ganz schön abgebogen. Irgendwann ist mir nämlich aufgegangen, dass die ganze Übung nie über ein Spielbeispiel rauskommen kann, wenn der Parser nicht fähig ist, sauber und zuverlässig die rekursive Blockstruktur eines Markdowndokuments zu verarbeiten. Damit sind wir mitten in tiefstem »context-sensitive/stateful land«, weil z.B. für jedes Blockquote-Level ein > am Zeilenanfang dazukommt.

Spirit X3 ist ne sehr feine Library, aber richtig! mies! dokumentiert – v.a. weil viel Doku einfach fehlt. Gerade für solche fortgeschrittenen Sachen wie State über mehrere Parser-Instanzen durchzuschleusen, gibt’s außer dem Quellcode nur diverse Stackoverflow- und Mailinglisten-Postings. Jetzt hab ich also drölfzig halbfunktionale Schnipsel vom hin- und hertesten rumliegen … also so ungefähr :)

Für die Competition krieg ich das nicht mehr zu einem sinnvollen Paket geschnürt. Macht aber nix, die war eh v.a. die Ausrede, um überhaupt die Motivation zum Parsern aufzubringen.

@theSplit @MurmeltierS
Euch drück ich die Daumen für 1. und 2. Platz. :D
 

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.677
  • Thread Starter Thread Starter
  • #68
@Brother John: Klingt als hattest du deinen Spaß damit :p

Ich weiß nicht ob ichs mit meinem "einfachen" einmal über die Daten fliegen und bissle hin und her springen in der Datei, wirklich gebracht habe. Aber zumindest ist schon etwas funktionierendes dabei herausgekommen. Aber wäre ja schon ganz nett wenn gutes Feedback dazu kommt, vielleicht kann man die Idee dann mal fortführen. ;)

Allerdings gebe ich auch zu, ich hätte, würde ich mich an das was hier bezüglich Commonmark diskutiert wird, daran gehalten haben, das Programm wäre noch viel komplexer/umfangreicher geworden/aufgebaut werden müssen. So habe ich mir zum Teil manche Regeln "für mich" angepasst, bzw. was mir logisch erschien zu dem Moment.

Und das ganze hat halt viele "if"-Klauseln für irgendwelche Sonderfälle und Schleifen über die bestehenden Tags, um zu identifizieren, wie man jetzt reagieren sollen müsste, ob Elemente noch offen sind und ähnliches. :)

Ich denke aber, es wäre leicht mit der Bauweise auch verschachtelte Elemente aufzudecken und abzuarbeiten, weil man sich eigentlich immer nur auf die ein oder anderen nächsten Zeilen und am Whitespace orientiert. Hat man zumindest die Erkenntnis in welcher Tiefe man sich befindet und ob Elemente noch "offen" sind, so eine Struktur erfasse ich ja, kann man theoretisch darauf Rückschlüsse ziehen wo man sich befindet.

Der Prozess an sich ist aber sehr geradlinig bzw. sequentiell, finde ich. - Aber das könnte auch damit zusammenhängen, wenn man komplexe Situationen nicht richtig oder überhaupt nicht bedacht hat. Und wie Kreativ man als "Anwender" ist, sieht man ja häufig. Aber wie gesagt, dafür braucht es dann eine Spezifikation an der man sich zumindest die "gängigen" Situation herausziehen kann. Commonmark hat ja nun wirklich viele viele Punkte... aber ne C Source dazu konnte ich auch nicht finden :p - Obwohl das dransteht auf Github :D

Ich glaube auch, ein Problem von Commonmark ist, das ließt sich alles "sehr einfach" - aber kein Mensch hat je probiert diese ganzen Fälle in Code zu beschreiben. Manchmal muß man einen "*" mal so behandeln, mal so, dann darf man aber die Leerzeile weglassen oder es handelt sich um Paragraphen Inhalt - alles ein wenig "widersprüchlich" fand ich.

Lange Rede kurzer Sinn, das mit dem Framework bzw. der Library kann ich sogar nachvollziehen. Wenn etwas nicht klar dokumentiert ist oder zu viele Fragen offen bleiben, wie soll man lernen es effektiv zu nutzen - gerade als "Außenstehender"?
Ging mir bei ffmpeg so.. und das ist dokumentiert, aber kein Mensch sagt dir direkt du mußt das "so" oder "so" "zusammenbauen" damit das alles funktioniert oder irgendwelche Eigenheiten von den De- und Encodern oder Filtern funktioniert. Und die Beispiele waren leider auch sehr alt bzw, komplett outdated. Also ziemlich schwierig damit zu arbeiten.

Naja, obs für nen Gewinn reicht, mal sehen... :D
Meinen Code veröffentliche ich definitiv, aber es sind ja noch ein paar Stunden, also wenn dann morgen früh um 0800 oder so ;)
---

Aber eine Frage hätte ich noch, würdest du die Aufgabe nochmal angehen, jetzt wo du auch die Probleme besser einsehen kannst, im Nachhinein, wenn du ohne die Library programmieren würdest?
 

Brother John

(schein)heilig
Veteran

Registriert
1 Aug. 2013
Beiträge
235
Definitiv Spaß. Wenn ich’s jetzt noch so zusammengesetzt kriege, dass auch was Funktionierendes dabei rauskommt … Drückt mir die Daumen, dass es möglichst gleich compiliert. Die seitenweisen Compilerfehlermeldungen tief aus irgendwelchen Boost-Templates bin ich doch ein bisschen leid.

Aber wenn’s mal geht, dann geht’s! Ich hab in meinem ersten Programmiererjob einen CSV-Parser schreiben müssen. Ohne Ahnung, ohne Erfahrung und ohne Framework (wir hatten halt nix, außer Delphi … und das zählt kaum ;)). Das war ein Mehrwochenprojekt und dann nochmal 1-2 Monate Testeinsatz beim Kunden, bis die Bugs draußen waren. Als Spirit-Grammatik dürften es wenige Zeilen sein.

Ich weiß nicht ob ichs mit meinem "einfachen" einmal über die Daten fliegen und bissle hin und her springen in der Datei, wirklich gebracht habe.
So wie ichs verstehe, ist das gar kein so doofer Ansatz. Hält den Parser klein und übersichtlich. Wenn man Verschachtelungen vorerst ignoriert, ist Markdown gar nicht so kompliziert. Wenn du eine Ebene davon parsen kannst, bräuchtest du deinen kompletten Parser »nur« rekursiv anwenden. Aus rekursiver Sichtweise ist die Blockstruktur von Markdown nämlich reichlich simpel. Es gibt zwei grundverschiedene Blocktypen, langweilige und interessante ;):

  • Absätze, Überschriften, Codeblöcke: Langweilig, weil sie nicht geschachtelt werden können.
  • Listenpunkte und Blockquotes: Hier wirds interessant, weil *die* sind rekursiv. Und zwar nicht irgendwie beliebig, sondern: jeder Listenpunkt/Blockquote enthält schlicht und einfach ein vollständiges Markdown-Dokument.
Wenn dein Parser mit flexiblen Ebenenmarkern (unterschiedliche viel Leading Whitespace und unterschiedlich viele > bei den Quotes) umgehen kann, braucht er sich pro Listenpunkt/Blockquote »nur« rekursiv selbst aufrufen: Problem gelöst. … Ja, ok. Bisschen State-Handling, paar Grenzfälle. Ach, komm. Maximal ein Nachmittag, oder!? :D

Apropos deine Frage ganz am Ende: Ohne Framework würde ichs konzeptionell so rekursiv angehen. Wahrscheinlich nach ein bisschen Rumlesen in Sachen Parserbau. Ich weiß z.B. dass man mit Spirit »Recursive Descent Parser« baut. Ich hab ein sinnvolles Gefühl dafür, was dahinter steckt, nämlich vermutlich etwas in die Richtung wie oben beschrieben; aber was *genau* das bedeutet? Welche Typen Parser es sonst noch so gibt? Wie andere Leute solche Parser implementieren? Klingt nach einem Gebiet, das Laune macht.

aber ne C Source dazu konnte ich auch nicht finden - Obwohl das dransteht auf Github [...] Ich glaube auch, ein Problem von Commonmark ist, das ließt sich alles "sehr einfach" - aber kein Mensch hat je probiert diese ganzen Fälle in Code zu beschreiben.
Das ist auf commonmark.org ein bisschen doof verlinkt: Liste von CommonMark-Parsern, der erste Eintrag ist die Referenzimplementierung in C. Zumindest die ist auch vollständig, also man kann (und hat) die Spec schon in Code umgesetzt. Heist natürlich nicht, dass die Spec vollständig, fehler- und widerspruchsfrei ist. Das würde mich wundern.
 

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.677
  • Thread Starter Thread Starter
  • #70
Naja, wenn mal Whitespace als "Tiefe" betrachtet und das als Attribut für einen Tag speichert, hat man schon die Tiefe nachvollziehbar mit drin.

Wie und ob sich Tags verschachteln lassen, also Markdown in Markdown, steht auf einem anderen Blatt. Und das sind aber Sonderfälle bzw. hat man ja eine gewisse "Logik" schon vordefiniert würde vieles. Sind aber wie gesagt eben, Sonderfälle für einen Tag.

Aber dafür, meine ich, braucht man nicht rekursiv zu sein. Es muss lediglich eine Überprüfung stattfinden, in welchem Level man sich aktuell befindet, in was für ein Typ von Element und ob dieses nicht nach anderen Regeln geschlossen werden muß oder weitergeführt wird.

Wir arbeiten dann aber immer noch sequentiell alles ab, heißt Zeile für Zeile, nur merken wir uns, welchen Stand (Whitespaces/Tabs) die vorherigen Zeilen haben und ob wir ein Element schließen müssen oder nicht.

Aber ob es auf nen Nachmittag hinausläuft? :p
Man muß halt schauen das man mit einer "neu eingeführten" Regel, keine anderen umgeht oder bricht. Das war immer mein Problem an meinem Code.

Aber ich finds lustig wenn du das so beschreibst - ich kann mit den "Fachvokabular" ja eher weniger anfangen, einfach weil ich das nicht gelernt habe... und die Wege irgendwie gehe, weil ich das Problem sehe bzw. meine "Denke" hab.

Aber ich denke auch, du solltest das mal in Angriff nehmen, dann wird dir auch mehr oder minder bewusst, das die Spezifikation, wie du selbst sagst, noch Implementierungsprobleme hat oder "ausnahmen" die alle einprogrammiert werden müssen.

Aber kann auch gut sein das ich da, wie soll ich sagen, unkonventioneller herangehe als du es selbst vielleicht gewönt bist - das man alles in Funktionen schachteln muß die kleine Aufgaben erledigen.

Ich betrachte es alles als Sequenz und ein paar Loops die Tags schließen, sobald wir aus dem Muster der Tags ausbrechen, eine Schleife. :)

Deswegen, ich fand es jetzt nicht so kompliziert, aber man muß halt auf viele Details achten und nicht vorne "aufzubauen" und hinten dann umzuschmeißen :D
 

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.677
  • Thread Starter Thread Starter
  • #72
Hi, also, was bei mir nicht wirklich funktioniert, die Live-Formatierung von Überschriften mittels "#".

Fett und Kursiv funktionieren, aber die Überschriften hauen nicht hin.
Da mußt du wohl nochmal ran ;)

Listen funktionieren aber auch in der Live Vorschau, sogar geschachtelt.

Aber schön zu sehen wieviel Mühe du dir gemacht hast, finde ich sehr gut "aufbereitet"... auch für mögliche User deines Codes. :)
 

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.677
  • Thread Starter Thread Starter
  • #74
Ich nutze Firefox für Linux... auch in der aktuellen Version.
 

MurmeltierS

Neu angemeldet

Registriert
9 Apr. 2017
Beiträge
21
Intressant, den Fehler konnte ich leider nicht reproduzieren, an das " " nach der # hast du gedacht?
 

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.677
  • Thread Starter Thread Starter
  • #76
Hehe, genau - das ist mir nämlich auch gerade eingefallen! :T

Wenn man ein Leerzeichen nach der Raute lässt, also "# " schreibt, dann klappt das auch.... :)

Ist aber auch nicht so genormt glaube ich, die müssen ja nur am Zeilenanfang stehen, laut Aufgabe.., muss nochmal schauen. ;)
 

MurmeltierS

Neu angemeldet

Registriert
9 Apr. 2017
Beiträge
21
Eine h1-Überschrift wird durch eine Raute (gefolgt von einem Leerzeichen) eingeleitet

Steht so in der Aufgabenbeschreibung bei IT-Talents :D

Ist aber, wenn man an anderer Stelle schaut völlig egal, markdown ist eben nie wirklich "genormt" worden.
 

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.677
  • Thread Starter Thread Starter
  • #78
Ich glaube dann kann ich ja noch schnell meinen Code hochladen...

Done.

Zu finden unter: https://github.com/jrie/mdownhtml

oder direkt hier: https://github.com/jrie/mdownhtml/blob/master/mdownhtml.c

Oder so, die Lizenz ist nach wie vor gültig... :)

[src=c]//------------------------------------------------------------------------------
// NOTICE
//------------------------------------------------------------------------------
//
// "Markdown to HTML converter" short "mdownhtml"
//
// Converts markdown to HTML, partly mixing some commonmark with
// John Grubers definition of markdown.
//
// Uses/converts the ATX-Syntax for markdown headings!
// Initially written for the www.it-talents.de coding competition
//
// Version date: 29.04.2017
//
// Author: Jan R.
// Contact: <jan AT dwrox DOT net>
//
//------------------------------------------------------------------------------


// CODE START
//------------------------------------------------------------------------------
// Includes
//------------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <ctype.h>


//------------------------------------------------------------------------------
// Definitions
//------------------------------------------------------------------------------
#define PARAGRAPH_LISTS // Define if we should create "<li>" elements with paragraphed content, equals "<li><p></p></li>"
#undef PARAGRAPH_LISTS // Comment me out to create <li><p>CONTENT</p></li> elements

//------------------------------------------------------------------------------
// Structs
//------------------------------------------------------------------------------
typedef struct html_tag {
bool isClosed; // Is the markdown tag already closed with html?
bool isSibling; // TODO: Add comment
bool isListEnd;
unsigned int tagType; // Which mardkown/html tag are we dealing with?
short formatDepth;
} html_tag;

typedef struct html_collection {
long count; // The amount of tags
struct html_tag* tags; // The tag list
} html_collection;

//------------------------------------------------------------------------------
// Functions
//------------------------------------------------------------------------------
// None present... its just one big main, splitted in 3 to 4 logical blocks

//------------------------------------------------------------------------------
// Code
//------------------------------------------------------------------------------

int main(int argc, char *argv[]) {

char* inputName = NULL; // "input_markdown.md";
char* outputName = NULL; //"output_html.html";

bool hasInput = false;
bool hasOutput = false;

printf("Mdownhtml - v29.04.2017 -\nAuthor and contact: <jan@dwrox.net>\n\n");

for (int i = 1; i < argc; ++i) {
if (argv[0] == '-') {
if (strlen(argv) > 1) {
if (tolower(argv[1]) == 'i') {
inputName = malloc(strlen(argv) * sizeof(char));
strcpy(inputName, &argv[2]);
hasInput = true;
} else if (tolower(argv[1]) == 'o') {
outputName = malloc(strlen(argv) * sizeof(char));
strcpy(outputName, &argv[2]);
hasOutput = true;
} else if (tolower(argv[1]) == 'h') {
printf("Usage:\n-i\tInput file name, use '-iMyInputFilename'\n-o\tOutput file name, use '-oMyOutputFilename'\n-h\tPrint this help\n\nBy default if nothing is provided the input file 'input_markdown.md' is used.\nAs output, the default file is called 'output_html.html'\n\n");

free(inputName);
free(outputName);
return EXIT_SUCCESS;
}
} else {
printf("Usage:\n-i\tInput file name, use '-iMyInputFilename'\n-o\tOutput file name, use '-oMyOutputFilename'\n-h\tPrint this help\n\nBy default if nothing is provided the input file 'input_markdown.md' is used.\nAs output, the default file is called 'output_html.html'\n\n");
return EXIT_SUCCESS;
}
}
}

if (!hasInput) {
inputName = malloc(19);
strcpy(inputName, "input_markdown.md");
}

if (!hasOutput) {
outputName = malloc(17);
strcpy(outputName, "output_html.html");
}

// Open the input and out file and deal with errors
FILE* inputFile = fopen(inputName, "rb");

if (inputFile == NULL) {
fprintf(stderr, "Cannot open input markdown file '%s' for reading.\nWithout parameters this defaults to 'input_markdown.md'.\n\nUse mdownhtml -h to show a list of commands.\n", inputName);
free(inputName);
free(outputName);
return EXIT_FAILURE;
}

FILE* outputFile = fopen(outputName, "wb");

if (outputFile == NULL) {
fclose(inputFile);

free(inputName);
free(outputName);

fprintf(stderr, "Cannot open output html file '%s' for writing.\nWithout parameters this defaults to 'output_html.html'.\n\nUse mdownhtml -h to show a list of commands.\n", outputName);
return EXIT_FAILURE;
}

//----------------------------------------------------------------------------
// Tag definitions and "htmlCollection" as data holder for the open markdown tags

#ifdef PARAGRAPH_LISTS
char tagOpenings[12][24] = {
"<h1>", "<h2>", "<h3>", "<h4>", "<h5>", "<h6>", "<li><p>", "<strong>", "<em>", "<p>", "<blockquote>", "<strong><em>"
};

char tagClosings[12][27] = {
"</h1>", "</h2>", "</h3>", "</h4>", "</h5>", "</h6>", "</p></li>", "</strong>", "</em>", "</p>", "</blockquote>", "</em></strong>"
};

#else

char tagOpenings[12][24] = {
"<h1>", "<h2>", "<h3>", "<h4>", "<h5>", "<h6>", "<li>", "<strong>", "<em>", "<p>", "<blockquote>", "<strong><em>"
};

char tagClosings[12][27] = {
"</h1>", "</h2>", "</h3>", "</h4>", "</h5>", "</h6>", "</li>", "</strong>", "</em>", "</p>", "</blockquote>", "</em></strong>"
};

#endif

struct html_collection htmlCollection = { 0, NULL }; // Our data collection for all present markdown/html tags


//----------------------------------------------------------------------------

char inputChar = '\0'; // The currently processed character of the input file
char nextChar = '\0'; // In case we deal with a follow up character for the formatting
char oldChar = '\0'; // Temporary store nextChar to check the following character, in some case
bool lineStart = true; // Are we at the beginning of a new line?
bool lineEnd = false; // Are we at the end?
bool tagIsClosed = false; // Is the tag closed already?
int tagType = -1; // Which markdown/html tag are we dealing with
int headerDepth = 0; // How deep is a header markdown?
int formatDepth = 0; // How deep is the formatting level of asterisk/star characters?
int depthDiff = 0;
bool hasOpenParagraph = false;
bool hasOpenQuote = false;
bool hasOpenList = false;
long orgPos = 0;

printf("Start converting '%s' and saving to '%s'...\n", inputName, outputName);

// Main loop for readout and creation
while (true) {
inputChar = fgetc(inputFile);
nextChar = '\0';
tagType = -1;
headerDepth = 0;
formatDepth = 0;
depthDiff = 0;
hasOpenParagraph = false;
hasOpenQuote = false;
hasOpenList = false;

switch (inputChar) {
case '#':
if (lineStart) {
// Create a header object if we are at linestart and gather the depth
headerDepth = 1;

while ((nextChar = fgetc(inputFile)) == '#') {
++headerDepth;
}

if (nextChar != ' ') {
fseek(inputFile, -1, SEEK_CUR);
}
tagType = headerDepth - 1;

// Previous method
/*if (fgetc(inputFile) == '#') {
tagType = 1;
} else {
tagType = 0;
fseek(inputFile, -1, SEEK_CUR);
}*/
} else {
tagType = 9;
}

break;
case '*':
// Create a text format or list item, either italic or bold or bold italic based on start
if (lineStart) {
// We are at linestart... could be a list item or a format or an empty list item

nextChar = fgetc(inputFile);

if (nextChar == ' ' || nextChar == '\t' || nextChar == '\n' || nextChar == '\r') {
tagType = 6;
formatDepth = 0;

if (nextChar == '\n' || nextChar == '\r') {
hasOpenList = false;

if (htmlCollection.count != 0 && htmlCollection.tags[htmlCollection.count - 1].tagType == 6 && !htmlCollection.tags[htmlCollection.count - 1].isClosed) {
orgPos = ftell(inputFile);
while (true) {
nextChar = fgetc(inputFile);
if (nextChar != '\n' || nextChar != '\r') {
break;
}
}

if (nextChar == '*') {
hasOpenList = true;
fseek(inputFile, -1, SEEK_CUR);
} else {
fseek(inputFile, orgPos, SEEK_SET);
}
}

if (!hasOpenList) {
if (htmlCollection.count != 0 && htmlCollection.tags[htmlCollection.count - 1].tagType == 9 && !htmlCollection.tags[htmlCollection.count - 1].isClosed) {
if (fgetc(inputFile) != '*') {
tagType = -1;
}

fseek(inputFile, -1, SEEK_CUR);
}
}
}

if (nextChar != ' ') {
fseek(inputFile, -1, SEEK_CUR);
}
} else {
// Else we have format
fseek(inputFile, -1, SEEK_CUR);
formatDepth = 1;
}
} else {
// If we are not at the start, its italic first
formatDepth = 1;
tagType = 8;
}

if (formatDepth != 0) {
while (fgetc(inputFile) == '*') {
++formatDepth;
}

switch (formatDepth) {
case 1:
// its italic
tagType = 8;
break;
case 2:
// if another star follows, its bold
tagType = 7;
break;
case 3:
// if another star follows, its bolditalic
tagType = 11;
break;
default:
break;
}

fseek(inputFile, -1, SEEK_CUR);
}

break;
case '>':
if (lineStart) {
// At the line start, we deal with quote markdown
tagType = 10;

for (long i = htmlCollection.count - 1; i > -1; --i) {
// Check if we already have an not closed quote, so we dont create a new tag
if (!htmlCollection.tags.isClosed && htmlCollection.tags.tagType == 10 && !htmlCollection.tags.isListEnd) {
tagType = -1;
break;
}
}

nextChar = fgetc(inputFile);

if (nextChar != ' ') {
fseek(inputFile, -1, SEEK_CUR);
} else {
if (tagType == -1) {
// If we dont create a new tag, ignore the line start and markdown character
lineStart = false;
continue;
} else {
fputc('#', inputFile);
}
}
}
break;
case ' ':

// Check if we are at line end with two spaces or more spaces and insert a br if the line ends
if (lineStart) {
tagType = 9;
} else {
orgPos = ftell(inputFile);

formatDepth = 1;

while ((nextChar = fgetc(inputFile)) == ' ') {
++formatDepth;
continue;
}

if (formatDepth == 2 && (nextChar == '\n' || nextChar == '\r')) {
fputs("<br/>", outputFile);
lineStart = true;
lineEnd = false;
continue;
} else {
fseek(inputFile, orgPos, SEEK_SET);
fputc(' ', outputFile);
continue;
}
}
break;
case '\n':
case '\r':
case EOF:
// Set that the current line is ended
lineEnd = true;
break;
default:
if (lineStart || (htmlCollection.count != 0 && htmlCollection.tags[htmlCollection.count - 1].tagType == 10 && !htmlCollection.tags[htmlCollection.count - 1].isClosed)) {
// If we are at a start of a new line, we assume that we should use a paragraph for every text item
// in case the last open tag is a quote, we could wrap it into a p - tag too
tagType = 9;

if (htmlCollection.count != 0) {
// If we have possible open tags, check if we really need to add a paragraph
// in case there is a open blockquote, we create a paragraph, in case of a open paragraph we dont create a new one
hasOpenParagraph = false;
hasOpenQuote = false;

for (long i = htmlCollection.count - 1; i > -1; --i) {
if (htmlCollection.tags.tagType == 9 && !htmlCollection.tags.isClosed) {
hasOpenParagraph = true;
break;
} else if (htmlCollection.tags.tagType == 10 && !htmlCollection.tags.isClosed) {
hasOpenQuote = true;
break;
}
}

if (hasOpenParagraph && !hasOpenQuote) {
tagType = -1;
}
}
}
break;
}


//--------------------------------------------------------------------------

tagIsClosed = false; // Is the tag closed

// If we are at line end, or we have a follow up text format or an open tag, try to close it...
if ((lineEnd || tagType != -1) && htmlCollection.count != 0) {
nextChar = fgetc(inputFile); // Which character follows? - This becomes also dynamically changed on demand
oldChar = nextChar; // Backup the current selection
char pChar = '\0';
bool isParserAtEnd = false; // Are we at the end of the file? This is needed to finalize with the last read in data and break out of execution

if (nextChar == EOF) {
nextChar = '\n'; // Overwrite the EOF, so the switch case statement can deal with it
isParserAtEnd = true;
}

if (nextChar == '*') {
// This is most likely a text format or a list following, particular at the linEend
nextChar = fgetc(inputFile);
if (nextChar == ' ' || nextChar == '\n' || nextChar == '\r' || (nextChar == '*' && oldChar == ' ')) {
// Its a list item
nextChar = '*';
} else {
// Its most likely the end of a list item...
hasOpenList = false; // Do we have a list which needs to be closed now?
for (long i = htmlCollection.count - 1; i > -1; --i) {
if (htmlCollection.tags.tagType == 6 && !htmlCollection.tags.isClosed) {
hasOpenList = true; // Yes
nextChar = 0; // Set nextChar to zero, to add special case handling
break;
}
}

if (!hasOpenList) {
nextChar = oldChar; // We dont have an open list, get back to the old picked character threatment
}
}

if (nextChar != ' ') {
fseek(inputFile, -1, SEEK_CUR); // Rewind by one
}
} else {
// This is not a list, so we check if we are at the end of a paragraph item which is not yet closed
if (lineEnd) {
for (long i = htmlCollection.count - 1; i > -1; --i) {
if (htmlCollection.tags.tagType == 6 && !htmlCollection.tags.isClosed) {
nextChar = 0; // Set a special rule to handle a paragraph correctly
break;
}
}
}
}

for (long i = htmlCollection.count-1; i > -1; --i) {
if (!htmlCollection.tags.isClosed) {
// Check all open markdown/html tags

if (htmlCollection.tags.tagType == 6) {
// If we have a open list element
switch (nextChar) {
case '*':
// Has a follow list element, close only the li element
fputs(tagClosings[6], outputFile); // Add closing </li> element
htmlCollection.tags.isClosed = true; // Close the tag
htmlCollection.tags.isListEnd = false;
break;
case '\n':
case '\r':
case 0:
// Has no following list element, close the li and ul elements
#ifdef PARAGRAPH_LISTS
fputs("</p></li></ul>", outputFile); // Add special ending not in closing list (with paragraph)
#else
fputs("</li></ul>", outputFile); // Add special ending not in closing list
#endif
htmlCollection.tags.isClosed = true; // Close...
htmlCollection.tags.isListEnd = true;
break;
default:
break;
}

} else if (htmlCollection.tags.tagType == 9) {
// If we have a paragraph
switch (nextChar) {
case '>':
pChar = fgetc(inputFile);
if (pChar == '\n' || pChar == '\r') {
fputs(tagClosings[9], outputFile);
htmlCollection.tags.isClosed = true;
}
fseek(inputFile, -1, SEEK_CUR);
break;
case '\n':
case '\r':
// Close the paragraph, we have a empty line in between which might introduce a new paragraph
// Add closing p tag
if (inputChar != '*') {
fputs(tagClosings[9], outputFile);
htmlCollection.tags.isClosed = true;
}
break;
case 0:
// Special threatment case, there is a newline following, close the paragraph
if (oldChar == '\n' || oldChar == '\r') {
fputs(tagClosings[9], outputFile);
htmlCollection.tags.isClosed = true;
}
break;
default:
// If anything else follows and we deal with a paragraph, reset it to avoid creation of a new one
if (tagType == 9) {
tagType = -1; // Reset, only affects the current dealed with tag
}
break;
}

} else if (htmlCollection.tags.tagType == 10) {
// Add and close a quote tag

if (lineEnd && nextChar != '>' && (nextChar == '\n' || nextChar == '\r')) {
// if we are at the end of the line and next line has no connected quote markdown, close the quote
fputs(tagClosings[10], outputFile);
htmlCollection.tags.isClosed = true;
htmlCollection.tags.isListEnd = true;
}
} else {
if (tagType == htmlCollection.tags.tagType) {
// If the processed tag type is equal to the current processed one (we go from top to bottom/backwards), close this tag
tagIsClosed = true; // Set this, to avoid readding another closing for this tag
htmlCollection.tags.isClosed = true; // Close the tag
fputs(tagClosings[htmlCollection.tags.tagType], outputFile);
} else if (htmlCollection.tags.tagType > 5 && htmlCollection.tags[htmlCollection.count - 1].tagType == tagType && !htmlCollection.tags[htmlCollection.count - 1].isClosed) {
// if we dont deal with a headline, close the tag
fputs(tagClosings[htmlCollection.tags.tagType], outputFile);
} else if (lineEnd) {
// if we deal with a headline and are at the line end, close it as a headline affects the whole line
// close only at end
fputs(tagClosings[htmlCollection.tags.tagType], outputFile);
htmlCollection.tags.isClosed = true;
}
}
}
}

if (isParserAtEnd) {
// EOF, break out the main loop
break;
} else {
fseek(inputFile, -1, SEEK_CUR);
}
}

//--------------------------------------------------------------------------
// Here we start to check for closing of tags or handle if we have to create a new html tag

if (tagType != -1 && !tagIsClosed ) {
// Add tag html to outputFile

bool doCreateTag = true; // Create a new tag by defualt


if (tagType == 7 || tagType == 8 || tagType == 11) {
// Check if we have a following markdown character for text formatting
// (bold, italic) or if a '*' only occurs as normal text
bool addLeadingParagraph = true;

// Check if we have any open data format
for (long i = htmlCollection.count - 1; i > -1; --i) {
if ((htmlCollection.tags.tagType == 6 || htmlCollection.tags.tagType == 9 || htmlCollection.tags.tagType == 10) && !htmlCollection.tags.isClosed) {
// Wrap into a paragraph if not present for some items
addLeadingParagraph = false;
break;
}
}

if (addLeadingParagraph) {
htmlCollection.tags = realloc(htmlCollection.tags, sizeof(html_tag) * (htmlCollection.count + 1));
htmlCollection.tags[htmlCollection.count].isClosed = false;
htmlCollection.tags[htmlCollection.count].isSibling = false;
htmlCollection.tags[htmlCollection.count].isListEnd = false;
htmlCollection.tags[htmlCollection.count].tagType = 9;
htmlCollection.tags[htmlCollection.count].formatDepth = 0;
++htmlCollection.count;
fputs(tagOpenings[9], outputFile); // Add the "<p>"
}

doCreateTag = false;

long orgPos = ftell(inputFile); // Save the current file position
char dataChar = '\0'; // The current character
bool doExit = false; // Should we exit the while loop?
short tempFormatDepth = 0; // Temporary store the depth on look aheads


while (true) {
dataChar = fgetc(inputFile);
switch (dataChar) {
case '\n':
case '\r':
// We are at the end of the line...
doCreateTag = false; // Dont create a text format tag
doExit = true; // Exit the loop!
if (tagType == 7) {
// If we have an bold tag, place one addional star, which otherwise would be lost
depthDiff = 1;
} else if (tagType == 11) {
// If we have an italicbold tag, place two addional asterisks, which otherwise would be lost
depthDiff = 2;
}
break;
case '*':
tempFormatDepth = 1;

while (fgetc(inputFile) == '*') {
++tempFormatDepth;
}

if (tempFormatDepth == formatDepth) { // The asterisk match
doCreateTag = true;
doExit = true;
} else {
// The tag is smaller as the one initially provided
// if its not, it could be another nested tag this seems to do less harm as the opposite
if (formatDepth > tempFormatDepth) {
depthDiff = formatDepth - 1;
doExit = true;
}
}

fseek(inputFile, -1, SEEK_CUR);
break;
default:
break;
}

if (doExit || dataChar == EOF) {
break;
}
}

fseek(inputFile, orgPos, SEEK_SET); // Reset to current reading position
}



if (doCreateTag) {
// Yes, we create a html tag
bool isSibling = false;

if (tagType == 6) {
// If we deal with a list item
bool hasOpener = false;

for (long i = htmlCollection.count - 1; i > -1; --i) {
if (htmlCollection.tags.tagType == 6 && !htmlCollection.tags.isListEnd && !htmlCollection.tags.isSibling) {
hasOpener = true;
break;
} else if (htmlCollection.tags.tagType == 6 && htmlCollection.tags.isListEnd) {
break;
}
}

if (!hasOpener) {
// There is no list open, create a new "<ul><li>"...
fputs("<ul>", outputFile);
fputs(tagOpenings[tagType], outputFile); // Add the <li>
isSibling = false;
} else {
// We have a open list, create only the "<li>"
fputs(tagOpenings[tagType], outputFile);
isSibling = true;
}

} else {
if (lineStart && (tagType == 7 || tagType == 8 || tagType == 11)) {
// If we are at lineStart and have bold or italic markdown or bolditalic
bool hasOpenTag = false;
for (long i = htmlCollection.count - 1;i > -1; --i) {
if (htmlCollection.tags.tagType == 9 && !htmlCollection.tags.isClosed) {
// We are inside a paragraph, dont create a new one
hasOpenTag = true;
break;
}
}

if (!hasOpenTag) {
// The markdown is not surrounded by a paragraph, create one and put its data in memory
htmlCollection.tags = realloc(htmlCollection.tags, sizeof(html_tag) * (htmlCollection.count + 1));
htmlCollection.tags[htmlCollection.count].isClosed = false;
htmlCollection.tags[htmlCollection.count].isSibling = false;
htmlCollection.tags[htmlCollection.count].isListEnd = false;
htmlCollection.tags[htmlCollection.count].tagType = 9;
htmlCollection.tags[htmlCollection.count].formatDepth = 0;
++htmlCollection.count;
fputs(tagOpenings[9], outputFile); // Add the "<p>"
}
}

fputs(tagOpenings[tagType], outputFile); // Add the html markdown variant for the text format
}

// Put the data for the new tag in memory
htmlCollection.tags = realloc(htmlCollection.tags, sizeof(html_tag) * (htmlCollection.count + 1));
htmlCollection.tags[htmlCollection.count].isClosed = false;
htmlCollection.tags[htmlCollection.count].isSibling = isSibling;
htmlCollection.tags[htmlCollection.count].isListEnd = false;
htmlCollection.tags[htmlCollection.count].tagType = tagType;
htmlCollection.tags[htmlCollection.count].formatDepth = formatDepth;
++htmlCollection.count;

} else {
// We dont create a new tag, this is because its a regular '*' inside the text, so we add this symbol
tagType = -1;
}

}

// Special case handling for line breaks if we have no tag starts here, tagtype -1 means, we have a regular character
// tagtype 9, we openend up a paragraph
if (tagType == -1 || tagType == 9) {

// If we dont have a tag markdown character or a normal text charater with a paragraph
bool addedNewLine = false;

if (lineEnd) {

// if we are at lineEnd safely check if we have a open paragraph we are inside of
nextChar = fgetc(inputFile);

if (nextChar == '>') {
nextChar = fgetc(inputFile);

if (nextChar != '\n' && nextChar != '\r') {
for (long i = htmlCollection.count - 1; i > -1; --i) {
if (!htmlCollection.tags.isClosed && (htmlCollection.tags.tagType == 9 || htmlCollection.tags.tagType == 10)) {
// We have an open paragraph or blockquote

// If we have either a list element, bold or italic text, set a new line

if (htmlCollection.tags[htmlCollection.count - 1].tagType >= 7 && htmlCollection.tags[htmlCollection.count - 1].tagType <= 11) {
if (htmlCollection.tags.tagType == 10 && nextChar != '>') {
fputs("<br/>\n", outputFile); // set a html line ending "<br/>"

// Any text is not surrounded by a paragraph, create one and put its data in memory
htmlCollection.tags = realloc(htmlCollection.tags, sizeof(html_tag) * (htmlCollection.count + 1));
htmlCollection.tags[htmlCollection.count].isClosed = false;
htmlCollection.tags[htmlCollection.count].isSibling = false;
htmlCollection.tags[htmlCollection.count].isListEnd = false;
htmlCollection.tags[htmlCollection.count].tagType = 9;
htmlCollection.tags[htmlCollection.count].formatDepth = 0;
++htmlCollection.count;
fputs(tagOpenings[9], outputFile); // Add the "<p>"
addedNewLine = true;
break;
} else if (htmlCollection.tags.tagType == 9 && nextChar == ' ') {
fputs("<br/>", outputFile); // set a html line ending "<br/>"
break;
}
}
}
}

fseek(inputFile, -1, SEEK_CUR);
}

fseek(inputFile, -1, SEEK_CUR);

} else if (nextChar != '\n' && nextChar != '\r') {
oldChar = nextChar;
nextChar = fgetc(inputFile);

if (oldChar == '*' && nextChar != ' ' && htmlCollection.count != 0 && !htmlCollection.tags[htmlCollection.count - 1].isClosed && (htmlCollection.tags[htmlCollection.count - 1].tagType == 9 || htmlCollection.tags[htmlCollection.count - 1].tagType == 10)) {
// This checks, if we a possible format or list character which would avoid creating a line break in some cases
fputs("<br/>", outputFile); // set a html line ending "<br/>"
} else {
// Test if we have open items...
hasOpenQuote = false;
hasOpenParagraph = false;
hasOpenList = false;

if (nextChar == ' ') {
for (long i = htmlCollection.count - 1; i > -1; --i) {
if (htmlCollection.tags.tagType == 10 && !htmlCollection.tags.isClosed) {
// We have an open blockquote
hasOpenQuote = true;
break;
} else if (htmlCollection.tags.tagType == 9 && !htmlCollection.tags.isClosed) {
hasOpenParagraph = true;
break;
} else if (htmlCollection.tags.tagType == 6 && !htmlCollection.tags.isClosed && !htmlCollection.tags.isListEnd) {
hasOpenList = true;
break;
}
}
}

if (!lineStart && (!hasOpenQuote && hasOpenParagraph && !hasOpenList)) {
if (htmlCollection.count != 0 && htmlCollection.tags[htmlCollection.count - 1].tagType != 6)
fputs("<br/>", outputFile); // set a html line ending "<br/>"
}
}

fseek(inputFile, -2, SEEK_CUR);
} else {
fseek(inputFile, -1, SEEK_CUR);
}

}

// Write out asterik characters in case we have a mismatch from formatting
if (depthDiff != 0) {
for (int i = 0;i < depthDiff; ++i) {
fputc('*', outputFile);
}
}


// Store any other data like regular text and such into output, char by char...
// Escape only angle brackets with html entities, other characters stay
if (!addedNewLine) {
if (inputChar == '<') {
fputs("<", outputFile);
} else if (inputChar == '>') {
fputs(">", outputFile);
} else {
fputc(inputChar, outputFile);
}
}
}

//--------------------------------------------------------------------------
lineStart = false; // Set that we are not anymore at the line start after processing one character

if (lineEnd) {
// If we are at the line end, set linestart active again
lineStart = true;
lineEnd = false;
}

//--------------------------------------------------------------------------
if (inputChar == EOF) {
// End of file character found, break the main loop
break;
}

}

//----------------------------------------------------------------------------
// Cleanup
fclose(inputFile);
fclose(outputFile);

free(inputName);
free(outputName);
free(htmlCollection.tags);

//----------------------------------------------------------------------------
printf("Finished parsing conversion.\n");
return EXIT_SUCCESS;
}[/src]
 

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.677
  • Thread Starter Thread Starter
  • #80
Code Competition für Mai 2017: Das Rucksackproblem

Ich weiß das folgt jetzt etwas harsch aufeinander, aber es gibt bereits eine neue Challenge. Und Drfuture hatte ja indirekt darum gebeten, dass diese auch hier mit "angekündigt" werden.

Also hier ist sie, die aktuelle Code Competition für Mai 2017:
"Das Rucksackproblem"

Aufgabenkurzbeschreibung von IT-Talents.de:

Aufgabe

Das Rucksackproblem ist eine in der Informatik bekannte Problemstellung.
Stell Dir vor, Du stehst am Check-in-Schalter von "Knapsack"-Airlines und erfährst, dass Du Deine einzelnen Gepäckstücke, die unterschiedlich wertvoll sind, in Deinem Rucksack verstauen musst. Dein Rucksack darf insgesamt maximal 15 kg wiegen, sonst geht er nicht mehr als Handgepäck durch und wird abgewiesen. Es ist klar, das Du nicht alle Gepäckstücke wirst mitnehmen können. Du musst nun eine Lösung finden, wie Du Deinen Rucksack am besten packst, um die wichtigsten Gepäckstücke mitzunehmen.

Und hier geht es zur Competition-Seite.

Preise gibt es für die Gewinner der Challenge in Bargeldform von IT-Talents für die ersten 3 Plätze.

Allen die teilnehmen wollen auch viel Erfolg an dieser Stelle und natürlich jede Menge Spaß! :)
 
Oben