| ... | @@ -2637,6 +2637,50 @@ fn argvCmd(allocator: *Allocator, argv: []const []const u8) ![]u8 { | ... | @@ -2637,6 +2637,50 @@ fn argvCmd(allocator: *Allocator, argv: []const []const u8) ![]u8 { |
| 2637 | return cmd.toOwnedSlice(); | 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 | pub const usage_fmt = | 2684 | pub const usage_fmt = |
| 2641 | \\Usage: zig fmt [file]... | 2685 | \\Usage: zig fmt [file]... |
| 2642 | \\ | 2686 | \\ |
| ... | @@ -2708,9 +2752,10 @@ pub fn cmdFmt(gpa: *Allocator, args: []const []const u8) !void { | ... | @@ -2708,9 +2752,10 @@ pub fn cmdFmt(gpa: *Allocator, args: []const []const u8) !void { |
| 2708 | fatal("cannot use --stdin with positional arguments", .{}); | 2752 | fatal("cannot use --stdin with positional arguments", .{}); |
| 2709 | } | 2753 | } |
| 2710 | | 2754 | |
| 2711 | const stdin = io.getStdIn().reader(); | 2755 | const stdin = io.getStdIn(); |
| 2712 | | 2756 | const source_code = readSourceFileToEndAlloc(gpa, &stdin, null) catch |err| { |
| 2713 | const source_code = try stdin.readAllAlloc(gpa, max_src_size); | 2757 | fatal("unable to read stdin: {s}", .{err}); |
| | 2758 | }; |
| 2714 | defer gpa.free(source_code); | 2759 | defer gpa.free(source_code); |
| 2715 | | 2760 | |
| 2716 | var tree = std.zig.parse(gpa, source_code) catch |err| { | 2761 | var tree = std.zig.parse(gpa, source_code) catch |err| { |
| ... | @@ -2785,6 +2830,7 @@ const FmtError = error{ | ... | @@ -2785,6 +2830,7 @@ const FmtError = error{ |
| 2785 | EndOfStream, | 2830 | EndOfStream, |
| 2786 | Unseekable, | 2831 | Unseekable, |
| 2787 | NotOpenForWriting, | 2832 | NotOpenForWriting, |
| | 2833 | UnsupportedEncoding, |
| 2788 | } || fs.File.OpenError; | 2834 | } || fs.File.OpenError; |
| 2789 | | 2835 | |
| 2790 | fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool, dir: fs.Dir, sub_path: []const u8) FmtError!void { | 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,21 +2896,15 @@ fn fmtPathFile( |
| 2850 | if (stat.kind == .Directory) | 2896 | if (stat.kind == .Directory) |
| 2851 | return error.IsDir; | 2897 | return error.IsDir; |
| 2852 | | 2898 | |
| 2853 | const source_code = source_file.readToEndAllocOptions( | 2899 | const source_code = try readSourceFileToEndAlloc( |
| 2854 | fmt.gpa, | 2900 | fmt.gpa, |
| 2855 | max_src_size, | 2901 | &source_file, |
| 2856 | std.math.cast(usize, stat.size) catch return error.FileTooBig, | 2902 | std.math.cast(usize, stat.size) catch return error.FileTooBig, |
| 2857 | @alignOf(u8), | 2903 | ); |
| 2858 | null, | 2904 | defer fmt.gpa.free(source_code); |
| 2859 | ) catch |err| switch (err) { | 2905 | |
| 2860 | error.ConnectionResetByPeer => unreachable, | | |
| 2861 | error.ConnectionTimedOut => unreachable, | | |
| 2862 | error.NotOpenForReading => unreachable, | | |
| 2863 | else => |e| return e, | | |
| 2864 | }; | | |
| 2865 | source_file.close(); | 2906 | source_file.close(); |
| 2866 | file_closed = true; | 2907 | file_closed = true; |
| 2867 | defer fmt.gpa.free(source_code); | | |
| 2868 | | 2908 | |
| 2869 | // Add to set after no longer possible to get error.IsDir. | 2909 | // Add to set after no longer possible to get error.IsDir. |
| 2870 | if (try fmt.seen.fetchPut(stat.inode, {})) |_| return; | 2910 | if (try fmt.seen.fetchPut(stat.inode, {})) |_| return; |