1// Copyright 2018 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <errno.h> 6#include <stdio.h> 7 8#include <fstream> 9#include <iostream> 10#include <memory> 11#include <string> 12#include <vector> 13 14#include <fidl/formatter.h> 15#include <fidl/identifier_table.h> 16#include <fidl/lexer.h> 17#include <fidl/parser.h> 18#include <fidl/source_manager.h> 19 20namespace { 21 22void Usage(const std::string& argv0) { 23 std::cout 24 << "usage: " << argv0 << " <options> <files>\n" 25 "\n" 26 " * `-i, --in-place` Formats file in place\n" 27 "\n" 28 " * `-h, --help`. Prints this help, and exit immediately.\n" 29 "\n"; 30 std::cout.flush(); 31} 32 33[[noreturn]] void FailWithUsage(const std::string& argv0, const char* message, ...) { 34 va_list args; 35 va_start(args, message); 36 vfprintf(stderr, message, args); 37 va_end(args); 38 Usage(argv0); 39 exit(1); 40} 41 42[[noreturn]] void Fail(const char* message, ...) { 43 va_list args; 44 va_start(args, message); 45 vfprintf(stderr, message, args); 46 va_end(args); 47 exit(1); 48} 49 50bool Format(const fidl::SourceFile& source_file, fidl::IdentifierTable* identifier_table, 51 fidl::ErrorReporter* error_reporter, std::string& output) { 52 fidl::Lexer lexer(source_file, identifier_table); 53 fidl::Parser parser(&lexer, error_reporter); 54 std::unique_ptr<fidl::raw::File> ast = parser.Parse(); 55 if (!parser.Ok()) { 56 return false; 57 } 58 fidl::raw::FormattingTreeVisitor visitor; 59 visitor.OnFile(ast); 60 output = *visitor.formatted_output(); 61 return true; 62} 63 64} // namespace 65 66int main(int argc, char* argv[]) { 67 std::vector<std::string> args(argc); 68 for (int i = 0; i < argc; i++) { 69 args[i] = argv[i]; 70 } 71 72 bool in_place = false; 73 int pos = 1; 74 // Process options 75 while (pos < args.size() && args[pos] != "--" && args[pos].find("-") == 0) { 76 if (args[pos] == "-i" || args[pos] == "--in-place") { 77 in_place = true; 78 } else if (args[pos] == "-h" || args[pos] == "--help") { 79 Usage(args[0]); 80 exit(0); 81 } else { 82 FailWithUsage(args[0], "Unknown argument: %s\n", args[pos].c_str()); 83 } 84 pos++; 85 } 86 87 if (pos >= args.size()) { 88 // TODO: Should probably read a file from stdin, instead. 89 FailWithUsage(args[0], "No files provided"); 90 } 91 92 fidl::SourceManager source_manager; 93 94 // Process filenames 95 for (; pos < args.size(); pos++) { 96 std::string arg = args[pos]; 97 if (!source_manager.CreateSource(arg.data())) { 98 Fail("Couldn't read in source data from %s\n", arg.data()); 99 } 100 } 101 102 fidl::IdentifierTable identifier_table; 103 fidl::ErrorReporter error_reporter; 104 for (const auto& source_file : source_manager.sources()) { 105 std::string output; 106 if (!Format(*source_file, &identifier_table, &error_reporter, output)) { 107 error_reporter.PrintReports(); 108 return 1; 109 } 110 FILE* out_file; 111 if (in_place) { 112 const char* filename = source_file->filename().data(); 113 out_file = fopen(filename, "w+"); 114 if (out_file == nullptr) { 115 std::string error = "Fail: cannot open file: "; 116 error.append(filename); 117 error.append(":\n"); 118 error.append(strerror(errno)); 119 Fail(error.c_str()); 120 } 121 } else { 122 out_file = stdout; 123 } 124 fprintf(out_file, "%s", output.c_str()); 125 } 126} 127