001/////////////////////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code and other text files for adherence to a set of rules. 003// Copyright (C) 2001-2025 the original author or authors. 004// 005// This library is free software; you can redistribute it and/or 006// modify it under the terms of the GNU Lesser General Public 007// License as published by the Free Software Foundation; either 008// version 2.1 of the License, or (at your option) any later version. 009// 010// This library is distributed in the hope that it will be useful, 011// but WITHOUT ANY WARRANTY; without even the implied warranty of 012// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013// Lesser General Public License for more details. 014// 015// You should have received a copy of the GNU Lesser General Public 016// License along with this library; if not, write to the Free Software 017// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 018/////////////////////////////////////////////////////////////////////////////////////////////// 019 020package com.puppycrawl.tools.checkstyle.checks; 021 022import java.io.File; 023import java.io.IOException; 024import java.nio.file.Files; 025import java.util.Locale; 026 027import com.puppycrawl.tools.checkstyle.StatelessCheck; 028import com.puppycrawl.tools.checkstyle.api.AbstractFileSetCheck; 029import com.puppycrawl.tools.checkstyle.api.FileText; 030 031/** 032 * <div> 033 * Checks whether the files have a specific line ending (LF or CRLF). 034 * </div> 035 * 036 * <p> 037 * Files containing mixed line endings may produce multiple violations, one for 038 * each line that does not match the configured line ending. 039 * </p> 040 * 041 * <p> 042 * Notes: 043 * This check treats each line independently and reports violations 044 * per line. 045 * </p> 046 * 047 * @since 12.4.0 048 */ 049@StatelessCheck 050public class LineEndingCheck extends AbstractFileSetCheck { 051 052 /** 053 * A key is pointing to the warning message text in "message.properties" 054 * file. 055 */ 056 public static final String MSG_KEY_UNABLE_OPEN = "unable.open"; 057 058 /** 059 * A key is pointing to the warning message text in "message.properties" 060 * file. 061 */ 062 public static final String MSG_KEY_WRONG_ENDING_LF = "wrong.line.end"; 063 064 /** 065 * A key is pointing to the warning message text in "message.properties" 066 * file. 067 */ 068 public static final String MSG_KEY_WRONG_ENDING_CRLF = "wrong.line.end.crlf"; 069 070 /** 071 * Default line separator LF. 072 */ 073 private LineEndingOption lineEnding = LineEndingOption.LF; 074 075 @Override 076 protected void processFiltered(File file, FileText fileText) { 077 try { 078 readAndCheckFile(file); 079 } 080 catch (final IOException ignore) { 081 log(0, MSG_KEY_UNABLE_OPEN, file.getPath()); 082 } 083 } 084 085 /** 086 * Setter to set lineEnding. 087 * 088 * @param ending string of value LF or CRLF 089 * @since 12.3.0 090 */ 091 public void setLineEnding(String ending) { 092 lineEnding = Enum.valueOf(LineEndingOption.class, 093 ending.trim().toUpperCase(Locale.ENGLISH)); 094 } 095 096 /** 097 * Reads the given file and checks its line endings against the configured 098 * line ending option. 099 * 100 * @param file the file to be processed 101 * @throws IOException if an I/O error occurs while reading the file 102 */ 103 private void readAndCheckFile(File file) throws IOException { 104 final byte[] content = Files.readAllBytes(file.toPath()); 105 106 if (lineEnding == LineEndingOption.LF) { 107 checkLfLineEndings(content); 108 } 109 else { 110 checkCrlfLineEndings(content); 111 } 112 } 113 114 /** 115 * Checks that the file content uses LF line endings. 116 * 117 * @param content the file content as a byte array 118 */ 119 private void checkLfLineEndings(byte... content) { 120 int line = 1; 121 122 for (int index = 0; index < content.length; index++) { 123 if (LineEndingOption.LF.matches(content[index])) { 124 if (index > 0 && LineEndingOption.isCarriageReturn(content[index - 1])) { 125 log(line, MSG_KEY_WRONG_ENDING_LF); 126 } 127 line++; 128 } 129 } 130 } 131 132 /** 133 * Checks that the file content uses CRLF line endings. 134 * 135 * @param content the file content as a byte array 136 */ 137 private void checkCrlfLineEndings(byte... content) { 138 int line = 1; 139 140 for (int index = 0; index < content.length; index++) { 141 if (LineEndingOption.LF.matches(content[index])) { 142 if (index == 0 || !LineEndingOption.isCarriageReturn(content[index - 1])) { 143 log(line, MSG_KEY_WRONG_ENDING_CRLF); 144 } 145 line++; 146 } 147 } 148 } 149 150}