import singlog; import core.stdc.stdlib : exit, EXIT_SUCCESS, EXIT_FAILURE; import std.stdio, std.conv, std.path, std.file, std.format, std.regex, std.array, std.algorithm, std.uuid; import source.database; import source.sql; enum { GROUP_THEME = 2, GROUP_THEME_TEXT = 5, GROUP_QUESTION = 7, GROUP_QUESTION_TEXT = 10, GROUP_ANSWER = 12, GROUP_ANSWER_TEXT = 15, GROUP_ANSWER_RIGHT = 17, GROUP_ANSWER_RIGHT_TEXT = 20, GROUP_IMAGE = 22, GROUP_IMAGE_NAME = 25, } int main(string[] args) { log.level(log.level.debugging) .output(log.output.stdout.stderr) .color(true); const string pictures = "./images"; string testFilePath; string databaseFile; if (args.length != 3) { log.e("Не было передано необходимое количество параметров для запуска программы"); return EXIT_FAILURE; } databaseFile = args[1]; testFilePath = args[2]; const string pattern = "^((( |\\t)*\\#( |\\t)*)(.*[^\\s]))|((( |\\t)*\\?( |\\t)*)(.*[^\\s]))" ~ "|((( |\\t)*-( |\\t)*)(.*[^\\s]))|((( |\\t)*\\+( |\\t)*)(.*[^\\s]))|((( |\\t)*\\*( |\\t)*)(.*[^\\s]))$"; File testFile; try { testFile = File(testFilePath, "r"); } catch (Exception e) { log.w("Unable to open the test file " ~ testFilePath); log.e(e); return EXIT_FAILURE; } dbliteConnect(databaseFile); auto regular = regex(pattern, "m"); struct Answer { int number; string text; bool truth; bool addToDB(int question_id) { int id = sqlAddNewAnswer(question_id, this.number, this.text, this.truth); if (!id) return false; return true; } } struct Question { int number; string text; Answer[int] answers; bool hasPicture; ubyte[] picture; string pictureName; int pictureSize; ulong count() { return answers.length; } bool isValid() { bool error = false; if (answers.length <= 1) error = true; if (hasPicture && pictureSize > 256) error = true; return !error; } bool addToDB(int topic_id) { int id = sqlAddNewQuestion( topic_id, this.number, this.text, this.hasPicture, this.picture, this.pictureName); if (!id) return false; foreach (answer; answers.byKeyValue.array.sort!((a, b) => a.key < b.key)) { if (!answer.value.addToDB(id)) return false; } return true; } } struct Theme { string text; Question[int] questions; ulong count() { return questions.length; } bool isValid() { return questions.length > 1; } bool addToDB() { if (!check()) return false; int id = sqlAddNewTheme(this.text); if (!id) return false; foreach (question; this.questions.byKeyValue.array.sort!((a, b) => a.key < b.key)) { if (!question.value.addToDB(id)) return false; } return true; } void print() { writeln("Количество вопросов: %s".format(this.count())); foreach (question; this.questions.byKeyValue.array.sort!((a, b) => a.key < b.key)) { writeln("\tВопрос №%d: %s".format(question.key, question.value.text)); if (question.value.hasPicture) writeln("\tСодержит изображение: %s (%d kB)" .format(question.value.pictureName, question.value.pictureSize)); writeln("\tКоличество ответов: %d".format(question.value.count())); foreach (answer; question.value.answers.byKeyValue.array.sort!((a, b) => a.key < b.key)) { writeln("\t\tОтвет №%d: %s".format(answer.key, answer.value.text)); } } } bool check() { bool error = false; if (!this.isValid()) { writeln("Недостаточное количество вопросов: %d".format(this.count())); error = true; } if (!error) { foreach (question; this.questions.byKeyValue.array.sort!((a, b) => a.key < b.key)) { if (!question.value.isValid()) { writeln("Вопрос №%d \"%s\" содержит недостаточное количество ответов (%d) или большой (> 256 kB) размер изображения (%d kB)" .format(question.key, question.value.text, question.value.count(), question.value.pictureSize)); error = true; } int truth; foreach (answer; question.value.answers) { if (answer.truth) ++truth; } if (truth > 1) { writeln("Вопрос №%d \"%s\" содержит более одного правильного ответа".format( question.key, question.value.text )); error = true; } } } return !error; } } Theme theme; int numQuestion; int numAnswer; while (!testFile.eof()) { string line = testFile.readln(); auto match = matchFirst(line, regular); if (match.length == 0) continue; if (match[GROUP_THEME].length) { theme.text = match[GROUP_THEME_TEXT]; continue; } if (match[GROUP_QUESTION].length) { numAnswer = 0; theme.questions[++numQuestion] = Question(numQuestion, match[GROUP_QUESTION_TEXT]); continue; } if (match[GROUP_ANSWER].length) { theme.questions[numQuestion].answers[++numAnswer] = Answer(numAnswer, match[GROUP_ANSWER_TEXT], false); continue; } if (match[GROUP_ANSWER_RIGHT].length) { theme.questions[numQuestion].answers[++numAnswer] = Answer(numAnswer, match[GROUP_ANSWER_RIGHT_TEXT], true); continue; } if (match[GROUP_IMAGE].length) { string currentPicture = buildPath(pictures, match[GROUP_IMAGE_NAME]); if (currentPicture.exists) { auto picFile = File(currentPicture, "r"); theme.questions[numQuestion].hasPicture = true; theme.questions[numQuestion].picture = cast(ubyte[])read(currentPicture); theme.questions[numQuestion].pictureName = md5UUID(theme.questions[numQuestion].picture).to!string ~ currentPicture.extension; theme.questions[numQuestion].pictureSize = picFile.size().to!int / 1024; } else { log.e("Файл \"%s\" не найден".format(currentPicture)); } continue; } } // theme.print(); // theme.check(); theme.addToDB(); return EXIT_SUCCESS; }