/// <summary> /// Plural msgstr encountered - Abort if it contains a reference, as plural forms /// are not supported yet and will result in the msgstr not being expanded. /// </summary> void TestPluralForm(LineInfo pluralMsgstrLine) { if (GetFirstReference(pluralMsgstrLine.Line, 0) != null) { throw new LineException(pluralMsgstrLine, "Multiple msgstrs encountered, PO plural-forms are not currently supported - Aborting because the msgstr contains a reference which popp will fail to expand."); } else { ErrorEncountered(pluralMsgstrLine, "Multiple msgstrs encountered, PO plural-forms are not currently supported. Non-fatal as line contains nothing to expand (skipping)."); } }
/// <summary> /// Returns a TextReader for the file pointed to by the $include line. /// Remember to Dispose() of it. /// May return null. /// </summary> /// <param name="inputDirectory">The directory that contained the source file that was supplied to popp, or null (e.g. if stdin was the source)</param> /// <param name="currentIncludeDirectory">null unless 'line' is from an $included file, in which case it /// should contain the directory containing the $included file so we can add that to our search path</param> /// <param name="includedFileNameAndPath">set to null unless the function returns a TextReader, in /// which case it's </param> TextReader IncludedTextReader(LineInfo line, string inputDirectory, string currentIncludeDirectory, out string includedFileNameAndPath) { TextReader result = null; FileStream sourceStream = null; includedFileNameAndPath = null; try { string pathAndFileName = null; string fileName = ExtractString(line); // Add inputDirectory and "no directory" to the front of the list of include-directories to search List<string> directoryList = new List<string>(); directoryList.Add(inputDirectory); if (currentIncludeDirectory != null) directoryList.Add(currentIncludeDirectory); directoryList.Add(""); directoryList.AddRange(_options.IncludeDirectories); foreach (string directory in directoryList) { string tempPath = Path.Combine(directory, fileName); if (File.Exists(tempPath)) { pathAndFileName = tempPath; break; } } if (pathAndFileName == null) { throw new LineException( line, "$included source-file not found" + (String.IsNullOrEmpty(fileName) ? "" : ": " + fileName) ); } else { sourceStream = new FileStream(pathAndFileName, FileMode.Open, FileAccess.Read); result = new StreamReader(sourceStream); includedFileNameAndPath = Path.GetFullPath(pathAndFileName); } } catch (LineException) { throw; } catch (Exception ex) { if (sourceStream != null) sourceStream.Close(); throw new LineException(line, "Unexpected error while expanding $include: " + ex); } return result; }
/// <summary> /// Returns either 'line x' or 'line x of "file.po"' depending on whether the /// line came from the source file or an included file. /// </summary> /// <param name="lineInfo"></param> /// <returns></returns> string LineNumberToString(LineInfo lineInfo) { if (lineInfo.IncludeFileID >= 0) { return String.Format( "line {0} of \"{1}\"", lineInfo.LineNumber, Path.GetFileName(_includeFileNames[lineInfo.IncludeFileID]) ); } else { return "line " + lineInfo.LineNumber; } }
/// <summary> /// Extracts the string inside the left-most " and the right-most " /// i.e. extracts the string specified in the line, but does not unencode any escaped characters /// </summary> string ExtractString(LineInfo lineInfo) { string result = String.Empty; // find the characters between the left-most " and the right-most " int quotePosLeft = lineInfo.Line.IndexOf('"'); int quotePosRight = lineInfo.Line.LastIndexOf('"'); if (quotePosLeft < 0 || quotePosRight <= quotePosLeft) { // A note about the wording of this error message: It can occur when quotes are missing // from a .PO entry such as a msgid or msgstr, but it can also happen if quotes are missing // from an $include statement intended for popp. ErrorEncountered(lineInfo, "Missing quotemarks - very bad - line will be missing from output"); } else { result = lineInfo.Line.Substring(quotePosLeft + 1, quotePosRight - quotePosLeft - 1); } return result; }
/// <summary> /// Sends an error message to the console, if errors are not suppressed /// and sets the return value to indicate a non-fatal error. /// </summary> /// <param name="lineNumber">0 if line number is not known, otherwise provide the line of the source file the error was encountered at</param> /// <seealso cref="DisplayInfo"/> void ErrorEncountered(LineInfo lineInfo, string message) { if (!_options.Quiet) { if (lineInfo == null) { Console.Error.WriteLine("Error: " + message); } else { Console.Error.WriteLine("Error on " + LineNumberToString(lineInfo) + ": " + message); } } if (_errorLevel == 0) _errorLevel = (int)ErrorLevel.NonFatalError; }
/// <param name="expandIncludes">if true the referenced file will be inserted, if false, the include will be removed</param> /// <param name="depth">how many includes deep are we</param> /// <param name="includeFileStack">tracks the include files we are inside of, to prevent loops, and to know how deep we are</param> /// <param name="inputDirectory">The directory that contained the source file that was supplied to popp, or null (e.g. if stdin was the source)</param> IEnumerable<LineInfo> BuildListOfLines(TextReader inputReader, string inputDirectory, bool expandIncludes, List<int> includeFileIDStack) { int line_num = 0; int includeFileID = -1; string includeDirectory = null; if (includeFileIDStack.Count > 0) { // We're inside an include file, find our current directory includeFileID = includeFileIDStack.First(); includeDirectory = Path.GetDirectoryName(_includeFileNames[includeFileID]); } string line; List<LineInfo> result = new List<LineInfo>(); while ((line = inputReader.ReadLine()) != null) { line_num++; LineType lineType = DetermineLineType(line, line_num, includeFileID); LineInfo lineInfo = new LineInfo(lineType, line_num, includeFileID, line); if (lineType != LineType.IncludeStatement) { result.Add(lineInfo); } else { // this line is an $include statement if (expandIncludes && includeFileIDStack.Count < cMaxIncludeDepth) { // Expand the included file string includeStatement_File; TextReader includeStatement_FileReader = IncludedTextReader(lineInfo, inputDirectory, includeDirectory, out includeStatement_File); if (includeStatement_FileReader != null) using(includeStatement_FileReader) { int includeStatement_FileID = _includeFileNames.IndexOfFileInList(includeStatement_File); if (includeFileIDStack.Contains(includeStatement_FileID)) { throw new LineException(lineInfo, "Recursive $include statement found. Aborting."); } if (includeStatement_FileID < 0) { // The $include statement is pointing to a new include file, add it to the global list of _includeFileNames _includeFileNames.Add(includeStatement_File); includeStatement_FileID = _includeFileNames.Count - 1; } // push includeStatement_FileID onto includeFileIDStack includeFileIDStack.Insert(0, includeStatement_FileID); try { IEnumerable<LineInfo> includedLines = BuildListOfLines(includeStatement_FileReader, inputDirectory, true, includeFileIDStack); result.AddRange(includedLines); } finally { // pop includeStatement_FileID off includeFileIDStack includeFileIDStack.RemoveAt(0); } } } } } return result; }
/// <param name="expandIncludes">if true the referenced file will be inserted, if false, the include will be removed</param> /// <param name="depth">how many includes deep are we</param> /// <param name="includeFileStack">tracks the include files we are inside of, to prevent loops, and to know how deep we are</param> /// <param name="inputDirectory">The directory that contained the source file that was supplied to popp, or null (e.g. if stdin was the source)</param> IEnumerable <LineInfo> BuildListOfLines(TextReader inputReader, string inputDirectory, bool expandIncludes, List <int> includeFileIDStack) { int line_num = 0; int includeFileID = -1; string includeDirectory = null; if (includeFileIDStack.Count > 0) { // We're inside an include file, find our current directory includeFileID = includeFileIDStack.First(); includeDirectory = Path.GetDirectoryName(_includeFileNames[includeFileID]); } string line; List <LineInfo> result = new List <LineInfo>(); while ((line = inputReader.ReadLine()) != null) { line_num++; LineType lineType = DetermineLineType(line, line_num, includeFileID); LineInfo lineInfo = new LineInfo(lineType, line_num, includeFileID, line); if (lineType != LineType.IncludeStatement) { result.Add(lineInfo); } else { // this line is an $include statement if (expandIncludes && includeFileIDStack.Count < cMaxIncludeDepth) { // Expand the included file string includeStatement_File; TextReader includeStatement_FileReader = IncludedTextReader(lineInfo, inputDirectory, includeDirectory, out includeStatement_File); if (includeStatement_FileReader != null) { using (includeStatement_FileReader) { int includeStatement_FileID = _includeFileNames.IndexOfFileInList(includeStatement_File); if (includeFileIDStack.Contains(includeStatement_FileID)) { throw new LineException(lineInfo, "Recursive $include statement found. Aborting."); } if (includeStatement_FileID < 0) { // The $include statement is pointing to a new include file, add it to the global list of _includeFileNames _includeFileNames.Add(includeStatement_File); includeStatement_FileID = _includeFileNames.Count - 1; } // push includeStatement_FileID onto includeFileIDStack includeFileIDStack.Insert(0, includeStatement_FileID); try { IEnumerable <LineInfo> includedLines = BuildListOfLines(includeStatement_FileReader, inputDirectory, true, includeFileIDStack); result.AddRange(includedLines); } finally { // pop includeStatement_FileID off includeFileIDStack includeFileIDStack.RemoveAt(0); } } } } } } return(result); }
public LineException(LineInfo lineInfo, string message) : base(message) { _lineInfo = lineInfo; }