// Convert a unidiff to a context diff. // Bruno Haible 30.12.1995 (Common Lisp), 12.1.1996 (C++), 25.1.1997 (Java) /* * Copyright (C) 1995, 1996, 1997, 1999, 2000 Bruno Haible * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ import java.io.*; class IntRef { int _i; public IntRef (int i) { _i = i; } public int getValue () { return _i; } public void setValue (int i) { _i = i; } } class DiffParse { public static Long parseInteger (String str, IntRef index) { int i = index.getValue(); boolean negative = false; if (str.charAt(i) == '-') { i++; negative = true; } int after_sign = i; long val = 0; for (;;) { char c = str.charAt(i); if (!(c >= '0' && c <= '9')) break; val = val*10 + (c-'0'); i++; } if (after_sign < i) { index.setValue(i); return new Long(negative ? -val : val); } else return null; // was: throw new NumberFormatException(); } } class ContextIn { DataInput _in_stream; int _linenum; // Number of last read line. String _line; // Last read line, or null. public ContextIn (DataInput stream) { _in_stream = stream; _linenum = 0; _line = null; } // Read the next line. public void nextLine () throws IOException { String line = _in_stream.readLine(); _linenum++; _line = line; } // Read the next line, if the last line has already been digested. public void prepareLine () throws IOException { if (_line == null) nextLine(); } } class ContextOut { DataOutput _out_stream; public ContextOut (DataOutput stream) { _out_stream = stream; } } class UnidiffHunkParams { // An unidiff hunk... int old_start_line; int old_line_count; int new_start_line; int new_line_count; } // ... is introduced by a line of the form "@@ -%d,%d +%d,%d @@%s". class UnidiffHunkParse { public static UnidiffHunkParams parseUnidiffHunkLine (String line) { IntRef index; int i; if (line.length() >= 11) { if ( line.charAt(0) == '@' && line.charAt(1) == '@' && line.charAt(2) == ' ' && line.charAt(3) == '-') { index = new IntRef(4); Long old_start_line = DiffParse.parseInteger(line,index); i = index.getValue(); if (old_start_line != null && i+1 <= line.length() && line.charAt(i) == ',') { index = new IntRef(i+1); Long old_line_count = DiffParse.parseInteger(line,index); i = index.getValue(); if (old_line_count != null && i+2 <= line.length() && line.charAt(i) == ' ' && line.charAt(i+1) == '+') { index = new IntRef(i+2); Long new_start_line = DiffParse.parseInteger(line,index); i = index.getValue(); if (new_start_line != null && i+1 <= line.length() && line.charAt(i) == ',') { index = new IntRef(i+1); Long new_line_count = DiffParse.parseInteger(line,index); i = index.getValue(); if (new_line_count != null && i+3 <= line.length() && line.charAt(i) == ' ' && line.charAt(i+1) == '@' && line.charAt(i+2) == '@') { UnidiffHunkParams result = new UnidiffHunkParams(); result.old_start_line = old_start_line.intValue(); result.old_line_count = old_line_count.intValue(); result.new_start_line = new_start_line.intValue(); result.new_line_count = new_line_count.intValue(); return result; } } } } } } return null; } } class ud2cd { static class PieceBuffer { StringVector _destination; StringVector _buffer; PieceBuffer (StringVector dest) { _destination = dest; _buffer = new StringVector(); } } static class TwoPieceBuffer { PieceBuffer _pb_old; PieceBuffer _pb_new; TwoPieceBuffer (StringVector olds, StringVector news) { _pb_old = new PieceBuffer(olds); _pb_new = new PieceBuffer(news); } void add_old_line (String line) { _pb_old._buffer.addElement(line); } void add_new_line (String line) { _pb_new._buffer.addElement(line); } // flush the buffers static String prep_exclam (String line) { return "! ".concat(line); } static String prep_plus (String line) { return "+ ".concat(line); } static String prep_minus (String line) { return "- ".concat(line); } void done () { StringEnumeration sloop; if (_pb_old._buffer.size() > 0) if (_pb_new._buffer.size() > 0) { // Prepend "! " to each line. for (sloop = new StringVectorEnumerator(_pb_old._buffer); sloop.hasMoreElements(); ) _pb_old._destination.addElement(prep_exclam(sloop.nextElement())); for (sloop = new StringVectorEnumerator(_pb_new._buffer); sloop.hasMoreElements(); ) _pb_new._destination.addElement(prep_exclam(sloop.nextElement())); } else { // Prepend "- " to each old line. for (sloop = new StringVectorEnumerator(_pb_old._buffer); sloop.hasMoreElements(); ) _pb_old._destination.addElement(prep_minus(sloop.nextElement())); } else if (_pb_new._buffer.size() > 0) { // Prepend "+ " to each new line. for (sloop = new StringVectorEnumerator(_pb_new._buffer); sloop.hasMoreElements(); ) _pb_new._destination.addElement(prep_plus(sloop.nextElement())); } else { // Nothing. } _pb_old._buffer.removeAllElements(); _pb_new._buffer.removeAllElements(); } } /* Should have multiple inheritance, really! static class ContextInOut { ContextIn _cin; ContextOut _cout; ContextInOut (DataInput istream, DataOutput ostream) { _cin = new ContextIn(istream); _cout = new ContextOut(ostream); } } */ static class ContextInOut extends ContextIn { DataOutput _out_stream; String _program_name; ContextInOut (DataInput istream, DataOutput ostream) { super (istream); _out_stream = ostream; _program_name = "ud2cd"; } static String two_lines_string (int start_line, int end_line) { if (start_line <= end_line) return String.valueOf(start_line) .concat(",") .concat(String.valueOf(end_line)); else return String.valueOf(start_line); } void doHunks () throws IOException { for (;;) { prepareLine(); if (_line == null) break; UnidiffHunkParams hunk_params = UnidiffHunkParse.parseUnidiffHunkLine(_line); if (hunk_params == null) break; int old_start_line = hunk_params.old_start_line; int new_start_line = hunk_params.new_start_line; int old_end_line = hunk_params.old_start_line + hunk_params.old_line_count - 1; int new_end_line = hunk_params.new_start_line + hunk_params.new_line_count - 1; int old_line_count = hunk_params.old_line_count; int new_line_count = hunk_params.new_line_count; StringVector old_lines = new StringVector(); StringVector new_lines = new StringVector(); boolean no_old_lines = true; boolean no_new_lines = true; TwoPieceBuffer buffer = new TwoPieceBuffer(old_lines,new_lines); loop: for (;;) { _line = null; if (!((old_line_count > 0) || (new_line_count > 0))) break; prepareLine(); if (_line == null) break; if (!(_line.length() >= 1)) break; switch (_line.charAt(0)) { case ' ': { buffer.done(); String sp_line = " ".concat(_line.substring(1)); old_lines.addElement(sp_line); old_line_count--; new_lines.addElement(sp_line); new_line_count--; break; } case '-': { buffer.add_old_line(_line.substring(1)); old_line_count--; no_old_lines = false; break; } case '+': { buffer.add_new_line(_line.substring(1)); new_line_count--; no_new_lines = false; break; } default: break loop; } } buffer.done(); StringEnumeration sloop; _out_stream.writeBytes("***************\n"); _out_stream.writeBytes("*** "); _out_stream.writeBytes(two_lines_string(old_start_line,old_end_line)); _out_stream.writeBytes(" ****\n"); if (!no_old_lines) { for (sloop = new StringVectorEnumerator(old_lines); sloop.hasMoreElements(); ) { _out_stream.writeBytes(sloop.nextElement()); _out_stream.writeBytes("\n"); } } _out_stream.writeBytes("--- "); _out_stream.writeBytes(two_lines_string(new_start_line,new_end_line)); _out_stream.writeBytes(" ----\n"); if (!no_new_lines) { for (sloop = new StringVectorEnumerator(new_lines); sloop.hasMoreElements(); ) { _out_stream.writeBytes(sloop.nextElement()); _out_stream.writeBytes("\n"); } } if ((old_line_count > 0) || (new_line_count > 0)) { System.err.print(_program_name); System.err.print(": Warning: Incomplete hunk ending at line "); System.err.print(_linenum - (_line != null ? 1 : 0)); System.err.println(); } else if ((old_line_count != 0) || (new_line_count != 0)) { System.err.print(_program_name); System.err.print(": Warning: Overly long hunk ending at line "); System.err.print(_linenum - (_line != null ? 1 : 0)); System.err.println(); } } } void doFiles () throws IOException { for (;;) { String headline = null; String oldfile = null; String newfile = null; for (;;) { prepareLine(); if (_line == null) break; if (_line.length() >= 4 && _line.charAt(0) == 'd' && _line.charAt(1) == 'i' && _line.charAt(2) == 'f' && _line.charAt(3) == 'f') headline = _line; else if (_line.length() >= 4 && _line.charAt(0) == '-' && _line.charAt(1) == '-' && _line.charAt(2) == '-' && _line.charAt(3) == ' ') break; else { // System.err.print(_program_name); // System.err.print(": Warning: Junk at line "); // System.err.print(linenum); // System.err.print("."); // System.err.println(); _out_stream.writeBytes(_line); _out_stream.writeBytes("\n"); } _line = null; } if (_line == null) break; if (_line.length() >= 4 && _line.charAt(0) == '-' && _line.charAt(1) == '-' && _line.charAt(2) == '-' && _line.charAt(3) == ' ') { oldfile = _line.substring(4); nextLine(); } if (_line == null) break; if (_line.length() >= 4 && _line.charAt(0) == '+' && _line.charAt(1) == '+' && _line.charAt(2) == '+' && _line.charAt(3) == ' ') { newfile = _line.substring(4); nextLine(); } if (_line == null) break; if (headline != null) { _out_stream.writeBytes(headline); _out_stream.writeBytes("\n"); } if (oldfile != null && newfile != null) { _out_stream.writeBytes("*** "); _out_stream.writeBytes(oldfile); _out_stream.writeBytes("\n"); _out_stream.writeBytes("--- "); _out_stream.writeBytes(newfile); _out_stream.writeBytes("\n"); } doHunks(); } } } // Main program! public static void main (String args[]) { ContextInOut context = new ContextInOut(new DataInputStream(System.in), new DataOutputStream(System.out)); try { context.doFiles(); } catch (IOException e) { System.exit(1); } if (System.out.checkError()) System.exit(1); } }