/// <summary> /// Reads an openedge log file (that should contain the FILEID trace type) and output all the files /// that were opened during the log session /// When activating logs before a compilation, this can be a safe way to get ALL the includes /// </summary> /// <param name="filePath"></param> /// <param name="encoding"></param> /// <param name="currentDirectory"></param> /// <returns></returns> public static HashSet <string> GetReferencedFilesFromFileIdLog(string filePath, Encoding encoding, string currentDirectory) { // we want to read this kind of line : // [17/04/09@16:44:14.372+0200] P-009532 T-007832 2 4GL FILEID Open E:\Common\CommonObj.i ID=33 // [17/04/09@16:44:14.372+0200] P-009532 T-007832 2 4GL FILEID Open E:\Common space\CommonObji.cls ID=33 var references = new HashSet <string>(StringComparer.OrdinalIgnoreCase); using (var reader = new UoeExportReader(filePath, encoding)) { while (reader.MoveToNextRecordField()) { if (reader.RecordFieldNumber != 5 || reader.RecordValue != "FILEID") { continue; } var currentRecordNumber = reader.RecordNumber; if (!reader.MoveToNextRecordField() || currentRecordNumber != reader.RecordNumber || reader.RecordValue != "Open") { continue; } if (!reader.MoveToNextRecordField() || currentRecordNumber != reader.RecordNumber) { continue; } string foundRef = reader.RecordValue; // E:\Common (or directly E:\Common\CommonObj.i) if (!reader.MoveToNextRecordField() || currentRecordNumber != reader.RecordNumber) { continue; } string lastString = reader.RecordValue; // space\CommonObji.cls (or directly ID=33) do { if (!reader.MoveToNextRecordField() || currentRecordNumber != reader.RecordNumber) { break; } foundRef = $"{foundRef} {lastString}"; lastString = reader.RecordValue; } while (true); if (!Utils.IsPathRooted(foundRef)) { foundRef = Path.GetFullPath(Path.Combine(currentDirectory, foundRef)); } foundRef = foundRef.ToCleanPath(); if (!references.Contains(foundRef)) { references.Add(foundRef); } } } return(references); }
/// <summary> /// Returns the detailed message found in the prohelp folder of dlc corresponding to the given error number /// </summary> /// <param name="dlcPath"></param> /// <param name="errorNumber"></param> /// <returns></returns> public static UoeProMessage GetProMessage(string dlcPath, int errorNumber) { var messageDir = Path.Combine(dlcPath, "prohelp", "msgdata"); if (!Directory.Exists(messageDir)) { return(null); } var messageFile = Path.Combine(messageDir, $"msg{(errorNumber - 1) / 50 + 1}"); if (!File.Exists(messageFile)) { return(null); } UoeProMessage outputMessage = null; var err = errorNumber.ToString(); using (var reader = new UoeExportReader(messageFile, Encoding.Default)) { while (reader.MoveToNextRecordField()) { if (reader.RecordFieldNumber == 0 && reader.RecordValue == err) { outputMessage = new UoeProMessage { Number = errorNumber, Text = reader.MoveToNextRecordField() ? reader.RecordValueNoQuotes : string.Empty, Description = reader.MoveToNextRecordField() ? reader.RecordValueNoQuotes : string.Empty, CategoryFirstLetters = reader.MoveToNextRecordField() ? reader.RecordValueNoQuotes : string.Empty, KnowledgeBase = reader.MoveToNextRecordField() ? reader.RecordValueNoQuotes : string.Empty }; break; } } } return(outputMessage); }
/// <summary> /// Reads an xref file (generated during compilation) and outputs a list of referenced tables and sequences /// This list can then be used to know the dependencies of a given file which in turns help you /// know which file needs to be recompiled when a table is modified (or sequence deleted) /// </summary> /// <param name="filePath"></param> /// <param name="encoding"></param> /// <returns></returns> public static HashSet <string> GetDatabaseReferencesFromXrefFile(string filePath, Encoding encoding) { var references = new HashSet <string>(StringComparer.OrdinalIgnoreCase); using (var reader = new UoeExportReader(filePath, encoding)) { while (reader.MoveToNextRecordField()) { if (reader.RecordFieldNumber != 3) { continue; } string foundRef = null; switch (reader.RecordValue) { // dynamic access case "ACCESS": // "file.p" "file.p" line ACCESS [DATA-MEMBER] random.table1 idx_1 WHOLE-INDEX if (reader.MoveToNextRecordField() && reader.RecordFieldNumber == 4) { foundRef = reader.RecordValue; if (foundRef.Equals("DATA-MEMBER") && reader.MoveToNextRecordField() && reader.RecordFieldNumber == 5) { foundRef = reader.RecordValue; } } break; // dynamic access case "CREATE": case "DELETE": case "UPDATE": case "SEARCH": // "file.p" "file.p" line SEARCH random.table1 idx_1 WHOLE-INDEX if (reader.MoveToNextRecordField() && reader.RecordFieldNumber == 4) { foundRef = reader.RecordValue; } break; // static reference case "REFERENCE": // "file.p" "file.p" line REFERENCE random.table1 if (reader.MoveToNextRecordField() && reader.RecordFieldNumber == 4) { foundRef = reader.RecordValue; } break; // static reference case "NEW-SHR-WORKFILE": case "NEW-SHR-WORKTABLE": case "SHR-WORKFILE": case "SHR-WORKTABLE": // "file.p" "file.p" line SHR-WORKFILE WORKtable2 LIKE random.table1 if (reader.MoveToNextRecordField() && reader.RecordFieldNumber == 4 && reader.MoveToNextRecordField() && reader.RecordFieldNumber == 5 && reader.MoveToNextRecordField() && reader.RecordFieldNumber == 6) { foundRef = reader.RecordValue; } break; default: continue; } if (!references.Contains(foundRef)) { references.Add(foundRef); } } } return(references); }