IOStatus KGrGameIO::fetchLevelData (const QString & dir, const QString & prefix, const int level, KGrLevelData & d, QString & filePath) { filePath = getFilePath (dir, prefix, level); d.level = level; // Level number. d.width = FIELDWIDTH; // Default width of layout grid (28 cells). d.height = FIELDHEIGHT; // Default height of layout grid (20 cells). d.layout = ""; // Codes for the level layout (mandatory). d.name = ""; // Level name (optional). d.hint = ""; // Level hint (optional). // kDebug()<< "LEVEL PATH:" << filePath; openFile.setFileName (filePath); // Check that the level-file exists. if (! openFile.exists()) { return (NotFound); } // Open the file for read-only. if (! openFile.open (QIODevice::ReadOnly)) { return (NoRead); } char c; QByteArray textLine; IOStatus result = UnexpectedEOF; // Determine whether the file is in KGoldrunner v3 or v2 format. bool kgr3Format = (filePath.endsWith (".txt")); if (kgr3Format) { // In KGr 3 format, if a line starts with 'L', check the number. while ((c = getALine (kgr3Format, textLine)) != '\0') { if ((c == 'L') && (textLine.left (3).toInt() == level)) { break; // We have found the required level. } } if (c == '\0') { openFile.close(); // We reached end-of-file. return (UnexpectedEOF); } } // Check for further settings in this level. while ((c = getALine (kgr3Format, textLine)) == '.') { if (textLine.startsWith ("dwf ")) { // Dig while falling is allowed in this level, or not. d.digWhileFalling = textLine.endsWith (" false\n") ? false : true; } } // Get the character-codes for the level layout. if (c == ' ') { result = OK; d.layout = removeNewline (textLine); // Remove '\n'. // Look for a line containing a level name (optional). if ((c = getALine (kgr3Format, textLine)) == ' ') { d.name = removeNewline (textLine); // Remove '\n'. // Look for one or more lines containing a hint (optional). while ((c = getALine (kgr3Format, textLine)) == ' ') { d.hint.append (textLine); } d.hint = removeNewline (d.hint); // Remove final '\n'. } } // kDebug() << "Level:" << level << "Layout length:" << d.layout.size(); // kDebug() << "Name:" << "[" + d.name + "]"; // kDebug() << "Hint:" << "[" + d.hint + "]"; openFile.close(); return (result); }
IOStatus KGrGameIO::fetchGameListData (const Owner o, const QString & dir, QList<KGrGameData *> & gameList, QString & filePath) { QDir directory (dir); QStringList pattern; pattern << "game_*"; QStringList files = directory.entryList (pattern, QDir::Files, QDir::Name); // KGr 3 has a game's data and all its levels in one file. // KGr 2 has all game-data in "games.dat" and each level in a separate file. bool kgr3Format = (files.count() > 0); if (! kgr3Format) { files << "games.dat"; } // Loop to read each file containing game-data. foreach (const QString &filename, files) { if (filename == "game_ende.txt") { continue; // Skip the "ENDE" file. } filePath = dir + filename; KGrGameData * g = initGameData (o); gameList.append (g); // kDebug()<< "GAME PATH:" << filePath; openFile.setFileName (filePath); // Check that the game-file exists. if (! openFile.exists()) { return (NotFound); } // Open the file for read-only. if (! openFile.open (QIODevice::ReadOnly)) { return (NoRead); } char c; QByteArray textLine; QByteArray gameName; // Find the first line of game-data. c = getALine (kgr3Format, textLine); if (kgr3Format) { while ((c != 'G') && (c != '\0')) { c = getALine (kgr3Format, textLine); } } if (c == '\0') { openFile.close(); return (UnexpectedEOF); // We reached end-of-file unexpectedly. } // Loop to extract the game-data for each game on the file. while (c != '\0') { if (kgr3Format && (c == 'L')) { break; // End of KGr 3 game-file header. } // Decode line 1 of the game-data. QList<QByteArray> fields = textLine.split (' '); g->nLevels = fields.at (0).toInt(); g->rules = fields.at (1).at (0); g->prefix = fields.at (2); // kDebug() << "Levels:" << g->nLevels << "Rules:" << g->rules << // "Prefix:" << g->prefix; if (kgr3Format) { // KGr 3 Format: get skill, get game-name from a later line. g->skill = fields.at (3).at (0); } else { // KGr 2 Format: get game-name from end of line 1. int n = 0; // Skip the first 3 fields and extract the rest of the line. n = textLine.indexOf (' ', n) + 1; n = textLine.indexOf (' ', n) + 1; n = textLine.indexOf (' ', n) + 1; gameName = removeNewline (textLine.right (textLine.size() - n)); g->name = i18n (gameName.constData()); } // Check for further settings in this game. // bool usedDwfOpt = false; // For debug. while ((c = getALine (kgr3Format, textLine)) == '.') { if (textLine.startsWith ("dwf ")) { // Dig while falling is allowed in this game, or not. g->digWhileFalling = textLine.endsWith (" false\n") ? false : true; // usedDwfOpt = true; // For debug. } } if (kgr3Format && (c == ' ')) { gameName = removeNewline (textLine); g->name = i18n (gameName.constData()); c = getALine (kgr3Format, textLine); } // qDebug() << "Dig while falling" << g->digWhileFalling // << "usedDwfOpt" << usedDwfOpt << "Game" << g->name; // kDebug() << "Skill:" << g->skill << "Name:" << g->name; // Loop to accumulate lines of about-data. If kgr3Format, exit on // EOF or 'L' line. If not kgr3Format, exit on EOF or numeric line. while (c != '\0') { if ((c == '\0') || (kgr3Format && (c == 'L')) || ((! kgr3Format) && (textLine.at (0) >= '0') && (textLine.at (0) <= '9'))) { break; } g->about.append (textLine); c = getALine (kgr3Format, textLine); } g->about = removeNewline (g->about); // Remove final '\n'. // kDebug() << "Info about: [" + g->about + "]"; if ((! kgr3Format) && (c != '\0')) { filePath = dir + filename; g = initGameData (o); gameList.append (g); } } // END: game-data loop openFile.close(); } // END: filename loop return (OK); }
/* * Extract a list of features from a table. */ static List * analyzeTable(const char * table) { static char fileName[MAXSTRING]; char ** resolved; List * features = NULL; FileInfo info; int k; resolved = resolveTable(table, NULL); if (resolved == NULL) { logMessage(LOG_ERROR, "Cannot resolve table '%s'", table); return NULL; } sprintf(fileName, "%s", *resolved); k = 0; for (k = 0; resolved[k]; k++) free(resolved[k]); free(resolved); if (k > 1) { logMessage(LOG_ERROR, "Table '%s' resolves to more than one file", table); return NULL; } info.fileName = fileName; info.encoding = noEncoding; info.status = 0; info.lineNumber = 0; if ((info.in = fopen(info.fileName, "rb"))) { while (getALine(&info)) { if (info.linelen == 0); else if (info.line[0] == '#') { if (info.linelen >= 2 && info.line[1] == '+') { widechar * key = NULL; widechar * val = NULL; size_t keySize = 0; size_t valSize = 0; info.linepos = 2; if (info.linepos < info.linelen && isIdentChar(info.line[info.linepos])) { key = &info.line[info.linepos]; keySize = 1; info.linepos++; while (info.linepos < info.linelen && isIdentChar(info.line[info.linepos])) { keySize++; info.linepos++; } if (info.linepos < info.linelen && info.line[info.linepos] == ':') { info.linepos++; while (info.linepos < info.linelen && (info.line[info.linepos] == ' ' || info.line[info.linepos] == '\t')) info.linepos++; if (info.linepos < info.linelen && isIdentChar(info.line[info.linepos])) { val = &info.line[info.linepos]; valSize = 1; info.linepos++; while (info.linepos < info.linelen && isIdentChar(info.line[info.linepos])) { valSize++; info.linepos++; } } else goto compile_error; } if (info.linepos == info.linelen) { char * k = widestrToStr(key, keySize); char * v = val ? widestrToStr(val, valSize) : NULL; Feature f = feature_new(k, v); logMessage(LOG_DEBUG, "Table has feature '%s:%s'", f.key, f.val); features = list_conj(features, memcpy(malloc(sizeof(f)), &f, sizeof(f)), NULL, NULL, (void (*)(void *))feature_free); free(k); free(v); } else goto compile_error; } else goto compile_error; } } else break; } fclose(info.in); } else logMessage (LOG_ERROR, "Cannot open table '%s'", info.fileName); return list_sort(features, (int (*)(void *, void *))cmpKeys); compile_error: if (info.linepos < info.linelen) logMessage(LOG_ERROR, "Unexpected character '%c' on line %d, column %d", info.line[info.linepos], info.lineNumber, info.linepos); else logMessage(LOG_ERROR, "Unexpected newline on line %d", info.lineNumber); list_free(features); return NULL; }