| ... | ... | @@ -2637,6 +2637,50 @@ fn argvCmd(allocator: *Allocator, argv: []const []const u8) ![]u8 { |
| 2637 | 2637 | return cmd.toOwnedSlice(); |
| 2638 | 2638 | } |
| 2639 | 2639 | |
| 2640 | fn readSourceFileToEndAlloc(allocator: *mem.Allocator, input: *const fs.File, size_hint: ?usize) ![]const u8 { |
| 2641 | const source_code = input.readToEndAllocOptions( |
| 2642 | allocator, |
| 2643 | max_src_size, |
| 2644 | size_hint, |
| 2645 | @alignOf(u16), |
| 2646 | null, |
| 2647 | ) catch |err| switch (err) { |
| 2648 | error.ConnectionResetByPeer => unreachable, |
| 2649 | error.ConnectionTimedOut => unreachable, |
| 2650 | error.NotOpenForReading => unreachable, |
| 2651 | else => |e| return e, |
| 2652 | }; |
| 2653 | errdefer allocator.free(source_code); |
| 2654 | |
| 2655 | // Detect unsupported file types with their Byte Order Mark |
| 2656 | const unsupported_boms = [_][]const u8{ |
| 2657 | "\xff\xfe\x00\x00", // UTF-32 little endian |
| 2658 | "\xfe\xff\x00\x00", // UTF-32 big endian |
| 2659 | "\xfe\xff", // UTF-16 big endian |
| 2660 | }; |
| 2661 | for (unsupported_boms) |bom| { |
| 2662 | if (mem.startsWith(u8, source_code, bom)) { |
| 2663 | return error.UnsupportedEncoding; |
| 2664 | } |
| 2665 | } |
| 2666 | |
| 2667 | // If the file starts with a UTF-16 little endian BOM, translate it to UTF-8 |
| 2668 | if (mem.startsWith(u8, source_code, "\xff\xfe")) { |
| 2669 | const source_code_utf16_le = mem.bytesAsSlice(u16, source_code); |
| 2670 | const source_code_utf8 = std.unicode.utf16leToUtf8Alloc(allocator, source_code_utf16_le) catch |err| switch (err) { |
| 2671 | error.DanglingSurrogateHalf => error.UnsupportedEncoding, |
| 2672 | error.ExpectedSecondSurrogateHalf => error.UnsupportedEncoding, |
| 2673 | error.UnexpectedSecondSurrogateHalf => error.UnsupportedEncoding, |
| 2674 | else => |e| return e, |
| 2675 | }; |
| 2676 | |
| 2677 | allocator.free(source_code); |
| 2678 | return source_code_utf8; |
| 2679 | } |
| 2680 | |
| 2681 | return source_code; |
| 2682 | } |
| 2683 | |
| 2640 | 2684 | pub const usage_fmt = |
| 2641 | 2685 | \\Usage: zig fmt [file]... |
| 2642 | 2686 | \\ |
| ... | ... | @@ -2708,9 +2752,10 @@ pub fn cmdFmt(gpa: *Allocator, args: []const []const u8) !void { |
| 2708 | 2752 | fatal("cannot use --stdin with positional arguments", .{}); |
| 2709 | 2753 | } |
| 2710 | 2754 | |
| 2711 | | const stdin = io.getStdIn().reader(); |
| 2712 | | |
| 2713 | | const source_code = try stdin.readAllAlloc(gpa, max_src_size); |
| 2755 | const stdin = io.getStdIn(); |
| 2756 | const source_code = readSourceFileToEndAlloc(gpa, &stdin, null) catch |err| { |
| 2757 | fatal("unable to read stdin: {s}", .{err}); |
| 2758 | }; |
| 2714 | 2759 | defer gpa.free(source_code); |
| 2715 | 2760 | |
| 2716 | 2761 | var tree = std.zig.parse(gpa, source_code) catch |err| { |
| ... | ... | @@ -2785,6 +2830,7 @@ const FmtError = error{ |
| 2785 | 2830 | EndOfStream, |
| 2786 | 2831 | Unseekable, |
| 2787 | 2832 | NotOpenForWriting, |
| 2833 | UnsupportedEncoding, |
| 2788 | 2834 | } || fs.File.OpenError; |
| 2789 | 2835 | |
| 2790 | 2836 | fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool, dir: fs.Dir, sub_path: []const u8) FmtError!void { |
| ... | ... | @@ -2850,21 +2896,15 @@ fn fmtPathFile( |
| 2850 | 2896 | if (stat.kind == .Directory) |
| 2851 | 2897 | return error.IsDir; |
| 2852 | 2898 | |
| 2853 | | const source_code = source_file.readToEndAllocOptions( |
| 2899 | const source_code = try readSourceFileToEndAlloc( |
| 2854 | 2900 | fmt.gpa, |
| 2855 | | max_src_size, |
| 2901 | &source_file, |
| 2856 | 2902 | std.math.cast(usize, stat.size) catch return error.FileTooBig, |
| 2857 | | @alignOf(u8), |
| 2858 | | null, |
| 2859 | | ) catch |err| switch (err) { |
| 2860 | | error.ConnectionResetByPeer => unreachable, |
| 2861 | | error.ConnectionTimedOut => unreachable, |
| 2862 | | error.NotOpenForReading => unreachable, |
| 2863 | | else => |e| return e, |
| 2864 | | }; |
| 2903 | ); |
| 2904 | defer fmt.gpa.free(source_code); |
| 2905 | |
| 2865 | 2906 | source_file.close(); |
| 2866 | 2907 | file_closed = true; |
| 2867 | | defer fmt.gpa.free(source_code); |
| 2868 | 2908 | |
| 2869 | 2909 | // Add to set after no longer possible to get error.IsDir. |
| 2870 | 2910 | if (try fmt.seen.fetchPut(stat.inode, {})) |_| return; |