blob: a7899c4a3702c9f0cb7f8b9147bf5f1609bd96b4 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "tools/kazoo/output_util.h"
#include "tools/kazoo/outputs.h"
#include "tools/kazoo/string_util.h"
namespace {
// This is almost list SplitString() on spaces, but punctuation needs to be treated differently as
// it's broken on, but not discarded (for example, '-' in the middle of words, or '.' attached the
// last word of a sentence.)
//
// TODO(syscall-fidl-transition): 1) This is probably more particular than consumers of the .json
// file really are; 2) There may only be one consumer of this field anyway (update-docs-from-abigen)
// which is in-tree and can just be rewritten in some other way.
std::vector<std::string> BreakAsAbigenParser(const std::string& docstr) {
std::vector<std::string> tokens;
std::string tok;
for (const auto& c : docstr) {
if (isalnum(c) || c == '_') {
tok += c;
} else {
if (!tok.empty())
tokens.push_back(tok);
tok.clear();
if (ispunct(c))
tokens.emplace_back(1, c);
}
}
if (!tok.empty())
tokens.push_back(tok);
return tokens;
}
} // namespace
bool JsonOutput(const SyscallLibrary& library, Writer* writer) {
// Note, no comments allowed in plain json, so no copyright or "is generated" note.
writer->Puts("{\n");
writer->Puts(" \"syscalls\": [\n");
for (size_t j = 0; j < library.syscalls().size(); ++j) {
const auto& syscall = *library.syscalls()[j];
writer->Puts(" {\n");
std::string indent(" ");
auto iprintn = [&indent, &writer](const char* format, ...) {
writer->Puts(indent.c_str());
va_list ap;
va_start(ap, format);
std::string result = StringVPrintf((format + std::string("\n")).c_str(), ap);
va_end(ap);
return writer->Puts(result);
};
auto output_list = [&iprintn](const std::vector<std::string>& items) {
for (size_t i = 0; i < items.size(); ++i) {
iprintn("\"%s\"%s", items[i].c_str(), i == items.size() - 1 ? "" : ",");
}
};
auto in = [&indent]() { indent += " "; };
auto out = [&indent]() { indent = indent.substr(2); };
auto output_attributes_list = [&output_list](const auto& attrib_map) {
std::vector<std::string> items;
items.push_back("*"); // From abigen.
for (const auto& it : attrib_map) {
const auto& attr_name = CamelToSnake(it.first);
if (attr_name == "doc" || attr_name == "arg_reorder") {
continue;
}
items.push_back(attr_name);
}
output_list(items);
};
iprintn("\"name\": \"%s\",", syscall.name().c_str());
iprintn("\"attributes\": [");
in();
output_attributes_list(syscall.attributes());
out();
iprintn("],");
iprintn("\"top_description\": [");
in();
const auto doc_split = BreakAsAbigenParser(syscall.short_description());
if (!doc_split.empty()) {
iprintn(("\"" + JoinStrings(doc_split, "\", \"") + "\"").c_str());
}
out();
iprintn("],");
iprintn("\"requirements\": [");
in();
for (size_t i = 0; i < syscall.rights_specs().size(); ++i) {
std::string rights = syscall.rights_specs()[i];
const bool last_right = i == syscall.rights_specs().size() - 1;
iprintn("%s%s", ("\"" + JoinStrings(BreakAsAbigenParser(rights), "\", \"") + "\"").c_str(),
last_right ? "" : ",");
}
out();
iprintn("],");
iprintn("\"arguments\": [");
in();
for (size_t i = 0; i < syscall.kernel_arguments().size(); ++i) {
const auto& arg = syscall.kernel_arguments()[i];
iprintn("{");
in();
iprintn("\"name\": \"%s\",", arg.name().c_str());
auto type_info = GetJsonName(arg.type());
iprintn("\"type\": \"%s\",", type_info.name.c_str());
iprintn("\"is_array\": %s,", type_info.is_pointer ? "true" : "false");
iprintn("\"attributes\": [");
if (type_info.attribute == "IN") {
iprintn(" \"IN\"");
}
iprintn("]");
out();
const bool last_arg = i == syscall.kernel_arguments().size() - 1;
iprintn("}%s", last_arg ? "" : ",");
}
out();
iprintn("],");
iprintn("\"return_type\": \"%s\"", GetCUserModeName(syscall.kernel_return_type()).c_str());
const bool last_syscall = j == library.syscalls().size() - 1;
writer->Printf(" }%s\n", last_syscall ? "" : ",");
}
writer->Puts(" ]\n");
writer->Puts("}\n");
return true;
}