diff --git a/.gitignore b/.gitignore index 10c4807deeb0bc0087cd866d3525ea972e641256..f674592c232de1996299c1d2b8d6ec359d9d3373 100644 --- a/.gitignore +++ b/.gitignore @@ -64,6 +64,7 @@ autom4te.cache /devel_tools/fc-time /devel_tools/fc-memuse /bin/ocamldep_transitive_closure +/bin/check_newlines #share /share/Makefile.config diff --git a/Makefile b/Makefile index c71e627f4fc670e5c53d88320952156593b693e7..4f8cb85784b3184e2e55a7f3eae91f70e4bec58b 100644 --- a/Makefile +++ b/Makefile @@ -2141,6 +2141,28 @@ clean:: hdrck-clean CURRENT_HEADERS?=open-source CURRENT_HEADER_DIRS?=$(addsuffix /$(CURRENT_HEADERS),$(HEADER_DIRS)) +CHECK_NEWLINES:=./bin/check_newlines$(EXE) + +$(CHECK_NEWLINES): bin/check_newlines.ml + $(PRINT_MAKING) $@ +ifeq ($(OCAMLBEST),opt) + $(OCAMLOPT) unix.cmxa $< -o $@ +else + $(OCAMLC) unix.cma $< -o $@ +endif + +FILES_WITHOUT_NEWLINE := \ + VERSION \ + VERSION_CODENAME \ + $(sort $(wildcard ivette/src/dome/doc/template/static/fonts/*)) \ + $(sort $(wildcard share/*.ico share/*.png share/theme/*/*.png)) + +TESTS_WITHOUT_NEWLINE := \ + tests/spec/unfinished-oneline-acsl-comment.i \ + tests/verisec/suite/programs/apps/SpamAssassin/BID-6679/message_write/test \ + tests/verisec/suite/programs/apps/sendmail/CVE-1999-0047/mime7to8/array_vs_pointer.ods \ + tests/verisec/suite/programs/apps/sendmail/CVE-1999-0047/mime7to8/data_testing.ods \ + # OPEN_SOURCE: set it to 'yes' if you want to check open source headers # STRICT_HEADERS: set it to 'yes' if you want to consider warnings as errors # The target check-headers does the following checks: @@ -2153,7 +2175,7 @@ CURRENT_HEADER_DIRS?=$(addsuffix /$(CURRENT_HEADERS),$(HEADER_DIRS)) # because identical headers but with different encodings are not exactly # easy to distinguish .PHONY: check-headers -check-headers: $(HDRCK) +check-headers: $(HDRCK) $(CHECK_NEWLINES) $(PRINT) "Checking $(DISTRIB_HEADERS) headers (OPEN_SOURCE=$(OPEN_SOURCE), CURRENT_HEADERS=$(CURRENT_HEADERS))..." $(PRINT) "- HEADER_SPEC_FILE=$(HEADER_SPEC_FILE)" $(PRINT) "- CURRENT_HEADER_DIRS=$(CURRENT_HEADER_DIRS)" @@ -2163,8 +2185,8 @@ check-headers: $(HDRCK) $(file >distrib_tests.tmp) $(foreach O,$(DISTRIB_TESTS),$(file >>distrib_tests.tmp,$O)) $(file >header_exceptions.tmp) $(foreach O,$(HEADER_EXCEPTIONS),$(file >>header_exceptions.tmp,$O)) echo "Checking that distributed files terminate with a newline..." - bin/check_newline.sh distrib_files.tmp - bin/check_newline.sh distrib_tests.tmp + $(CHECK_NEWLINES) distrib_files.tmp $(FILES_WITHOUT_NEWLINE) + $(CHECK_NEWLINES) distrib_tests.tmp $(TESTS_WITHOUT_NEWLINE) @if command -v file >/dev/null 2>/dev/null; then \ echo "Checking that distributed files do not use iso-8859..."; \ file --mime-encoding -f distrib_files.tmp -f distrib_tests.tmp | \ diff --git a/bin/check_newline.sh b/bin/check_newline.sh deleted file mode 100755 index d2ff0d0689244708c5965fd35619ef24f0cb9559..0000000000000000000000000000000000000000 --- a/bin/check_newline.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash -e - -# $1: file containing the list of files to check -# prints a warning for each file not finishing with a newline, -# unless it is one of a few well-known exceptions (e.g. VERSION). -# Note: requires the 'file' command-line tool to check which files are text. - -if [ $# -lt 1 ]; then - echo "usage: $0 file_list.txt" - exit 2 -fi - -is_likely_text_file() { - case $(file -b --mime-type - < "$1") in - (text/*) echo "1" - esac -} - -errors=0 - -IFS='' -while read file -do - if [ -n "$(is_likely_text_file "$file")" ]; then - x=$(tail -c 1 "$file") - if [ "$x" != "" ] && [ "$file" != "VERSION" ] && [ "$file" != "VERSION_CODENAME" ]; then - echo "error: no newline at end of file: $file" - errors=$((errors+1)) - fi - fi -done < <(file -f "$1" --mime | grep '\btext' | cut -d: -f1) - -if [ $errors -gt 0 ]; then - echo "Found $errors file(s) with errors." - exit 1 -fi diff --git a/bin/check_newlines.ml b/bin/check_newlines.ml new file mode 100644 index 0000000000000000000000000000000000000000..df74f3ae3dc3c7ae9f78588ddc9d6213fc78c462 --- /dev/null +++ b/bin/check_newlines.ml @@ -0,0 +1,54 @@ +module StringSet = Set.Make(String) + +(* returns true for empty files *) +let is_last_byte_newline filename = + try + let ic = open_in filename in + try + let fd = Unix.descr_of_in_channel ic in + ignore (Unix.lseek fd (-1) Unix.SEEK_END); + let buf = Bytes.create 1 in + let n_bytes_read = Unix.read fd buf 0 1 in + close_in ic; + n_bytes_read <= 0 || Bytes.get buf 0 = '\n' + with + | Unix.Unix_error _ -> + (* probably an empty file; ignoring *) + close_in ic; + true + with + | Sys_error _ -> + (* possibly a non-existing file (e.g. with spaces); ignoring *) + Format.printf "could not open, ignoring file: %s" filename; + true + +(* usage: first argument is a file name containing a list of files + (one per line) to be checked; the remaining arguments are a list of + files to be ignored during checking + (i.e. they do not terminate with newlines). *) +let () = + if Array.length Sys.argv < 2 then begin + Format.printf "usage: %s file_list.txt [ignore1 ignore2 ...]@." Sys.argv.(0); + exit 0 + end; + let errors = ref 0 in + let file_list_ic = open_in Sys.argv.(1) in + let to_ignore = StringSet.of_list (List.tl (Array.to_list Sys.argv)) in + begin + try + while true; do + let filename = input_line file_list_ic in + if not (StringSet.mem filename to_ignore) && + not (is_last_byte_newline filename) then begin + incr errors; + Format.printf "error: no newline at end of file: %s@." filename + end + done + with End_of_file -> + close_in file_list_ic + end; + if !errors > 0 then begin + Format.printf "Found %d file(s) with errors.@." !errors; + exit 1 + end else + exit 0