Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 7 Oct 2016 12:57:35 +0000 (UTC)
From:      Ed Maste <emaste@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r306806 - head/usr.bin/dtc
Message-ID:  <201610071257.u97CvZ3V029734@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: emaste
Date: Fri Oct  7 12:57:35 2016
New Revision: 306806
URL: https://svnweb.freebsd.org/changeset/base/306806

Log:
  Improvements to BSD-licensed DTC.
  
  - Numerous crash and bug fixes
  - Improved warning and error messages
  - Permit multiple labels on nodes and properties
  - Fix node@address references
  - Add support for /delete-node/
  - Consume whitespace after a node
  - Read the next token before the second /memreserve/
  - Fix parsing of whitespace
  - Clean up /delete-node/ and add support for /delete-property/
  - Handle /delete-node/ specifying a unit address
  
  Obtained from:	https://github.com/davidchisnall/dtc @df5ede4

Modified:
  head/usr.bin/dtc/checking.cc
  head/usr.bin/dtc/checking.hh
  head/usr.bin/dtc/dtb.cc
  head/usr.bin/dtc/dtb.hh
  head/usr.bin/dtc/dtc.1
  head/usr.bin/dtc/dtc.cc
  head/usr.bin/dtc/fdt.cc
  head/usr.bin/dtc/fdt.hh
  head/usr.bin/dtc/input_buffer.cc
  head/usr.bin/dtc/input_buffer.hh
  head/usr.bin/dtc/string.cc
  head/usr.bin/dtc/util.hh

Modified: head/usr.bin/dtc/checking.cc
==============================================================================
--- head/usr.bin/dtc/checking.cc	Fri Oct  7 11:50:59 2016	(r306805)
+++ head/usr.bin/dtc/checking.cc	Fri Oct  7 12:57:35 2016	(r306806)
@@ -33,7 +33,7 @@
 #include "checking.hh"
 #include <stdio.h>
 
-
+using std::string;
 
 namespace dtc
 {
@@ -44,6 +44,30 @@ namespace checking
 
 namespace
 {
+	struct deleted_node_checker : public checker
+	{
+		deleted_node_checker(const char *name) : checker(name) {}
+		virtual bool check_node(device_tree *, const node_ptr &n)
+		{
+			auto &deleted = n->deleted_child_nodes();
+			if (deleted.empty())
+			{
+				return true;
+			}
+			bool plural = deleted.size() > 1;
+			string errmsg("Attempts to delete ");
+			errmsg += plural ? "nodes" : "node";
+			errmsg += " that ";
+			errmsg += plural ? "were" : "was";
+			errmsg += " not added in merge: ";
+			for (auto &d : deleted)
+			{
+				errmsg += d;
+			}
+			report_error(errmsg.c_str());
+			return false;
+		}
+	};
 	/**
 	 * Checker that verifies that every node that has children has
 	 * #address-cells and #size-cells properties.
@@ -73,16 +97,16 @@ namespace
 				}
 				if (found_size && found_address)
 				{
-						break;
+					break;
 				}
 			}
 			if (!found_address)
 			{
-					report_error("Missing #address-cells property");
+				report_error("Missing #address-cells property");
 			}
 			if (!found_size)
 			{
-					report_error("Missing #size-cells property");
+				report_error("Missing #size-cells property");
 			}
 			return found_address && found_size;
 		}
@@ -126,11 +150,11 @@ checker::report_error(const char *errmsg
 	for (auto &p : path)
 	{
 		putc('/', stderr);
-		p.first.dump();
+		puts(p.first.c_str());
 		if (!(p.second.empty()))
 		{
 			putc('@', stderr);
-			p.second.dump();
+			puts(p.second.c_str());
 		}
 	}
 	fprintf(stderr, " [-W%s]\n", checker_name);
@@ -167,7 +191,7 @@ property_size_checker::check(device_tree
 
 template<property_value::value_type T>
 void
-check_manager::add_property_type_checker(const char *name, string prop)
+check_manager::add_property_type_checker(const char *name, const string &prop)
 {
 	checkers.insert(std::make_pair(string(name),
 		new property_type_checker<T>(name, prop)));
@@ -175,7 +199,7 @@ check_manager::add_property_type_checker
 
 void
 check_manager::add_property_size_checker(const char *name,
-                                         string prop,
+                                         const string &prop,
                                          uint32_t size)
 {
 	checkers.insert(std::make_pair(string(name),
@@ -207,6 +231,8 @@ check_manager::check_manager()
 	add_property_size_checker("type-phandle", string("phandle"), 4);
 	disabled_checkers.insert(std::make_pair(string("cells-attributes"),
 		new address_cells_checker("cells-attributes")));
+	checkers.insert(std::make_pair(string("deleted-nodes"),
+		new deleted_node_checker("deleted-nodes")));
 }
 
 bool
@@ -225,7 +251,7 @@ check_manager::run_checks(device_tree *t
 }
 
 bool
-check_manager::disable_checker(string name)
+check_manager::disable_checker(const string &name)
 {
 	auto checker = checkers.find(name);
 	if (checker != checkers.end())
@@ -239,7 +265,7 @@ check_manager::disable_checker(string na
 }
 
 bool
-check_manager::enable_checker(string name)
+check_manager::enable_checker(const string &name)
 {
 	auto checker = disabled_checkers.find(name);
 	if (checker != disabled_checkers.end())

Modified: head/usr.bin/dtc/checking.hh
==============================================================================
--- head/usr.bin/dtc/checking.hh	Fri Oct  7 11:50:59 2016	(r306805)
+++ head/usr.bin/dtc/checking.hh	Fri Oct  7 12:57:35 2016	(r306806)
@@ -32,7 +32,7 @@
 
 #ifndef _CHECKING_HH_
 #define _CHECKING_HH_
-#include "string.hh"
+#include <string>
 #include "fdt.hh"
 
 namespace dtc
@@ -58,7 +58,7 @@ class checker
 	/**
 	 * The name of the checker.  This is used for printing error messages
 	 * and for enabling / disabling specific checkers from the command
-	 * line. 
+	 * line.
 	 */
 	const char *checker_name;
 	/**
@@ -118,18 +118,18 @@ class property_checker : public checker
 	/**
 	 * The name of the property that this checker is looking for.
 	 */
-	string key;
+	std::string key;
 	public:
 	/**
 	 * Implementation of the generic property-checking method that checks
-	 * for a property with the name specified in the constructor 
+	 * for a property with the name specified in the constructor.
 	 */
 	virtual bool check_property(device_tree *tree, const node_ptr &n, property_ptr p);
 	/**
 	 * Constructor.  Takes the name of the checker and the name of the
 	 * property to check.
 	 */
-	property_checker(const char* name, string property_name)
+	property_checker(const char* name, const std::string &property_name)
 		: checker(name), key(property_name) {}
 	/**
 	 * The check method, which subclasses should implement.
@@ -147,7 +147,7 @@ struct property_type_checker : public pr
 	 * Constructor, takes the name of the checker and the name of the
 	 * property to check as arguments.
 	 */
-	property_type_checker(const char* name, string property_name) : 
+	property_type_checker(const char* name, const std::string &property_name) :
 		property_checker(name, property_name) {}
 	virtual bool check(device_tree *tree, const node_ptr &n, property_ptr p) = 0;
 };
@@ -158,7 +158,7 @@ struct property_type_checker : public pr
 template<>
 struct property_type_checker <property_value::EMPTY> : public property_checker
 {
-	property_type_checker(const char* name, string property_name) : 
+	property_type_checker(const char* name, const std::string &property_name) :
 		property_checker(name, property_name) {}
 	virtual bool check(device_tree *, const node_ptr &, property_ptr p)
 	{
@@ -173,7 +173,7 @@ struct property_type_checker <property_v
 template<>
 struct property_type_checker <property_value::STRING> : public property_checker
 {
-	property_type_checker(const char* name, string property_name) : 
+	property_type_checker(const char* name, const std::string &property_name) :
 		property_checker(name, property_name) {}
 	virtual bool check(device_tree *, const node_ptr &, property_ptr p)
 	{
@@ -188,7 +188,7 @@ template<>
 struct property_type_checker <property_value::STRING_LIST> :
 	public property_checker
 {
-	property_type_checker(const char* name, string property_name) : 
+	property_type_checker(const char* name, const std::string &property_name) :
 		property_checker(name, property_name) {}
 	virtual bool check(device_tree *, const node_ptr &, property_ptr p)
 	{
@@ -211,11 +211,11 @@ struct property_type_checker <property_v
 template<>
 struct property_type_checker <property_value::PHANDLE> : public property_checker
 {
-	property_type_checker(const char* name, string property_name) : 
+	property_type_checker(const char* name, const std::string &property_name) :
 		property_checker(name, property_name) {}
 	virtual bool check(device_tree *tree, const node_ptr &, property_ptr p)
 	{
-		return (p->begin() + 1 == p->end()) && 
+		return (p->begin() + 1 == p->end()) &&
 			(tree->referenced_node(*p->begin()) != 0);
 	}
 };
@@ -234,7 +234,9 @@ struct property_size_checker : public pr
 	 * Constructor, takes the name of the checker, the name of the property
 	 * to check, and its expected size as arguments.
 	 */
-	property_size_checker(const char* name, string property_name, uint32_t bytes)
+	property_size_checker(const char* name,
+	                      const std::string &property_name,
+	                      uint32_t bytes)
 		: property_checker(name, property_name), size(bytes) {}
 	/**
 	 * Check, validates that the property has the correct size.
@@ -254,26 +256,26 @@ class check_manager
 	 * disabling checkers from the command line.  When this manager runs,
 	 * it will only run the checkers from this map.
 	 */
-	std::unordered_map<string, checker*> checkers;
+	std::unordered_map<std::string, checker*> checkers;
 	/**
 	 * The disabled checkers.  Moving checkers to this list disables them,
 	 * but allows them to be easily moved back.
 	 */
-	std::unordered_map<string, checker*> disabled_checkers;
+	std::unordered_map<std::string, checker*> disabled_checkers;
 	/**
 	 * Helper function for adding a property value checker.
 	 */
 	template<property_value::value_type T>
-	void add_property_type_checker(const char *name, string prop);
+	void add_property_type_checker(const char *name, const std::string &prop);
 	/**
 	 * Helper function for adding a simple type checker.
 	 */
-	void add_property_type_checker(const char *name, string prop);
+	void add_property_type_checker(const char *name, const std::string &prop);
 	/**
 	 * Helper function for adding a property value checker.
 	 */
 	void add_property_size_checker(const char *name,
-	                               string prop,
+	                               const std::string &prop,
 	                               uint32_t size);
 	public:
 	/**
@@ -292,11 +294,11 @@ class check_manager
 	/**
 	 * Disables the named checker.
 	 */
-	bool disable_checker(string name);
+	bool disable_checker(const std::string &name);
 	/**
-	 * Enables the named checker.  
+	 * Enables the named checker.
 	 */
-	bool enable_checker(string name);
+	bool enable_checker(const std::string &name);
 };
 
 } // namespace checking

Modified: head/usr.bin/dtc/dtb.cc
==============================================================================
--- head/usr.bin/dtc/dtb.cc	Fri Oct  7 11:50:59 2016	(r306805)
+++ head/usr.bin/dtc/dtb.cc	Fri Oct  7 12:57:35 2016	(r306806)
@@ -36,6 +36,7 @@
 #include <stdio.h>
 #include <unistd.h>
 
+using std::string;
 
 namespace dtc
 {
@@ -51,9 +52,9 @@ void output_writer::write_data(byte_buff
 }
 
 void
-binary_writer::write_string(string name)
+binary_writer::write_string(const string &name)
 {
-	name.push_to_buffer(buffer);
+	push_string(buffer, name);
 	// Trailing nul
 	buffer.push_back(0);
 }
@@ -98,15 +99,6 @@ binary_writer::size()
 }
 
 void
-asm_writer::write_string(const char *c)
-{
-	while (*c)
-	{
-		buffer.push_back((uint8_t)*(c++));
-	}
-}
-
-void
 asm_writer::write_line(const char *c)
 {
 	if (byte_count != 0)
@@ -142,34 +134,44 @@ asm_writer::write_byte(uint8_t b)
 }
 
 void
-asm_writer::write_label(string name)
+asm_writer::write_label(const string &name)
 {
 	write_line("\t.globl ");
-	name.push_to_buffer(buffer);
+	push_string(buffer, name);
 	buffer.push_back('\n');
-	name.push_to_buffer(buffer);
+	push_string(buffer, name);
 	buffer.push_back(':');
 	buffer.push_back('\n');
 	buffer.push_back('_');
-	name.push_to_buffer(buffer);
+	push_string(buffer, name);
 	buffer.push_back(':');
 	buffer.push_back('\n');
 	
 }
 
 void
-asm_writer::write_comment(string name)
+asm_writer::write_comment(const string &name)
 {
 	write_line("\t/* ");
-	name.push_to_buffer(buffer);
+	push_string(buffer, name);
 	write_string(" */\n");
 }
 
 void
-asm_writer::write_string(string name)
+asm_writer::write_string(const char *c)
+{
+	while (*c)
+	{
+		buffer.push_back((uint8_t)*(c++));
+	}
+}
+
+
+void
+asm_writer::write_string(const string &name)
 {
 	write_line("\t.string \"");
-	name.push_to_buffer(buffer);
+	push_string(buffer, name);
 	write_line("\"\n");
 	bytes_written += name.size() + 1;
 }
@@ -231,8 +233,8 @@ asm_writer::size()
 void
 header::write(output_writer &out)
 {
-	out.write_label(string("dt_blob_start"));
-	out.write_label(string("dt_header"));
+	out.write_label("dt_blob_start");
+	out.write_label("dt_header");
 	out.write_comment("magic");
 	out.write_data(magic);
 	out.write_comment("totalsize");
@@ -275,7 +277,7 @@ header::read_dtb(input_buffer &input)
 	       input.consume_binary(size_dt_struct);
 }
 uint32_t
-string_table::add_string(string str)
+string_table::add_string(const string &str)
 {
 	auto old = string_offsets.find(str);
 	if (old == string_offsets.end())
@@ -296,13 +298,13 @@ string_table::add_string(string str)
 void
 string_table::write(dtb::output_writer &writer)
 {
-	writer.write_comment(string("Strings table."));
-	writer.write_label(string("dt_strings_start"));
+	writer.write_comment("Strings table.");
+	writer.write_label("dt_strings_start");
 	for (auto &i : strings)
 	{
 		writer.write_string(i);
 	}
-	writer.write_label(string("dt_strings_end"));
+	writer.write_label("dt_strings_end");
 }
 
 } // namespace dtb

Modified: head/usr.bin/dtc/dtb.hh
==============================================================================
--- head/usr.bin/dtc/dtb.hh	Fri Oct  7 11:50:59 2016	(r306805)
+++ head/usr.bin/dtc/dtb.hh	Fri Oct  7 12:57:35 2016	(r306806)
@@ -33,10 +33,13 @@
 #ifndef _DTB_HH_
 #define _DTB_HH_
 #include <map>
-#include "string.hh"
+#include <string>
 
 #include <assert.h>
 
+#include "input_buffer.hh"
+#include "util.hh"
+
 namespace dtc
 {
 /**
@@ -121,16 +124,16 @@ struct output_writer
 	 * assembly output, where the labels become symbols that can be
 	 * resolved at link time.
 	 */
-	virtual void write_label(string name)   = 0;
+	virtual void write_label(const std::string &name)   = 0;
 	/**
 	 * Writes a comment into the output stream.  Useful only when debugging
 	 * the output.
 	 */
-	virtual void write_comment(string name) = 0;
+	virtual void write_comment(const std::string &name) = 0;
 	/**
 	 * Writes a string.  A nul terminator is implicitly added.
 	 */
-	virtual void write_string(string name)  = 0;
+	virtual void write_string(const std::string &name)  = 0;
 	/**
 	 * Writes a single 8-bit value.
 	 */
@@ -186,12 +189,12 @@ class binary_writer : public output_writ
 	 *  The binary format does not support labels, so this method
 	 * does nothing.
 	 */
-	virtual void write_label(string) {}
+	virtual void write_label(const std::string &) {}
 	/**
 	 * Comments are ignored by the binary writer.
 	 */
-	virtual void write_comment(string) {}
-	virtual void write_string(string name);
+	virtual void write_comment(const std::string&) {}
+	virtual void write_string(const std::string &name);
 	virtual void write_data(uint8_t v);
 	virtual void write_data(uint32_t v);
 	virtual void write_data(uint64_t v);
@@ -224,11 +227,15 @@ class asm_writer : public output_writer
 	uint32_t bytes_written;
 
 	/**
-	 * Writes a C string directly to the output as-is.  This is mainly used
-	 * for writing directives.
+	 * Writes a string directly to the output as-is.  This is the function that
+	 * performs the real output.
 	 */
 	void write_string(const char *c);
 	/**
+	 * Write a string to the output.
+	 */
+	void write_string(const std::string &c);
+	/**
 	 * Writes the string, starting on a new line.  
 	 */
 	void write_line(const char *c);
@@ -239,9 +246,8 @@ class asm_writer : public output_writer
 	void write_byte(uint8_t b);
 	public:
 	asm_writer() : byte_count(0), bytes_written(0) {}
-	virtual void write_label(string name);
-	virtual void write_comment(string name);
-	virtual void write_string(string name);
+	virtual void write_label(const std::string &name);
+	virtual void write_comment(const std::string &name);
 	virtual void write_data(uint8_t v);
 	virtual void write_data(uint32_t v);
 	virtual void write_data(uint64_t v);
@@ -328,14 +334,14 @@ class string_table {
 	/**
 	 * Map from strings to their offset. 
 	 */
-	std::map<string, uint32_t> string_offsets;
+	std::map<std::string, uint32_t> string_offsets;
 	/**
 	 * The strings, in the order in which they should be written to the
 	 * output.  The order must be stable - adding another string must not
 	 * change the offset of any that we have already referenced - and so we
 	 * simply write the strings in the order that they are passed.
 	 */
-	std::vector<string> strings;
+	std::vector<std::string> strings;
 	/**
 	 * The current size of the strings section.
 	 */
@@ -351,7 +357,7 @@ class string_table {
 	 * will return its existing offset, otherwise it will return a new
 	 * offset.
 	 */
-	uint32_t add_string(string str);
+	uint32_t add_string(const std::string &str);
 	/**
 	 * Writes the strings table to the specified output.
 	 */

Modified: head/usr.bin/dtc/dtc.1
==============================================================================
--- head/usr.bin/dtc/dtc.1	Fri Oct  7 11:50:59 2016	(r306805)
+++ head/usr.bin/dtc/dtc.1	Fri Oct  7 12:57:35 2016	(r306806)
@@ -237,6 +237,10 @@ Checks that all nodes with children have
 and
 .Va #size-cells
 properties.
+.It deleted-nodes
+Checks that all
+.Va /delete-node/
+statements refer to nodes that are merged.
 .El
 .Sh EXAMPLES
 The command:

Modified: head/usr.bin/dtc/dtc.cc
==============================================================================
--- head/usr.bin/dtc/dtc.cc	Fri Oct  7 11:50:59 2016	(r306805)
+++ head/usr.bin/dtc/dtc.cc	Fri Oct  7 12:57:35 2016	(r306806)
@@ -42,8 +42,10 @@
 
 #include "fdt.hh"
 #include "checking.hh"
+#include "util.hh"
 
 using namespace dtc;
+using std::string;
 
 /**
  * The current major version of the tool.
@@ -58,7 +60,7 @@ int version_minor = 4;
  */
 int version_patch = 0;
 
-static void usage(const char* argv0)
+static void usage(const string &argv0)
 {
 	fprintf(stderr, "Usage:\n"
 		"\t%s\t[-fhsv] [-b boot_cpu_id] [-d dependency_file]"
@@ -67,7 +69,7 @@ static void usage(const char* argv0)
 			"[-O output_format]\n"
 		"\t\t[-o output_file] [-R entries] [-S bytes] [-p bytes]"
 			"[-V blob_version]\n"
-		"\t\t-W [no-]checker_name] input_file\n", basename((char*)argv0));
+		"\t\t-W [no-]checker_name] input_file\n", basename(argv0).c_str());
 }
 
 /**
@@ -90,9 +92,8 @@ main(int argc, char **argv)
 	const char *in_file = "-";
 	FILE *depfile = 0;
 	bool debug_mode = false;
-	void (device_tree::*write_fn)(int) = &device_tree::write_binary;
-	void (device_tree::*read_fn)(const char*, FILE*) =
-		&device_tree::parse_dts;
+	auto write_fn = &device_tree::write_binary;
+	auto read_fn = &device_tree::parse_dts;
 	uint32_t boot_cpu;
 	bool boot_cpu_specified = false;
 	bool keep_going = false;
@@ -115,12 +116,12 @@ main(int argc, char **argv)
 			return EXIT_SUCCESS;
 		case 'I':
 		{
-			string arg = string(optarg);
-			if (arg == string("dtb"))
+			string arg(optarg);
+			if (arg == "dtb")
 			{
 				read_fn = &device_tree::parse_dtb;
 			}
-			else if (arg == string("dts"))
+			else if (arg == "dts")
 			{
 				read_fn = &device_tree::parse_dts;
 			}
@@ -133,16 +134,16 @@ main(int argc, char **argv)
 		}
 		case 'O':
 		{
-			string arg = string(optarg);
-			if (arg == string("dtb"))
+			string arg(optarg);
+			if (arg == "dtb")
 			{
 				write_fn = &device_tree::write_binary;
 			}
-			else if (arg == string("asm"))
+			else if (arg == "asm")
 			{
 				write_fn = &device_tree::write_asm;
 			}
-			else if (arg == string("dts"))
+			else if (arg == "dts")
 			{
 				write_fn = &device_tree::write_dts;
 			}
@@ -168,7 +169,7 @@ main(int argc, char **argv)
 			debug_mode = true;
 			break;
 		case 'V':
-			if (string(optarg) != string("17"))
+			if (string(optarg) != "17")
 			{
 				fprintf(stderr, "Unknown output format version: %s\n", optarg);
 				return EXIT_FAILURE;
@@ -180,7 +181,7 @@ main(int argc, char **argv)
 			{
 				fclose(depfile);
 			}
-			if (string(optarg) == string("-"))
+			if (string(optarg) == "-")
 			{
 				depfile = stdout;
 			}
@@ -197,16 +198,16 @@ main(int argc, char **argv)
 		}
 		case 'H':
 		{
-			string arg = string(optarg);
-			if (arg == string("both"))
+			string arg(optarg);
+			if (arg == "both")
 			{
 				tree.set_phandle_format(device_tree::BOTH);
 			}
-			else if (arg == string("epapr"))
+			else if (arg == "epapr")
 			{
 				tree.set_phandle_format(device_tree::EPAPR);
 			}
-			else if (arg == string("linux"))
+			else if (arg == "linux")
 			{
 				tree.set_phandle_format(device_tree::LINUX);
 			}
@@ -229,7 +230,7 @@ main(int argc, char **argv)
 		case 'W':
 		case 'E':
 		{
-			string arg = string(optarg);
+			string arg(optarg);
 			if ((arg.size() > 3) && (strncmp(optarg, "no-", 3) == 0))
 			{
 				arg = string(optarg+3);
@@ -307,7 +308,7 @@ main(int argc, char **argv)
 	}
 	if (!(tree.is_valid() || keep_going))
 	{
-		fprintf(stderr, "Failed to parse tree.  Unhappy face!\n");
+		fprintf(stderr, "Failed to parse tree.\n");
 		return EXIT_FAILURE;
 	}
 	clock_t c2 = clock();

Modified: head/usr.bin/dtc/fdt.cc
==============================================================================
--- head/usr.bin/dtc/fdt.cc	Fri Oct  7 11:50:59 2016	(r306805)
+++ head/usr.bin/dtc/fdt.cc	Fri Oct  7 12:57:35 2016	(r306806)
@@ -36,6 +36,7 @@
 #include "dtb.hh"
 
 #include <algorithm>
+#include <sstream>
 
 #include <ctype.h>
 #include <fcntl.h>
@@ -48,6 +49,8 @@
 #include <sys/stat.h>
 #include <errno.h>
 
+using std::string;
+
 namespace dtc
 {
 
@@ -78,7 +81,7 @@ property_value::push_to_buffer(byte_buff
 	}
 	else
 	{
-		string_data.push_to_buffer(buffer, true);
+		push_string(buffer, string_data, true);
 		// Trailing nul
 		buffer.push_back(0);
 	}
@@ -172,7 +175,7 @@ property_value::write_as_string(FILE *fi
 	putc('"', file);
 	if (byte_data.empty())
 	{
-		string_data.print(file);
+		fputs(string_data.c_str(), file);
 	}
 	else
 	{
@@ -240,31 +243,32 @@ property_value::write_as_bytes(FILE *fil
 }
 
 void
-property::parse_string(input_buffer &input)
+property::parse_string(text_input_buffer &input)
 {
 	property_value v;
-	assert(input[0] == '"');
+	assert(*input == '"');
 	++input;
-	const char *start = (const char*)input;
-	int length = 0;
-	while (char c = input[0])
+	std::vector<char> bytes;
+	bool isEscaped = false;
+	while (char c = *input)
 	{
-		if (c == '"' && input[-1] != '\\')
+		if (c == '"' && !isEscaped)
 		{
 			input.consume('"');
 			break;
 		}
+		isEscaped = (c == '\\');
+		bytes.push_back(c);
 		++input;
-		++length;
 	}
-	v.string_data = string(start, length);
+	v.string_data = string(bytes.begin(), bytes.end());
 	values.push_back(v);
 }
 
 void
-property::parse_cells(input_buffer &input, int cell_size)
+property::parse_cells(text_input_buffer &input, int cell_size)
 {
-	assert(input[0] == '<');
+	assert(*input == '<');
 	++input;
 	property_value v;
 	input.next_token();
@@ -282,9 +286,18 @@ property::parse_cells(input_buffer &inpu
 				return;
 			}
 			input.next_token();
-			// FIXME: We should support full paths here, but we
-			// don't.
-			string referenced = string::parse_node_name(input);
+			bool isPath = false;
+			string referenced;
+			if (!input.consume('{'))
+			{
+				referenced = input.parse_node_name();
+			}
+			else
+			{
+				referenced = input.parse_to('}');
+				input.consume('}');
+				isPath = true;
+			}
 			if (referenced.empty())
 			{
 				input.parse_error("Expected node name");
@@ -343,9 +356,9 @@ property::parse_cells(input_buffer &inpu
 }
 
 void
-property::parse_bytes(input_buffer &input)
+property::parse_bytes(text_input_buffer &input)
 {
-	assert(input[0] == '[');
+	assert(*input == '[');
 	++input;
 	property_value v;
 	input.next_token();
@@ -370,13 +383,13 @@ property::parse_bytes(input_buffer &inpu
 }
 
 void
-property::parse_reference(input_buffer &input)
+property::parse_reference(text_input_buffer &input)
 {
-	assert(input[0] == '&');
+	assert(*input == '&');
 	++input;
 	input.next_token();
 	property_value v;
-	v.string_data = string::parse_node_name(input);
+	v.string_data = input.parse_node_name();
 	if (v.string_data.empty())
 	{
 		input.parse_error("Expected node name");
@@ -400,7 +413,7 @@ property::property(input_buffer &structs
 	}
 	// Find the name
 	input_buffer name_buffer = strings.buffer_from_offset(name_offset);
-	if (name_buffer.empty())
+	if (name_buffer.finished())
 	{
 		fprintf(stderr, "Property name offset %" PRIu32
 			" is past the end of the strings table\n",
@@ -408,7 +421,7 @@ property::property(input_buffer &structs
 		valid = false;
 		return;
 	}
-	key = string(name_buffer);
+	key = name_buffer.parse_to(0);
 
 	// If we're empty, do not push anything as value.
 	if (!length)
@@ -429,7 +442,7 @@ property::property(input_buffer &structs
 	values.push_back(v);
 }
 
-void property::parse_define(input_buffer &input, define_map *defines)
+void property::parse_define(text_input_buffer &input, define_map *defines)
 {
 	input.consume('$');
 	if (!defines)
@@ -438,7 +451,7 @@ void property::parse_define(input_buffer
 		valid = false;
 		return;
 	}
-	string name = string::parse_property_name(input);
+	string name = input.parse_property_name();
 	define_map::iterator found;
 	if ((name == string()) ||
 	    ((found = defines->find(name)) == defines->end()))
@@ -450,15 +463,15 @@ void property::parse_define(input_buffer
 	values.push_back((*found).second->values[0]);
 }
 
-property::property(input_buffer &input,
-                   string k,
-                   string l,
+property::property(text_input_buffer &input,
+                   string &&k,
+                   string_set &&l,
                    bool semicolonTerminated,
-                   define_map *defines) : key(k), label(l), valid(true)
+                   define_map *defines) : key(k), labels(l), valid(true)
 {
 	do {
 		input.next_token();
-		switch (input[0])
+		switch (*input)
 		{
 			case '$':
 			{
@@ -487,7 +500,7 @@ property::property(input_buffer &input,
 				}
 				if (!valid) return;
 				input.next_token();
-				if (input[0] != '<')
+				if (*input != '<')
 				{
 					input.parse_error("/bits/ directive is only valid on arrays");
 					valid = false;
@@ -534,10 +547,14 @@ property::parse_dtb(input_buffer &struct
 }
 
 property_ptr
-property::parse(input_buffer &input, string key, string label,
+property::parse(text_input_buffer &input, string &&key, string_set &&label,
                 bool semicolonTerminated, define_map *defines)
 {
-	property_ptr p(new property(input, key, label, semicolonTerminated, defines));
+	property_ptr p(new property(input,
+	                            std::move(key),
+	                            std::move(label),
+	                            semicolonTerminated,
+	                            defines));
 	if (!p->valid)
 	{
 		p = nullptr;
@@ -596,14 +613,16 @@ property::write_dts(FILE *file, int inde
 	{
 		putc('\t', file);
 	}
-	if (label != string())
+#ifdef PRINT_LABELS
+	for (auto &l : labels)
 	{
-		label.print(file);
+		fputs(l.c_str(), file);
 		fputs(": ", file);
 	}
+#endif
 	if (key != string())
 	{
-		key.print(file);
+		fputs(key.c_str(), file);
 	}
 	if (!values.empty())
 	{
@@ -637,7 +656,7 @@ property::write_dts(FILE *file, int inde
 }
 
 string
-node::parse_name(input_buffer &input, bool &is_property, const char *error)
+node::parse_name(text_input_buffer &input, bool &is_property, const char *error)
 {
 	if (!valid)
 	{
@@ -646,9 +665,9 @@ node::parse_name(input_buffer &input, bo
 	input.next_token();
 	if (is_property)
 	{
-		return string::parse_property_name(input);
+		return input.parse_property_name();
 	}
-	string n = string::parse_node_or_property_name(input, is_property);
+	string n = input.parse_node_or_property_name(is_property);
 	if (n.empty())
 	{
 		if (n.empty())
@@ -672,25 +691,23 @@ node::visit(std::function<void(node&)> f
 
 node::node(input_buffer &structs, input_buffer &strings) : valid(true)
 {
-	const char *name_start = (const char*)structs;
-	int name_length = 0;
+	std::vector<char> bytes;
 	while (structs[0] != '\0' && structs[0] != '@')
 	{
-		name_length++;
+		bytes.push_back(structs[0]);
 		++structs;
 	}
-	name = string(name_start, name_length);
+	name = string(bytes.begin(), bytes.end());
+	bytes.clear();
 	if (structs[0] == '@')
 	{
 		++structs;
-		name_start = (const char*)structs;
-		name_length = 0;
 		while (structs[0] != '\0')
 		{
-			name_length++;
+			bytes.push_back(structs[0]);
 			++structs;
 		}
-		unit_address = string(name_start, name_length);
+		unit_address = string(bytes.begin(), bytes.end());
 	}
 	++structs;
 	uint32_t token;
@@ -747,8 +764,12 @@ node::node(input_buffer &structs, input_
 	return;
 }
 
-node::node(input_buffer &input, string n, string l, string a, define_map *defines) : 
-	label(l), name(n), unit_address(a), valid(true)
+node::node(text_input_buffer &input,
+           string &&n,
+           std::unordered_set<string> &&l,
+           string &&a,
+           define_map *defines)
+	: labels(l), name(n), unit_address(a), valid(true)
 {
 	if (!input.consume('{'))
 	{
@@ -760,15 +781,60 @@ node::node(input_buffer &input, string n
 		// flag set if we find any characters that are only in
 		// the property name character set, not the node 
 		bool is_property = false;
-		string child_name, child_label, child_address;
+		string child_name, child_address;
+		std::unordered_set<string> child_labels;
+		auto parse_delete = [&](const char *expected, bool at)
+		{
+			if (child_name == string())
+			{
+				input.parse_error(expected);
+				valid = false;
+				return;
+			}
+			input.next_token();
+			if (at && input.consume('@'))
+			{
+				child_name += '@';
+				child_name += parse_name(input, is_property, "Expected unit address");
+			}
+			if (!input.consume(';'))
+			{
+				input.parse_error("Expected semicolon");
+				valid = false;
+				return;
+			}
+			input.next_token();
+		};
+		if (input.consume("/delete-node/"))
+		{
+			input.next_token();
+			child_name = input.parse_node_name();
+			parse_delete("Expected node name", true);
+			if (valid)
+			{
+				deleted_children.insert(child_name);
+			}
+			continue;
+		}

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201610071257.u97CvZ3V029734>