public Parser(string file) { SourceFile = file; Header = new GettextBlock(); HeaderFirstLines = 0; Data = new GettextBlockList(); }
public bool Parse() { if (!File.Exists(SourceFile)) { return(false); } try { var rx_regions = new Regex("^#(region|endregion|[1-9]).*$"); var rx_strings = new Regex("^(?<type>msgctxt|msgid|msgid_plural|msgstr|msgstr\\[(?<index>\\d)\\])\\s\"(?<string>.*)\"$"); var rx_srings_continue = new Regex("^\"(?<string>.*)\"$"); var rx_error = new Regex("^(msgid\\s\"|(#[,:.\\|]))"); var block = new GettextBlock(); string str = String.Empty; bool end = false, close_block = false, keep_line = false; bool header = true; Match m; var sr = new StreamReader(SourceFile); for (int line = 0; !end; line++) { end = sr.EndOfStream; if (keep_line) { line--; } else { str = (end ? string.Empty : sr.ReadLine().Trim()); } keep_line = false; if ((close_block = (str.Length == 0)) == false) { bool is_data = false; //UNDONE: Хреновенько, но пока хоть так, чтоб строки не удалял. if (block.ID != null && rx_error.IsMatch(str)) { close_block = keep_line = true; } #region Комментарии else if (str.StartsWith("#")) { if (rx_regions.IsMatch(str)) { close_block = true; } else { is_data = true; if (str.StartsWith("#,")) { block.Flags.Add(str); } else if (str.StartsWith("#:")) { block.Links.Add(str.Substring(2)); } else if (str.StartsWith("#.")) { block.AutoComments.Add(str); } else if (str.StartsWith("#|")) // TODO: Сделать поддержку форматирования предыдущих ID { block.PrevIDs.Add(str); } else if (str.StartsWith("#*")) { block.AltStrings.Add(str); } else { block.Comments.Add(str); } } } #endregion #region Строки else if ((m = rx_strings.Match(str)).Success) { keep_line = true; if (block.StartLine < 0) { block.StartLine = line; } string gs = String.Empty; var breaks = new List <int>(); bool add_break = false; Match gm = m; // Добавления всех последующих обрамленных кавычками строк do { if (add_break) { breaks.Add(gs.Length); } gs += gm.Groups["string"].Value; if ((end = sr.EndOfStream) == false) { str = sr.ReadLine().Trim(); } line++; add_break = true; }while(!end && (gm = rx_srings_continue.Match(str)).Success); close_block = end; switch (m.Groups["type"].Value) { case "msgctxt": block.Context = gs; break; case "msgid": block.ID = gs; block.ID_Breaks = breaks; break; case "msgid_plural": block.IDPlural = gs; block.IDPlural_Breaks = breaks; break; case "msgstr": block.Str = gs; block.Str_Breaks = breaks; break; default: int ind = int.Parse(m.Groups["index"].Value); if (block.StrInd.Length < ind + 1) { Array.Resize(ref block.StrInd, ind + 1); Array.Resize(ref block.StrInd_Breaks, ind + 1); } block.StrInd[ind] = gs; block.StrInd_Breaks[ind] = breaks; break; } } #endregion if (is_data && block.StartLine < 0) { block.StartLine = line; } } #region Завершение блока if (close_block) { if (block.ID != null) { block.LinesCount = line - block.StartLine; if (block.ID.Length == 0) { block.Comments.InsertRange(0, Header.Comments); Header = block; if (HeaderFirstLines > Header.StartLine) { HeaderFirstLines = Header.StartLine; } } else { Data.Add(block); } header = false; } else if (header) { Header.Comments.AddRange(block.Comments); if (str.Length == 0 && Header.ID == null) { Header.Comments.Add(string.Empty); } HeaderFirstLines = line + 1; } block = new GettextBlock(); } #endregion } sr.Close(); return(true); } catch { return(false); } }
void backgroundWorker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e) { #region Обработка файлов if (FilesError == 0) { for (int progress = 0; progress < Files.Count; progress++) { var file = Files[progress]; FilesError = (Stop ? EF_Canceled : 0); string file_src = file.Source, file_upd = file.Update, file_dest = file.Target; bool upd = (file_upd.Length > 0); FilesUpdated = (FilesUpdated || upd); Parser parser_src = new Parser(file_src), paser_upd = new Parser(file_upd); if (FilesError == 0 && !parser_src.Parse()) { FilesError = EF_ParserSrc; } if (FilesError == 0 && upd && !paser_upd.Parse()) { FilesError = EF_ParserUpd; } var data = new List <string>(); #region Отладка парсера #if DebugSourceParser try { var sr = new StreamReader(file_src); data.AddRange(sr.ReadToEnd().Replace("\r\n", "\n").Split('\n')); sr.Close(); Directory.CreateDirectory(SplitPath(file_dest)[0]); var sw = new StreamWriter(file_dest + "~dbg.txt"); for (int bl = 0; bl < parser_src.Data.Count; bl++) { var block = parser_src.Data[bl]; sw.WriteLine(String.Format("——————————— Block {0} ———————————", bl)); for (int ln = 0; ln < block.LinesCount; ln++) { sw.WriteLine(data[block.StartLine + ln]); } } sw.Close(); } catch (Exception ex) { System.Diagnostics.Trace.WriteLine(ex.ToString()); } data.Clear(); #endif #endregion #region Применение изменений bool wri_prev = !RemPrevIDs, wri_strings = !RemStrings, wri_alt = !RemAltStrings, wri_com = !RemComments, wri_autocom = !RemAutoComments, wri_links = !RemLinks, wri_flags = !RemFlags; bool upd_header = (upd && UpdHeader), upd_prev = (upd && UpdPrevIDs), upd_strings = (upd && UpdStrings), upd_alt = (upd && UpdAltStrings), upd_com = (upd && UpdComments), upd_autocom = (upd && UpdAutoComments), upd_links = (upd && UpdLinks), upd_flags = (upd && UpdFlags); if (FilesError == 0) { try { var sr = new StreamReader(file_src); data.AddRange(sr.ReadToEnd().Replace("\r\n", "\n").Split('\n')); sr.Close(); for (int isrc = parser_src.Data.Count - 1; isrc >= 0; isrc--) { var bsrc = parser_src.Data[isrc]; int iupd = paser_upd.Data.IndexOf(bsrc.ID); var bupd = (iupd < 0 ? null : paser_upd.Data[iupd]); var block = new List <string>(); if (wri_com) { block.AddRange(((upd_com && iupd >= 0 ? bupd : bsrc) as GettextBlock).Comments); } if (wri_autocom) { block.AddRange(((upd_autocom && iupd >= 0 ? bupd : bsrc) as GettextBlock).AutoComments); } if (wri_links) { block.AddRange(((upd_links && iupd >= 0 ? bupd : bsrc) as GettextBlock).FormatLinks(FormatLinks)); } if (wri_flags) { block.AddRange(((upd_flags && iupd >= 0 ? bupd : bsrc) as GettextBlock).Flags); } if (wri_prev) { block.AddRange(((upd_prev && iupd >= 0 ? bupd : bsrc) as GettextBlock).PrevIDs); } // TODO: Добавить обновление контекста if (!string.IsNullOrEmpty(bsrc.Context)) { block.Add(bsrc.FormatContext()); } block.AddRange(bsrc.FormatMsgID(FormatIDs)); if (bsrc.IDPlural != null) { block.AddRange(bsrc.FormatMsgIDPlural(FormatIDs)); } GettextBlock buse = (upd_strings && iupd >= 0 ? bupd : bsrc); if (buse.StrInd.Length == 0) { if (wri_strings) { block.AddRange(buse.FormatMsgStr(FormatStrings)); } else { block.Add("msgstr \"\""); } } else { for (int i = 0; i < buse.StrInd.Length; i++) { if (wri_strings) { block.AddRange(buse.FormatMsgStrInd(i, FormatStrings)); } else { block.Add("msgstr \"[" + i + "]\""); } } } if (wri_alt) { block.AddRange(((upd_alt && iupd >= 0 ? bupd : bsrc) as GettextBlock).AltStrings); } data.RemoveRange(bsrc.StartLine, bsrc.LinesCount); data.InsertRange(bsrc.StartLine, block); } if (upd_header) { data.RemoveRange(parser_src.Header.StartLine, parser_src.Header.LinesCount); data.RemoveRange(0, parser_src.HeaderFirstLines); data.InsertRange(0, paser_upd.Header.Comments); int cur = paser_upd.Header.Comments.Count; data.Insert(cur++, "msgid \"\""); data.InsertRange(cur, paser_upd.Header.FormatMsgStr(2)); } if (RemRegions) { var rx = new Regex("^#(region|endregion|[1-9])"); for (int i = data.Count - 1; i >= 0; i--) { if (rx.IsMatch(data[i])) { data.RemoveAt(i); } } } } catch //(Exception ex) { FilesError = EF_Process; //System.Diagnostics.Debug.WriteLine(ex.ToString()); } } #endregion #region Запись нового файла if (FilesError == 0) { try { Directory.CreateDirectory(SplitPath(file_dest)[0]); var sw = new StreamWriter(file_dest + ".tmp"); sw.Write(String.Join("\r\n", data.ToArray())); // foreach (string s in data) // sw.WriteLine(s); sw.Close(); // Net нормально понимает и просто реплейс для любых ситуаций. Mono - нифига. if (File.Exists(file_dest)) { File.Replace(file_dest + ".tmp", file_dest, !BackupFiles ? null : file_dest + ".bak"); } else { File.Move(file_dest + ".tmp", file_dest); } } catch { FilesError = EF_Write; } } #endregion file.Error = FilesError; if (Files.Count > 1) { FilesError = 0; } backgroundWorker.ReportProgress(progress + 1); } } #endregion }