Commit 658f29a5 authored by John Bonesio's avatar John Bonesio Committed by Grant Likely

of/flattree: Update dtc to current mainline.

Pull in recent changes from the main dtc repository. These changes
primarily allow multiple device trees to be declared which are merged
by dtc. This feature allows us to include a basic dts file and then
provide more information for the specific system through the merging
functionality.

Changes pulled from git://git.jdl.com/software/dtc.git
commit id: 37c0b6a0, "dtc: Add code to make diffing trees easier"
Signed-off-by: default avatarJohn Bonesio <bones@secretlab.ca>
Signed-off-by: default avatarGrant Likely <grant.likely@secretlab.ca>
parent cd1e6504
...@@ -4,7 +4,7 @@ hostprogs-y := dtc ...@@ -4,7 +4,7 @@ hostprogs-y := dtc
always := $(hostprogs-y) always := $(hostprogs-y)
dtc-objs := dtc.o flattree.o fstree.o data.o livetree.o treesource.o \ dtc-objs := dtc.o flattree.o fstree.o data.o livetree.o treesource.o \
srcpos.o checks.o srcpos.o checks.o util.o
dtc-objs += dtc-lexer.lex.o dtc-parser.tab.o dtc-objs += dtc-lexer.lex.o dtc-parser.tab.o
# Source files need to get at the userspace version of libfdt_env.h to compile # Source files need to get at the userspace version of libfdt_env.h to compile
...@@ -19,6 +19,7 @@ HOSTCFLAGS_fstree.o := $(HOSTCFLAGS_DTC) ...@@ -19,6 +19,7 @@ HOSTCFLAGS_fstree.o := $(HOSTCFLAGS_DTC)
HOSTCFLAGS_livetree.o := $(HOSTCFLAGS_DTC) HOSTCFLAGS_livetree.o := $(HOSTCFLAGS_DTC)
HOSTCFLAGS_srcpos.o := $(HOSTCFLAGS_DTC) HOSTCFLAGS_srcpos.o := $(HOSTCFLAGS_DTC)
HOSTCFLAGS_treesource.o := $(HOSTCFLAGS_DTC) HOSTCFLAGS_treesource.o := $(HOSTCFLAGS_DTC)
HOSTCFLAGS_util.o := $(HOSTCFLAGS_DTC)
HOSTCFLAGS_dtc-lexer.lex.o := $(HOSTCFLAGS_DTC) HOSTCFLAGS_dtc-lexer.lex.o := $(HOSTCFLAGS_DTC)
HOSTCFLAGS_dtc-parser.tab.o := $(HOSTCFLAGS_DTC) HOSTCFLAGS_dtc-parser.tab.o := $(HOSTCFLAGS_DTC)
......
...@@ -278,32 +278,112 @@ static void check_property_name_chars(struct check *c, struct node *dt, ...@@ -278,32 +278,112 @@ static void check_property_name_chars(struct check *c, struct node *dt,
} }
PROP_CHECK(property_name_chars, PROPNODECHARS, ERROR); PROP_CHECK(property_name_chars, PROPNODECHARS, ERROR);
#define DESCLABEL_FMT "%s%s%s%s%s"
#define DESCLABEL_ARGS(node,prop,mark) \
((mark) ? "value of " : ""), \
((prop) ? "'" : ""), \
((prop) ? (prop)->name : ""), \
((prop) ? "' in " : ""), (node)->fullpath
static void check_duplicate_label(struct check *c, struct node *dt,
const char *label, struct node *node,
struct property *prop, struct marker *mark)
{
struct node *othernode = NULL;
struct property *otherprop = NULL;
struct marker *othermark = NULL;
othernode = get_node_by_label(dt, label);
if (!othernode)
otherprop = get_property_by_label(dt, label, &othernode);
if (!othernode)
othermark = get_marker_label(dt, label, &othernode,
&otherprop);
if (!othernode)
return;
if ((othernode != node) || (otherprop != prop) || (othermark != mark))
FAIL(c, "Duplicate label '%s' on " DESCLABEL_FMT
" and " DESCLABEL_FMT,
label, DESCLABEL_ARGS(node, prop, mark),
DESCLABEL_ARGS(othernode, otherprop, othermark));
}
static void check_duplicate_label_node(struct check *c, struct node *dt,
struct node *node)
{
struct label *l;
for_each_label(node->labels, l)
check_duplicate_label(c, dt, l->label, node, NULL, NULL);
}
static void check_duplicate_label_prop(struct check *c, struct node *dt,
struct node *node, struct property *prop)
{
struct marker *m = prop->val.markers;
struct label *l;
for_each_label(prop->labels, l)
check_duplicate_label(c, dt, l->label, node, prop, NULL);
for_each_marker_of_type(m, LABEL)
check_duplicate_label(c, dt, m->ref, node, prop, m);
}
CHECK(duplicate_label, NULL, check_duplicate_label_node,
check_duplicate_label_prop, NULL, ERROR);
static void check_explicit_phandles(struct check *c, struct node *root, static void check_explicit_phandles(struct check *c, struct node *root,
struct node *node) struct node *node, struct property *prop)
{ {
struct property *prop; struct marker *m;
struct node *other; struct node *other;
cell_t phandle; cell_t phandle;
prop = get_property(node, "linux,phandle"); if (!streq(prop->name, "phandle")
if (! prop) && !streq(prop->name, "linux,phandle"))
return; /* No phandle, that's fine */ return;
if (prop->val.len != sizeof(cell_t)) { if (prop->val.len != sizeof(cell_t)) {
FAIL(c, "%s has bad length (%d) linux,phandle property", FAIL(c, "%s has bad length (%d) %s property",
node->fullpath, prop->val.len); node->fullpath, prop->val.len, prop->name);
return;
}
m = prop->val.markers;
for_each_marker_of_type(m, REF_PHANDLE) {
assert(m->offset == 0);
if (node != get_node_by_ref(root, m->ref))
/* "Set this node's phandle equal to some
* other node's phandle". That's nonsensical
* by construction. */ {
FAIL(c, "%s in %s is a reference to another node",
prop->name, node->fullpath);
return;
}
/* But setting this node's phandle equal to its own
* phandle is allowed - that means allocate a unique
* phandle for this node, even if it's not otherwise
* referenced. The value will be filled in later, so
* no further checking for now. */
return; return;
} }
phandle = propval_cell(prop); phandle = propval_cell(prop);
if ((phandle == 0) || (phandle == -1)) { if ((phandle == 0) || (phandle == -1)) {
FAIL(c, "%s has invalid linux,phandle value 0x%x", FAIL(c, "%s has bad value (0x%x) in %s property",
node->fullpath, phandle); node->fullpath, phandle, prop->name);
return; return;
} }
if (node->phandle && (node->phandle != phandle))
FAIL(c, "%s has %s property which replaces existing phandle information",
node->fullpath, prop->name);
other = get_node_by_phandle(root, phandle); other = get_node_by_phandle(root, phandle);
if (other) { if (other && (other != node)) {
FAIL(c, "%s has duplicated phandle 0x%x (seen before at %s)", FAIL(c, "%s has duplicated phandle 0x%x (seen before at %s)",
node->fullpath, phandle, other->fullpath); node->fullpath, phandle, other->fullpath);
return; return;
...@@ -311,7 +391,7 @@ static void check_explicit_phandles(struct check *c, struct node *root, ...@@ -311,7 +391,7 @@ static void check_explicit_phandles(struct check *c, struct node *root,
node->phandle = phandle; node->phandle = phandle;
} }
NODE_CHECK(explicit_phandles, NULL, ERROR); PROP_CHECK(explicit_phandles, NULL, ERROR);
static void check_name_properties(struct check *c, struct node *root, static void check_name_properties(struct check *c, struct node *root,
struct node *node) struct node *node)
...@@ -549,6 +629,9 @@ static struct check *check_table[] = { ...@@ -549,6 +629,9 @@ static struct check *check_table[] = {
&duplicate_node_names, &duplicate_property_names, &duplicate_node_names, &duplicate_property_names,
&node_name_chars, &node_name_format, &property_name_chars, &node_name_chars, &node_name_format, &property_name_chars,
&name_is_string, &name_properties, &name_is_string, &name_properties,
&duplicate_label,
&explicit_phandles, &explicit_phandles,
&phandle_references, &path_references, &phandle_references, &path_references,
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
* USA * USA
*/ */
%option noyywrap noinput nounput yylineno %option noyywrap nounput noinput never-interactive
%x INCLUDE %x INCLUDE
%x BYTESTRING %x BYTESTRING
...@@ -38,6 +38,13 @@ LINECOMMENT "//".*\n ...@@ -38,6 +38,13 @@ LINECOMMENT "//".*\n
#include "srcpos.h" #include "srcpos.h"
#include "dtc-parser.tab.h" #include "dtc-parser.tab.h"
YYLTYPE yylloc;
/* CAUTION: this will stop working if we ever use yyless() or yyunput() */
#define YY_USER_ACTION \
{ \
srcpos_update(&yylloc, yytext, yyleng); \
}
/*#define LEXDEBUG 1*/ /*#define LEXDEBUG 1*/
...@@ -47,15 +54,10 @@ LINECOMMENT "//".*\n ...@@ -47,15 +54,10 @@ LINECOMMENT "//".*\n
#define DPRINT(fmt, ...) do { } while (0) #define DPRINT(fmt, ...) do { } while (0)
#endif #endif
static int dts_version; /* = 0 */ static int dts_version = 1;
#define BEGIN_DEFAULT() if (dts_version == 0) { \ #define BEGIN_DEFAULT() DPRINT("<V1>\n"); \
DPRINT("<INITIAL>\n"); \
BEGIN(INITIAL); \
} else { \
DPRINT("<V1>\n"); \
BEGIN(V1); \ BEGIN(V1); \
}
static void push_input_file(const char *filename); static void push_input_file(const char *filename);
static int pop_input_file(void); static int pop_input_file(void);
...@@ -75,18 +77,13 @@ static int pop_input_file(void); ...@@ -75,18 +77,13 @@ static int pop_input_file(void);
} }
<*>{STRING} { <*>{STRING} {
yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
DPRINT("String: %s\n", yytext); DPRINT("String: %s\n", yytext);
yylval.data = data_copy_escape_string(yytext+1, yylval.data = data_copy_escape_string(yytext+1,
yyleng-2); yyleng-2);
yylloc.first_line = yylineno;
return DT_STRING; return DT_STRING;
} }
<*>"/dts-v1/" { <*>"/dts-v1/" {
yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
DPRINT("Keyword: /dts-v1/\n"); DPRINT("Keyword: /dts-v1/\n");
dts_version = 1; dts_version = 1;
BEGIN_DEFAULT(); BEGIN_DEFAULT();
...@@ -94,106 +91,57 @@ static int pop_input_file(void); ...@@ -94,106 +91,57 @@ static int pop_input_file(void);
} }
<*>"/memreserve/" { <*>"/memreserve/" {
yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
DPRINT("Keyword: /memreserve/\n"); DPRINT("Keyword: /memreserve/\n");
BEGIN_DEFAULT(); BEGIN_DEFAULT();
return DT_MEMRESERVE; return DT_MEMRESERVE;
} }
<*>{LABEL}: { <*>{LABEL}: {
yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
DPRINT("Label: %s\n", yytext); DPRINT("Label: %s\n", yytext);
yylval.labelref = strdup(yytext); yylval.labelref = xstrdup(yytext);
yylval.labelref[yyleng-1] = '\0'; yylval.labelref[yyleng-1] = '\0';
return DT_LABEL; return DT_LABEL;
} }
<INITIAL>[bodh]# {
yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
if (*yytext == 'b')
yylval.cbase = 2;
else if (*yytext == 'o')
yylval.cbase = 8;
else if (*yytext == 'd')
yylval.cbase = 10;
else
yylval.cbase = 16;
DPRINT("Base: %d\n", yylval.cbase);
return DT_BASE;
}
<INITIAL>[0-9a-fA-F]+ {
yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
yylval.literal = strdup(yytext);
DPRINT("Literal: '%s'\n", yylval.literal);
return DT_LEGACYLITERAL;
}
<V1>[0-9]+|0[xX][0-9a-fA-F]+ { <V1>[0-9]+|0[xX][0-9a-fA-F]+ {
yylloc.file = srcpos_file; yylval.literal = xstrdup(yytext);
yylloc.first_line = yylineno;
yylval.literal = strdup(yytext);
DPRINT("Literal: '%s'\n", yylval.literal); DPRINT("Literal: '%s'\n", yylval.literal);
return DT_LITERAL; return DT_LITERAL;
} }
\&{LABEL} { /* label reference */ <*>\&{LABEL} { /* label reference */
yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
DPRINT("Ref: %s\n", yytext+1); DPRINT("Ref: %s\n", yytext+1);
yylval.labelref = strdup(yytext+1); yylval.labelref = xstrdup(yytext+1);
return DT_REF; return DT_REF;
} }
"&{/"{PATHCHAR}+\} { /* new-style path reference */ <*>"&{/"{PATHCHAR}+\} { /* new-style path reference */
yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
yytext[yyleng-1] = '\0'; yytext[yyleng-1] = '\0';
DPRINT("Ref: %s\n", yytext+2); DPRINT("Ref: %s\n", yytext+2);
yylval.labelref = strdup(yytext+2); yylval.labelref = xstrdup(yytext+2);
return DT_REF;
}
<INITIAL>"&/"{PATHCHAR}+ { /* old-style path reference */
yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
DPRINT("Ref: %s\n", yytext+1);
yylval.labelref = strdup(yytext+1);
return DT_REF; return DT_REF;
} }
<BYTESTRING>[0-9a-fA-F]{2} { <BYTESTRING>[0-9a-fA-F]{2} {
yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
yylval.byte = strtol(yytext, NULL, 16); yylval.byte = strtol(yytext, NULL, 16);
DPRINT("Byte: %02x\n", (int)yylval.byte); DPRINT("Byte: %02x\n", (int)yylval.byte);
return DT_BYTE; return DT_BYTE;
} }
<BYTESTRING>"]" { <BYTESTRING>"]" {
yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
DPRINT("/BYTESTRING\n"); DPRINT("/BYTESTRING\n");
BEGIN_DEFAULT(); BEGIN_DEFAULT();
return ']'; return ']';
} }
<PROPNODENAME>{PROPNODECHAR}+ { <PROPNODENAME>{PROPNODECHAR}+ {
yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
DPRINT("PropNodeName: %s\n", yytext); DPRINT("PropNodeName: %s\n", yytext);
yylval.propnodename = strdup(yytext); yylval.propnodename = xstrdup(yytext);
BEGIN_DEFAULT(); BEGIN_DEFAULT();
return DT_PROPNODENAME; return DT_PROPNODENAME;
} }
"/incbin/" { "/incbin/" {
yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
DPRINT("Binary Include\n"); DPRINT("Binary Include\n");
return DT_INCBIN; return DT_INCBIN;
} }
...@@ -203,8 +151,6 @@ static int pop_input_file(void); ...@@ -203,8 +151,6 @@ static int pop_input_file(void);
<*>{LINECOMMENT}+ /* eat C++-style comments */ <*>{LINECOMMENT}+ /* eat C++-style comments */
<*>. { <*>. {
yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
DPRINT("Char: %c (\\x%02x)\n", yytext[0], DPRINT("Char: %c (\\x%02x)\n", yytext[0],
(unsigned)yytext[0]); (unsigned)yytext[0]);
if (yytext[0] == '[') { if (yytext[0] == '[') {
...@@ -221,100 +167,25 @@ static int pop_input_file(void); ...@@ -221,100 +167,25 @@ static int pop_input_file(void);
%% %%
/*
* Stack of nested include file contexts.
*/
struct incl_file {
struct dtc_file *file;
YY_BUFFER_STATE yy_prev_buf;
int yy_prev_lineno;
struct incl_file *prev;
};
static struct incl_file *incl_file_stack;
/*
* Detect infinite include recursion.
*/
#define MAX_INCLUDE_DEPTH (100)
static int incl_depth = 0;
static void push_input_file(const char *filename) static void push_input_file(const char *filename)
{ {
struct incl_file *incl_file;
struct dtc_file *newfile;
struct search_path search, *searchptr = NULL;
assert(filename); assert(filename);
if (incl_depth++ >= MAX_INCLUDE_DEPTH) srcfile_push(filename);
die("Includes nested too deeply");
if (srcpos_file) {
search.dir = srcpos_file->dir;
search.next = NULL;
search.prev = NULL;
searchptr = &search;
}
newfile = dtc_open_file(filename, searchptr);
incl_file = xmalloc(sizeof(struct incl_file)); yyin = current_srcfile->f;
/* yypush_buffer_state(yy_create_buffer(yyin, YY_BUF_SIZE));
* Save current context.
*/
incl_file->yy_prev_buf = YY_CURRENT_BUFFER;
incl_file->yy_prev_lineno = yylineno;
incl_file->file = srcpos_file;
incl_file->prev = incl_file_stack;
incl_file_stack = incl_file;
/*
* Establish new context.
*/
srcpos_file = newfile;
yylineno = 1;
yyin = newfile->file;
yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
} }
static int pop_input_file(void) static int pop_input_file(void)
{ {
struct incl_file *incl_file; if (srcfile_pop() == 0)
if (incl_file_stack == 0)
return 0; return 0;
dtc_close_file(srcpos_file); yypop_buffer_state();
yyin = current_srcfile->f;
/*
* Pop.
*/
--incl_depth;
incl_file = incl_file_stack;
incl_file_stack = incl_file->prev;
/*
* Recover old context.
*/
yy_delete_buffer(YY_CURRENT_BUFFER);
yy_switch_to_buffer(incl_file->yy_prev_buf);
yylineno = incl_file->yy_prev_lineno;
srcpos_file = incl_file->file;
yyin = incl_file->file ? incl_file->file->file : NULL;
/*
* Free old state.
*/
free(incl_file);
return 1; return 1;
} }
This diff is collapsed.
This diff is collapsed.
/* A Bison parser, made by GNU Bison 2.3. */
/* Skeleton interface for Bison's Yacc-like parsers in C /* A Bison parser, made by GNU Bison 2.4.1. */
Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 /* Skeleton interface for Bison's Yacc-like parsers in C
Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
Free Software Foundation, Inc. Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option) the Free Software Foundation, either version 3 of the License, or
any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software along with this program. If not, see <http://www.gnu.org/licenses/>. */
Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA. */
/* As a special exception, you may create a larger work that contains /* As a special exception, you may create a larger work that contains
part or all of the Bison parser skeleton and distribute that work part or all of the Bison parser skeleton and distribute that work
...@@ -29,10 +28,11 @@ ...@@ -29,10 +28,11 @@
special exception, which will cause the skeleton and the resulting special exception, which will cause the skeleton and the resulting
Bison output files to be licensed under the GNU General Public Bison output files to be licensed under the GNU General Public
License without this special exception. License without this special exception.
This special exception was added by the Free Software Foundation in This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */ version 2.2 of Bison. */
/* Tokens. */ /* Tokens. */
#ifndef YYTOKENTYPE #ifndef YYTOKENTYPE
# define YYTOKENTYPE # define YYTOKENTYPE
...@@ -43,35 +43,24 @@ ...@@ -43,35 +43,24 @@
DT_MEMRESERVE = 259, DT_MEMRESERVE = 259,
DT_PROPNODENAME = 260, DT_PROPNODENAME = 260,
DT_LITERAL = 261, DT_LITERAL = 261,
DT_LEGACYLITERAL = 262, DT_BASE = 262,
DT_BASE = 263, DT_BYTE = 263,
DT_BYTE = 264, DT_STRING = 264,
DT_STRING = 265, DT_LABEL = 265,
DT_LABEL = 266, DT_REF = 266,
DT_REF = 267, DT_INCBIN = 267
DT_INCBIN = 268
}; };
#endif #endif
/* Tokens. */
#define DT_V1 258
#define DT_MEMRESERVE 259
#define DT_PROPNODENAME 260
#define DT_LITERAL 261
#define DT_LEGACYLITERAL 262
#define DT_BASE 263
#define DT_BYTE 264
#define DT_STRING 265
#define DT_LABEL 266
#define DT_REF 267
#define DT_INCBIN 268
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef union YYSTYPE typedef union YYSTYPE
#line 37 "dtc-parser.y"
{ {
/* Line 1676 of yacc.c */
#line 39 "dtc-parser.y"
char *propnodename; char *propnodename;
char *literal; char *literal;
char *labelref; char *labelref;
...@@ -86,28 +75,17 @@ typedef union YYSTYPE ...@@ -86,28 +75,17 @@ typedef union YYSTYPE
struct node *node; struct node *node;
struct node *nodelist; struct node *nodelist;
struct reserve_info *re; struct reserve_info *re;
}
/* Line 1489 of yacc.c. */
#line 92 "dtc-parser.tab.h"
YYSTYPE; /* Line 1676 of yacc.c */
#line 83 "dtc-parser.tab.h"
} YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1
# define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1 # define YYSTYPE_IS_DECLARED 1
# define YYSTYPE_IS_TRIVIAL 1
#endif #endif
extern YYSTYPE yylval; extern YYSTYPE yylval;
#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
typedef struct YYLTYPE
{
int first_line;
int first_column;
int last_line;
int last_column;
} YYLTYPE;
# define yyltype YYLTYPE /* obsolescent; will be withdrawn */
# define YYLTYPE_IS_DECLARED 1
# define YYLTYPE_IS_TRIVIAL 1
#endif
extern YYLTYPE yylloc;
...@@ -18,15 +18,17 @@ ...@@ -18,15 +18,17 @@
* USA * USA
*/ */
%locations
%{ %{
#include <stdio.h> #include <stdio.h>
#include "dtc.h" #include "dtc.h"
#include "srcpos.h" #include "srcpos.h"
YYLTYPE yylloc;
extern int yylex(void); extern int yylex(void);
extern void print_error(char const *fmt, ...);
extern void yyerror(char const *s);
extern struct boot_info *the_boot_info; extern struct boot_info *the_boot_info;
extern int treesource_error; extern int treesource_error;
...@@ -55,7 +57,6 @@ static unsigned long long eval_literal(const char *s, int base, int bits); ...@@ -55,7 +57,6 @@ static unsigned long long eval_literal(const char *s, int base, int bits);
%token DT_MEMRESERVE %token DT_MEMRESERVE
%token <propnodename> DT_PROPNODENAME %token <propnodename> DT_PROPNODENAME
%token <literal> DT_LITERAL %token <literal> DT_LITERAL
%token <literal> DT_LEGACYLITERAL
%token <cbase> DT_BASE %token <cbase> DT_BASE
%token <byte> DT_BYTE %token <byte> DT_BYTE
%token <data> DT_STRING %token <data> DT_STRING
...@@ -67,11 +68,8 @@ static unsigned long long eval_literal(const char *s, int base, int bits); ...@@ -67,11 +68,8 @@ static unsigned long long eval_literal(const char *s, int base, int bits);
%type <data> propdataprefix %type <data> propdataprefix
%type <re> memreserve %type <re> memreserve
%type <re> memreserves %type <re> memreserves
%type <re> v0_memreserve
%type <re> v0_memreserves
%type <addr> addr %type <addr> addr
%type <data> celllist %type <data> celllist
%type <cbase> cellbase
%type <cell> cellval %type <cell> cellval
%type <data> bytestring %type <data> bytestring
%type <prop> propdef %type <prop> propdef
...@@ -81,18 +79,14 @@ static unsigned long long eval_literal(const char *s, int base, int bits); ...@@ -81,18 +79,14 @@ static unsigned long long eval_literal(const char *s, int base, int bits);
%type <node> nodedef %type <node> nodedef
%type <node> subnode %type <node> subnode
%type <nodelist> subnodes %type <nodelist> subnodes
%type <labelref> label
%% %%
sourcefile: sourcefile:
DT_V1 ';' memreserves devicetree DT_V1 ';' memreserves devicetree
{ {
the_boot_info = build_boot_info($3, $4, 0); the_boot_info = build_boot_info($3, $4,
} guess_boot_cpuid($4));
| v0_memreserves devicetree
{
the_boot_info = build_boot_info($1, $2, 0);
} }
; ;
...@@ -108,31 +102,14 @@ memreserves: ...@@ -108,31 +102,14 @@ memreserves:
; ;
memreserve: memreserve:
label DT_MEMRESERVE addr addr ';' DT_MEMRESERVE addr addr ';'
{ {
$$ = build_reserve_entry($3, $4, $1); $$ = build_reserve_entry($2, $3);
} }
; | DT_LABEL memreserve
v0_memreserves:
/* empty */
{ {
$$ = NULL; add_label(&$2->labels, $1);
} $$ = $2;
| v0_memreserve v0_memreserves
{
$$ = chain_reserve_entry($1, $2);
};
;
v0_memreserve:
memreserve
{
$$ = $1;
}
| label DT_MEMRESERVE addr '-' addr ';'
{
$$ = build_reserve_entry($3, $5 - $3 + 1, $1);
} }
; ;
...@@ -141,16 +118,26 @@ addr: ...@@ -141,16 +118,26 @@ addr:
{ {
$$ = eval_literal($1, 0, 64); $$ = eval_literal($1, 0, 64);
} }
| DT_LEGACYLITERAL
{
$$ = eval_literal($1, 16, 64);
}
; ;
devicetree: devicetree:
'/' nodedef '/' nodedef
{ {
$$ = name_node($2, "", NULL); $$ = name_node($2, "");
}
| devicetree '/' nodedef
{
$$ = merge_nodes($1, $3);
}
| devicetree DT_REF nodedef
{
struct node *target = get_node_by_ref($1, $2);
if (target)
merge_nodes(target, $3);
else
print_error("label or path, '%s', not found", $2);
$$ = $1;
} }
; ;
...@@ -173,13 +160,18 @@ proplist: ...@@ -173,13 +160,18 @@ proplist:
; ;
propdef: propdef:
label DT_PROPNODENAME '=' propdata ';' DT_PROPNODENAME '=' propdata ';'
{
$$ = build_property($1, $3);
}
| DT_PROPNODENAME ';'
{ {
$$ = build_property($2, $4, $1); $$ = build_property($1, empty_data);
} }
| label DT_PROPNODENAME ';' | DT_LABEL propdef
{ {
$$ = build_property($2, empty_data, $1); add_label(&$2->labels, $1);
$$ = $2;
} }
; ;
...@@ -202,31 +194,30 @@ propdata: ...@@ -202,31 +194,30 @@ propdata:
} }
| propdataprefix DT_INCBIN '(' DT_STRING ',' addr ',' addr ')' | propdataprefix DT_INCBIN '(' DT_STRING ',' addr ',' addr ')'
{ {
struct search_path path = { srcpos_file->dir, NULL, NULL }; FILE *f = srcfile_relative_open($4.val, NULL);
struct dtc_file *file = dtc_open_file($4.val, &path); struct data d;
struct data d = empty_data;
if ($6 != 0) if ($6 != 0)
if (fseek(file->file, $6, SEEK_SET) != 0) if (fseek(f, $6, SEEK_SET) != 0)
yyerrorf("Couldn't seek to offset %llu in \"%s\": %s", print_error("Couldn't seek to offset %llu in \"%s\": %s",
(unsigned long long)$6, (unsigned long long)$6,
$4.val, strerror(errno)); $4.val,
strerror(errno));
d = data_copy_file(file->file, $8); d = data_copy_file(f, $8);
$$ = data_merge($1, d); $$ = data_merge($1, d);
dtc_close_file(file); fclose(f);
} }
| propdataprefix DT_INCBIN '(' DT_STRING ')' | propdataprefix DT_INCBIN '(' DT_STRING ')'
{ {
struct search_path path = { srcpos_file->dir, NULL, NULL }; FILE *f = srcfile_relative_open($4.val, NULL);
struct dtc_file *file = dtc_open_file($4.val, &path);
struct data d = empty_data; struct data d = empty_data;
d = data_copy_file(file->file, -1); d = data_copy_file(f, -1);
$$ = data_merge($1, d); $$ = data_merge($1, d);
dtc_close_file(file); fclose(f);
} }
| propdata DT_LABEL | propdata DT_LABEL
{ {
...@@ -269,23 +260,11 @@ celllist: ...@@ -269,23 +260,11 @@ celllist:
} }
; ;
cellbase:
/* empty */
{
$$ = 16;
}
| DT_BASE
;
cellval: cellval:
DT_LITERAL DT_LITERAL
{ {
$$ = eval_literal($1, 0, 32); $$ = eval_literal($1, 0, 32);
} }
| cellbase DT_LEGACYLITERAL
{
$$ = eval_literal($2, $1, 32);
}
; ;
bytestring: bytestring:
...@@ -308,57 +287,44 @@ subnodes: ...@@ -308,57 +287,44 @@ subnodes:
{ {
$$ = NULL; $$ = NULL;
} }
| subnode subnodes | subnode subnodes
{ {
$$ = chain_node($1, $2); $$ = chain_node($1, $2);
} }
| subnode propdef | subnode propdef
{ {
yyerror("syntax error: properties must precede subnodes"); print_error("syntax error: properties must precede subnodes");
YYERROR; YYERROR;
} }
; ;
subnode: subnode:
label DT_PROPNODENAME nodedef DT_PROPNODENAME nodedef
{ {
$$ = name_node($3, $2, $1); $$ = name_node($2, $1);
} }
; | DT_LABEL subnode
label:
/* empty */
{ {
$$ = NULL; add_label(&$2->labels, $1);
} $$ = $2;
| DT_LABEL
{
$$ = $1;
} }
; ;
%% %%
void yyerrorf(char const *s, ...) void print_error(char const *fmt, ...)
{ {
const char *fname = srcpos_file ? srcpos_file->name : "<no-file>";
va_list va; va_list va;
va_start(va, s);
if (strcmp(fname, "-") == 0)
fname = "stdin";
fprintf(stderr, "%s:%d ", fname, yylloc.first_line); va_start(va, fmt);
vfprintf(stderr, s, va); srcpos_verror(&yylloc, fmt, va);
fprintf(stderr, "\n"); va_end(va);
treesource_error = 1; treesource_error = 1;
va_end(va);
} }
void yyerror (char const *s) void yyerror(char const *s) {
{ print_error("%s", s);
yyerrorf("%s", s);
} }
static unsigned long long eval_literal(const char *s, int base, int bits) static unsigned long long eval_literal(const char *s, int base, int bits)
...@@ -369,11 +335,11 @@ static unsigned long long eval_literal(const char *s, int base, int bits) ...@@ -369,11 +335,11 @@ static unsigned long long eval_literal(const char *s, int base, int bits)
errno = 0; errno = 0;
val = strtoull(s, &e, base); val = strtoull(s, &e, base);
if (*e) if (*e)
yyerror("bad characters in literal"); print_error("bad characters in literal");
else if ((errno == ERANGE) else if ((errno == ERANGE)
|| ((bits < 64) && (val >= (1ULL << bits)))) || ((bits < 64) && (val >= (1ULL << bits))))
yyerror("literal out of range"); print_error("literal out of range");
else if (errno != 0) else if (errno != 0)
yyerror("bad literal"); print_error("bad literal");
return val; return val;
} }
...@@ -30,30 +30,7 @@ int quiet; /* Level of quietness */ ...@@ -30,30 +30,7 @@ int quiet; /* Level of quietness */
int reservenum; /* Number of memory reservation slots */ int reservenum; /* Number of memory reservation slots */
int minsize; /* Minimum blob size */ int minsize; /* Minimum blob size */
int padsize; /* Additional padding to blob */ int padsize; /* Additional padding to blob */
int phandle_format = PHANDLE_BOTH; /* Use linux,phandle or phandle properties */
char *join_path(const char *path, const char *name)
{
int lenp = strlen(path);
int lenn = strlen(name);
int len;
int needslash = 1;
char *str;
len = lenp + lenn + 2;
if ((lenp > 0) && (path[lenp-1] == '/')) {
needslash = 0;
len--;
}
str = xmalloc(len);
memcpy(str, path, lenp);
if (needslash) {
str[lenp] = '/';
lenp++;
}
memcpy(str+lenp, name, lenn+1);
return str;
}
static void fill_fullpaths(struct node *tree, const char *prefix) static void fill_fullpaths(struct node *tree, const char *prefix)
{ {
...@@ -104,8 +81,15 @@ static void __attribute__ ((noreturn)) usage(void) ...@@ -104,8 +81,15 @@ static void __attribute__ ((noreturn)) usage(void)
fprintf(stderr, "\t\tSet the physical boot cpu\n"); fprintf(stderr, "\t\tSet the physical boot cpu\n");
fprintf(stderr, "\t-f\n"); fprintf(stderr, "\t-f\n");
fprintf(stderr, "\t\tForce - try to produce output even if the input tree has errors\n"); fprintf(stderr, "\t\tForce - try to produce output even if the input tree has errors\n");
fprintf(stderr, "\t-s\n");
fprintf(stderr, "\t\tSort nodes and properties before outputting (only useful for\n\t\tcomparing trees)\n");
fprintf(stderr, "\t-v\n"); fprintf(stderr, "\t-v\n");
fprintf(stderr, "\t\tPrint DTC version and exit\n"); fprintf(stderr, "\t\tPrint DTC version and exit\n");
fprintf(stderr, "\t-H <phandle format>\n");
fprintf(stderr, "\t\tphandle formats are:\n");
fprintf(stderr, "\t\t\tlegacy - \"linux,phandle\" properties only\n");
fprintf(stderr, "\t\t\tepapr - \"phandle\" properties only\n");
fprintf(stderr, "\t\t\tboth - Both \"linux,phandle\" and \"phandle\" properties\n");
exit(3); exit(3);
} }
...@@ -115,7 +99,7 @@ int main(int argc, char *argv[]) ...@@ -115,7 +99,7 @@ int main(int argc, char *argv[])
const char *inform = "dts"; const char *inform = "dts";
const char *outform = "dts"; const char *outform = "dts";
const char *outname = "-"; const char *outname = "-";
int force = 0, check = 0; int force = 0, check = 0, sort = 0;
const char *arg; const char *arg;
int opt; int opt;
FILE *outf = NULL; FILE *outf = NULL;
...@@ -127,7 +111,7 @@ int main(int argc, char *argv[]) ...@@ -127,7 +111,7 @@ int main(int argc, char *argv[])
minsize = 0; minsize = 0;
padsize = 0; padsize = 0;
while ((opt = getopt(argc, argv, "hI:O:o:V:R:S:p:fcqb:v")) != EOF) { while ((opt = getopt(argc, argv, "hI:O:o:V:R:S:p:fcqb:vH:s")) != EOF) {
switch (opt) { switch (opt) {
case 'I': case 'I':
inform = optarg; inform = optarg;
...@@ -165,6 +149,22 @@ int main(int argc, char *argv[]) ...@@ -165,6 +149,22 @@ int main(int argc, char *argv[])
case 'v': case 'v':
printf("Version: %s\n", DTC_VERSION); printf("Version: %s\n", DTC_VERSION);
exit(0); exit(0);
case 'H':
if (streq(optarg, "legacy"))
phandle_format = PHANDLE_LEGACY;
else if (streq(optarg, "epapr"))
phandle_format = PHANDLE_EPAPR;
else if (streq(optarg, "both"))
phandle_format = PHANDLE_BOTH;
else
die("Invalid argument \"%s\" to -H option\n",
optarg);
break;
case 's':
sort = 1;
break;
case 'h': case 'h':
default: default:
usage(); usage();
...@@ -182,6 +182,9 @@ int main(int argc, char *argv[]) ...@@ -182,6 +182,9 @@ int main(int argc, char *argv[])
if (minsize && padsize) if (minsize && padsize)
die("Can't set both -p and -S\n"); die("Can't set both -p and -S\n");
if (minsize)
fprintf(stderr, "DTC: Use of \"-S\" is deprecated; it will be removed soon, use \"-p\" instead\n");
fprintf(stderr, "DTC: %s->%s on file \"%s\"\n", fprintf(stderr, "DTC: %s->%s on file \"%s\"\n",
inform, outform, arg); inform, outform, arg);
...@@ -200,6 +203,8 @@ int main(int argc, char *argv[]) ...@@ -200,6 +203,8 @@ int main(int argc, char *argv[])
fill_fullpaths(bi->dt, ""); fill_fullpaths(bi->dt, "");
process_checks(force, bi); process_checks(force, bi);
if (sort)
sort_tree(bi);
if (streq(outname, "-")) { if (streq(outname, "-")) {
outf = stdout; outf = stdout;
......
...@@ -34,7 +34,17 @@ ...@@ -34,7 +34,17 @@
#include <libfdt_env.h> #include <libfdt_env.h>
#include <fdt.h> #include <fdt.h>
#include "util.h"
#ifdef DEBUG
#define debug(fmt,args...) printf(fmt, ##args)
#else
#define debug(fmt,args...)
#endif
#define DEFAULT_FDT_VERSION 17 #define DEFAULT_FDT_VERSION 17
/* /*
* Command line options * Command line options
*/ */
...@@ -42,36 +52,11 @@ extern int quiet; /* Level of quietness */ ...@@ -42,36 +52,11 @@ extern int quiet; /* Level of quietness */
extern int reservenum; /* Number of memory reservation slots */ extern int reservenum; /* Number of memory reservation slots */
extern int minsize; /* Minimum blob size */ extern int minsize; /* Minimum blob size */
extern int padsize; /* Additional padding to blob */ extern int padsize; /* Additional padding to blob */
extern int phandle_format; /* Use linux,phandle or phandle properties */
static inline void __attribute__((noreturn)) die(char * str, ...) #define PHANDLE_LEGACY 0x1
{ #define PHANDLE_EPAPR 0x2
va_list ap; #define PHANDLE_BOTH 0x3
va_start(ap, str);
fprintf(stderr, "FATAL ERROR: ");
vfprintf(stderr, str, ap);
exit(1);
}
static inline void *xmalloc(size_t len)
{
void *new = malloc(len);
if (! new)
die("malloc() failed\n");
return new;
}
static inline void *xrealloc(void *p, size_t len)
{
void *new = realloc(p, len);
if (! new)
die("realloc() failed (len=%d)\n", len);
return new;
}
typedef uint32_t cell_t; typedef uint32_t cell_t;
...@@ -140,13 +125,18 @@ int data_is_one_string(struct data d); ...@@ -140,13 +125,18 @@ int data_is_one_string(struct data d);
#define MAX_NODENAME_LEN 31 #define MAX_NODENAME_LEN 31
/* Live trees */ /* Live trees */
struct label {
char *label;
struct label *next;
};
struct property { struct property {
char *name; char *name;
struct data val; struct data val;
struct property *next; struct property *next;
char *label; struct label *labels;
}; };
struct node { struct node {
...@@ -163,22 +153,28 @@ struct node { ...@@ -163,22 +153,28 @@ struct node {
cell_t phandle; cell_t phandle;
int addr_cells, size_cells; int addr_cells, size_cells;
char *label; struct label *labels;
}; };
#define for_each_label(l0, l) \
for ((l) = (l0); (l); (l) = (l)->next)
#define for_each_property(n, p) \ #define for_each_property(n, p) \
for ((p) = (n)->proplist; (p); (p) = (p)->next) for ((p) = (n)->proplist; (p); (p) = (p)->next)
#define for_each_child(n, c) \ #define for_each_child(n, c) \
for ((c) = (n)->children; (c); (c) = (c)->next_sibling) for ((c) = (n)->children; (c); (c) = (c)->next_sibling)
struct property *build_property(char *name, struct data val, char *label); void add_label(struct label **labels, char *label);
struct property *build_property(char *name, struct data val);
struct property *chain_property(struct property *first, struct property *list); struct property *chain_property(struct property *first, struct property *list);
struct property *reverse_properties(struct property *first); struct property *reverse_properties(struct property *first);
struct node *build_node(struct property *proplist, struct node *children); struct node *build_node(struct property *proplist, struct node *children);
struct node *name_node(struct node *node, char *name, char *label); struct node *name_node(struct node *node, char *name);
struct node *chain_node(struct node *first, struct node *list); struct node *chain_node(struct node *first, struct node *list);
struct node *merge_nodes(struct node *old_node, struct node *new_node);
void add_property(struct node *node, struct property *prop); void add_property(struct node *node, struct property *prop);
void add_child(struct node *parent, struct node *child); void add_child(struct node *parent, struct node *child);
...@@ -186,6 +182,10 @@ void add_child(struct node *parent, struct node *child); ...@@ -186,6 +182,10 @@ void add_child(struct node *parent, struct node *child);
const char *get_unitname(struct node *node); const char *get_unitname(struct node *node);
struct property *get_property(struct node *node, const char *propname); struct property *get_property(struct node *node, const char *propname);
cell_t propval_cell(struct property *prop); cell_t propval_cell(struct property *prop);
struct property *get_property_by_label(struct node *tree, const char *label,
struct node **node);
struct marker *get_marker_label(struct node *tree, const char *label,
struct node **node, struct property **prop);
struct node *get_subnode(struct node *node, const char *nodename); struct node *get_subnode(struct node *node, const char *nodename);
struct node *get_node_by_path(struct node *tree, const char *path); struct node *get_node_by_path(struct node *tree, const char *path);
struct node *get_node_by_label(struct node *tree, const char *label); struct node *get_node_by_label(struct node *tree, const char *label);
...@@ -193,6 +193,8 @@ struct node *get_node_by_phandle(struct node *tree, cell_t phandle); ...@@ -193,6 +193,8 @@ struct node *get_node_by_phandle(struct node *tree, cell_t phandle);
struct node *get_node_by_ref(struct node *tree, const char *ref); struct node *get_node_by_ref(struct node *tree, const char *ref);
cell_t get_node_phandle(struct node *root, struct node *node); cell_t get_node_phandle(struct node *root, struct node *node);
uint32_t guess_boot_cpuid(struct node *tree);
/* Boot info (tree plus memreserve information */ /* Boot info (tree plus memreserve information */
struct reserve_info { struct reserve_info {
...@@ -200,10 +202,10 @@ struct reserve_info { ...@@ -200,10 +202,10 @@ struct reserve_info {
struct reserve_info *next; struct reserve_info *next;
char *label; struct label *labels;
}; };
struct reserve_info *build_reserve_entry(uint64_t start, uint64_t len, char *label); struct reserve_info *build_reserve_entry(uint64_t start, uint64_t len);
struct reserve_info *chain_reserve_entry(struct reserve_info *first, struct reserve_info *chain_reserve_entry(struct reserve_info *first,
struct reserve_info *list); struct reserve_info *list);
struct reserve_info *add_reserve_entry(struct reserve_info *list, struct reserve_info *add_reserve_entry(struct reserve_info *list,
...@@ -218,6 +220,7 @@ struct boot_info { ...@@ -218,6 +220,7 @@ struct boot_info {
struct boot_info *build_boot_info(struct reserve_info *reservelist, struct boot_info *build_boot_info(struct reserve_info *reservelist,
struct node *tree, uint32_t boot_cpuid_phys); struct node *tree, uint32_t boot_cpuid_phys);
void sort_tree(struct boot_info *bi);
/* Checks */ /* Checks */
...@@ -239,8 +242,4 @@ struct boot_info *dt_from_source(const char *f); ...@@ -239,8 +242,4 @@ struct boot_info *dt_from_source(const char *f);
struct boot_info *dt_from_fs(const char *dirname); struct boot_info *dt_from_fs(const char *dirname);
/* misc */
char *join_path(const char *path, const char *name);
#endif /* _DTC_H */ #endif /* _DTC_H */
This diff is collapsed.
...@@ -58,10 +58,9 @@ static struct node *read_fstree(const char *dirname) ...@@ -58,10 +58,9 @@ static struct node *read_fstree(const char *dirname)
"WARNING: Cannot open %s: %s\n", "WARNING: Cannot open %s: %s\n",
tmpnam, strerror(errno)); tmpnam, strerror(errno));
} else { } else {
prop = build_property(strdup(de->d_name), prop = build_property(xstrdup(de->d_name),
data_copy_file(pfile, data_copy_file(pfile,
st.st_size), st.st_size));
NULL);
add_property(tree, prop); add_property(tree, prop);
fclose(pfile); fclose(pfile);
} }
...@@ -69,8 +68,7 @@ static struct node *read_fstree(const char *dirname) ...@@ -69,8 +68,7 @@ static struct node *read_fstree(const char *dirname)
struct node *newchild; struct node *newchild;
newchild = read_fstree(tmpnam); newchild = read_fstree(tmpnam);
newchild = name_node(newchild, strdup(de->d_name), newchild = name_node(newchild, xstrdup(de->d_name));
NULL);
add_child(tree, newchild); add_child(tree, newchild);
} }
...@@ -86,8 +84,8 @@ struct boot_info *dt_from_fs(const char *dirname) ...@@ -86,8 +84,8 @@ struct boot_info *dt_from_fs(const char *dirname)
struct node *tree; struct node *tree;
tree = read_fstree(dirname); tree = read_fstree(dirname);
tree = name_node(tree, "", NULL); tree = name_node(tree, "");
return build_boot_info(NULL, tree, 0); return build_boot_info(NULL, tree, guess_boot_cpuid(tree));
} }
...@@ -24,17 +24,30 @@ ...@@ -24,17 +24,30 @@
* Tree building functions * Tree building functions
*/ */
struct property *build_property(char *name, struct data val, char *label) void add_label(struct label **labels, char *label)
{
struct label *new;
/* Make sure the label isn't already there */
for_each_label(*labels, new)
if (streq(new->label, label))
return;
new = xmalloc(sizeof(*new));
new->label = label;
new->next = *labels;
*labels = new;
}
struct property *build_property(char *name, struct data val)
{ {
struct property *new = xmalloc(sizeof(*new)); struct property *new = xmalloc(sizeof(*new));
memset(new, 0, sizeof(*new));
new->name = name; new->name = name;
new->val = val; new->val = val;
new->next = NULL;
new->label = label;
return new; return new;
} }
...@@ -78,17 +91,82 @@ struct node *build_node(struct property *proplist, struct node *children) ...@@ -78,17 +91,82 @@ struct node *build_node(struct property *proplist, struct node *children)
return new; return new;
} }
struct node *name_node(struct node *node, char *name, char * label) struct node *name_node(struct node *node, char *name)
{ {
assert(node->name == NULL); assert(node->name == NULL);
node->name = name; node->name = name;
node->label = label;
return node; return node;
} }
struct node *merge_nodes(struct node *old_node, struct node *new_node)
{
struct property *new_prop, *old_prop;
struct node *new_child, *old_child;
struct label *l;
/* Add new node labels to old node */
for_each_label(new_node->labels, l)
add_label(&old_node->labels, l->label);
/* Move properties from the new node to the old node. If there
* is a collision, replace the old value with the new */
while (new_node->proplist) {
/* Pop the property off the list */
new_prop = new_node->proplist;
new_node->proplist = new_prop->next;
new_prop->next = NULL;
/* Look for a collision, set new value if there is */
for_each_property(old_node, old_prop) {
if (streq(old_prop->name, new_prop->name)) {
/* Add new labels to old property */
for_each_label(new_prop->labels, l)
add_label(&old_prop->labels, l->label);
old_prop->val = new_prop->val;
free(new_prop);
new_prop = NULL;
break;
}
}
/* if no collision occurred, add property to the old node. */
if (new_prop)
add_property(old_node, new_prop);
}
/* Move the override child nodes into the primary node. If
* there is a collision, then merge the nodes. */
while (new_node->children) {
/* Pop the child node off the list */
new_child = new_node->children;
new_node->children = new_child->next_sibling;
new_child->parent = NULL;
new_child->next_sibling = NULL;
/* Search for a collision. Merge if there is */
for_each_child(old_node, old_child) {
if (streq(old_child->name, new_child->name)) {
merge_nodes(old_child, new_child);
new_child = NULL;
break;
}
}
/* if no collision occured, add child to the old node. */
if (new_child)
add_child(old_node, new_child);
}
/* The new node contents are now merged into the old node. Free
* the new node. */
free(new_node);
return old_node;
}
struct node *chain_node(struct node *first, struct node *list) struct node *chain_node(struct node *first, struct node *list)
{ {
assert(first->next_sibling == NULL); assert(first->next_sibling == NULL);
...@@ -124,18 +202,15 @@ void add_child(struct node *parent, struct node *child) ...@@ -124,18 +202,15 @@ void add_child(struct node *parent, struct node *child)
*p = child; *p = child;
} }
struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size, struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size)
char *label)
{ {
struct reserve_info *new = xmalloc(sizeof(*new)); struct reserve_info *new = xmalloc(sizeof(*new));
memset(new, 0, sizeof(*new));
new->re.address = address; new->re.address = address;
new->re.size = size; new->re.size = size;
new->next = NULL;
new->label = label;
return new; return new;
} }
...@@ -208,6 +283,60 @@ cell_t propval_cell(struct property *prop) ...@@ -208,6 +283,60 @@ cell_t propval_cell(struct property *prop)
return fdt32_to_cpu(*((cell_t *)prop->val.val)); return fdt32_to_cpu(*((cell_t *)prop->val.val));
} }
struct property *get_property_by_label(struct node *tree, const char *label,
struct node **node)
{
struct property *prop;
struct node *c;
*node = tree;
for_each_property(tree, prop) {
struct label *l;
for_each_label(prop->labels, l)
if (streq(l->label, label))
return prop;
}
for_each_child(tree, c) {
prop = get_property_by_label(c, label, node);
if (prop)
return prop;
}
*node = NULL;
return NULL;
}
struct marker *get_marker_label(struct node *tree, const char *label,
struct node **node, struct property **prop)
{
struct marker *m;
struct property *p;
struct node *c;
*node = tree;
for_each_property(tree, p) {
*prop = p;
m = p->val.markers;
for_each_marker_of_type(m, LABEL)
if (streq(m->ref, label))
return m;
}
for_each_child(tree, c) {
m = get_marker_label(c, label, node, prop);
if (m)
return m;
}
*prop = NULL;
*node = NULL;
return NULL;
}
struct node *get_subnode(struct node *node, const char *nodename) struct node *get_subnode(struct node *node, const char *nodename)
{ {
struct node *child; struct node *child;
...@@ -245,11 +374,13 @@ struct node *get_node_by_path(struct node *tree, const char *path) ...@@ -245,11 +374,13 @@ struct node *get_node_by_path(struct node *tree, const char *path)
struct node *get_node_by_label(struct node *tree, const char *label) struct node *get_node_by_label(struct node *tree, const char *label)
{ {
struct node *child, *node; struct node *child, *node;
struct label *l;
assert(label && (strlen(label) > 0)); assert(label && (strlen(label) > 0));
if (tree->label && streq(tree->label, label)) for_each_label(tree->labels, l)
return tree; if (streq(l->label, label))
return tree;
for_each_child(tree, child) { for_each_child(tree, child) {
node = get_node_by_label(child, label); node = get_node_by_label(child, label);
...@@ -293,16 +424,186 @@ cell_t get_node_phandle(struct node *root, struct node *node) ...@@ -293,16 +424,186 @@ cell_t get_node_phandle(struct node *root, struct node *node)
if ((node->phandle != 0) && (node->phandle != -1)) if ((node->phandle != 0) && (node->phandle != -1))
return node->phandle; return node->phandle;
assert(! get_property(node, "linux,phandle"));
while (get_node_by_phandle(root, phandle)) while (get_node_by_phandle(root, phandle))
phandle++; phandle++;
node->phandle = phandle; node->phandle = phandle;
add_property(node,
build_property("linux,phandle", if (!get_property(node, "linux,phandle")
data_append_cell(empty_data, phandle), && (phandle_format & PHANDLE_LEGACY))
NULL)); add_property(node,
build_property("linux,phandle",
data_append_cell(empty_data, phandle)));
if (!get_property(node, "phandle")
&& (phandle_format & PHANDLE_EPAPR))
add_property(node,
build_property("phandle",
data_append_cell(empty_data, phandle)));
/* If the node *does* have a phandle property, we must
* be dealing with a self-referencing phandle, which will be
* fixed up momentarily in the caller */
return node->phandle; return node->phandle;
} }
uint32_t guess_boot_cpuid(struct node *tree)
{
struct node *cpus, *bootcpu;
struct property *reg;
cpus = get_node_by_path(tree, "/cpus");
if (!cpus)
return 0;
bootcpu = cpus->children;
if (!bootcpu)
return 0;
reg = get_property(bootcpu, "reg");
if (!reg || (reg->val.len != sizeof(uint32_t)))
return 0;
/* FIXME: Sanity check node? */
return propval_cell(reg);
}
static int cmp_reserve_info(const void *ax, const void *bx)
{
const struct reserve_info *a, *b;
a = *((const struct reserve_info * const *)ax);
b = *((const struct reserve_info * const *)bx);
if (a->re.address < b->re.address)
return -1;
else if (a->re.address > b->re.address)
return 1;
else if (a->re.size < b->re.size)
return -1;
else if (a->re.size > b->re.size)
return 1;
else
return 0;
}
static void sort_reserve_entries(struct boot_info *bi)
{
struct reserve_info *ri, **tbl;
int n = 0, i = 0;
for (ri = bi->reservelist;
ri;
ri = ri->next)
n++;
if (n == 0)
return;
tbl = xmalloc(n * sizeof(*tbl));
for (ri = bi->reservelist;
ri;
ri = ri->next)
tbl[i++] = ri;
qsort(tbl, n, sizeof(*tbl), cmp_reserve_info);
bi->reservelist = tbl[0];
for (i = 0; i < (n-1); i++)
tbl[i]->next = tbl[i+1];
tbl[n-1]->next = NULL;
free(tbl);
}
static int cmp_prop(const void *ax, const void *bx)
{
const struct property *a, *b;
a = *((const struct property * const *)ax);
b = *((const struct property * const *)bx);
return strcmp(a->name, b->name);
}
static void sort_properties(struct node *node)
{
int n = 0, i = 0;
struct property *prop, **tbl;
for_each_property(node, prop)
n++;
if (n == 0)
return;
tbl = xmalloc(n * sizeof(*tbl));
for_each_property(node, prop)
tbl[i++] = prop;
qsort(tbl, n, sizeof(*tbl), cmp_prop);
node->proplist = tbl[0];
for (i = 0; i < (n-1); i++)
tbl[i]->next = tbl[i+1];
tbl[n-1]->next = NULL;
free(tbl);
}
static int cmp_subnode(const void *ax, const void *bx)
{
const struct node *a, *b;
a = *((const struct node * const *)ax);
b = *((const struct node * const *)bx);
return strcmp(a->name, b->name);
}
static void sort_subnodes(struct node *node)
{
int n = 0, i = 0;
struct node *subnode, **tbl;
for_each_child(node, subnode)
n++;
if (n == 0)
return;
tbl = xmalloc(n * sizeof(*tbl));
for_each_child(node, subnode)
tbl[i++] = subnode;
qsort(tbl, n, sizeof(*tbl), cmp_subnode);
node->children = tbl[0];
for (i = 0; i < (n-1); i++)
tbl[i]->next_sibling = tbl[i+1];
tbl[n-1]->next_sibling = NULL;
free(tbl);
}
static void sort_node(struct node *node)
{
struct node *c;
sort_properties(node);
sort_subnodes(node);
for_each_child(node, c)
sort_node(c);
}
void sort_tree(struct boot_info *bi)
{
sort_reserve_entries(bi);
sort_node(bi->dt);
}
...@@ -17,100 +17,232 @@ ...@@ -17,100 +17,232 @@
* USA * USA
*/ */
#define _GNU_SOURCE
#include <stdio.h>
#include "dtc.h" #include "dtc.h"
#include "srcpos.h" #include "srcpos.h"
/*
* Like yylineno, this is the current open file pos.
*/
struct dtc_file *srcpos_file; static char *dirname(const char *path)
{
const char *slash = strrchr(path, '/');
if (slash) {
int len = slash - path;
char *dir = xmalloc(len + 1);
memcpy(dir, path, len);
dir[len] = '\0';
return dir;
}
return NULL;
}
struct srcfile_state *current_srcfile; /* = NULL */
static int dtc_open_one(struct dtc_file *file, /* Detect infinite include recursion. */
const char *search, #define MAX_SRCFILE_DEPTH (100)
const char *fname) static int srcfile_depth; /* = 0 */
FILE *srcfile_relative_open(const char *fname, char **fullnamep)
{ {
FILE *f;
char *fullname; char *fullname;
if (search) { if (streq(fname, "-")) {
fullname = xmalloc(strlen(search) + strlen(fname) + 2); f = stdin;
fullname = xstrdup("<stdin>");
strcpy(fullname, search);
strcat(fullname, "/");
strcat(fullname, fname);
} else { } else {
fullname = strdup(fname); if (!current_srcfile || !current_srcfile->dir
|| (fname[0] == '/'))
fullname = xstrdup(fname);
else
fullname = join_path(current_srcfile->dir, fname);
f = fopen(fullname, "r");
if (!f)
die("Couldn't open \"%s\": %s\n", fname,
strerror(errno));
} }
file->file = fopen(fullname, "r"); if (fullnamep)
if (!file->file) { *fullnamep = fullname;
else
free(fullname); free(fullname);
return 0;
}
file->name = fullname; return f;
return 1;
} }
void srcfile_push(const char *fname)
{
struct srcfile_state *srcfile;
if (srcfile_depth++ >= MAX_SRCFILE_DEPTH)
die("Includes nested too deeply");
srcfile = xmalloc(sizeof(*srcfile));
srcfile->f = srcfile_relative_open(fname, &srcfile->name);
srcfile->dir = dirname(srcfile->name);
srcfile->prev = current_srcfile;
srcfile->lineno = 1;
srcfile->colno = 1;
current_srcfile = srcfile;
}
struct dtc_file *dtc_open_file(const char *fname, int srcfile_pop(void)
const struct search_path *search)
{ {
static const struct search_path default_search = { NULL, NULL, NULL }; struct srcfile_state *srcfile = current_srcfile;
struct dtc_file *file; assert(srcfile);
const char *slash;
file = xmalloc(sizeof(struct dtc_file)); current_srcfile = srcfile->prev;
slash = strrchr(fname, '/'); if (fclose(srcfile->f))
if (slash) { die("Error closing \"%s\": %s\n", srcfile->name,
char *dir = xmalloc(slash - fname + 1); strerror(errno));
memcpy(dir, fname, slash - fname); /* FIXME: We allow the srcfile_state structure to leak,
dir[slash - fname] = 0; * because it could still be referenced from a location
file->dir = dir; * variable being carried through the parser somewhere. To
} else { * fix this we could either allocate all the files from a
file->dir = NULL; * table, or use a pool allocator. */
}
if (streq(fname, "-")) { return current_srcfile ? 1 : 0;
file->name = "stdin"; }
file->file = stdin;
return file;
}
if (fname[0] == '/') { /*
file->file = fopen(fname, "r"); * The empty source position.
if (!file->file) */
goto fail;
file->name = strdup(fname); struct srcpos srcpos_empty = {
return file; .first_line = 0,
} .first_column = 0,
.last_line = 0,
.last_column = 0,
.file = NULL,
};
if (!search) #define TAB_SIZE 8
search = &default_search;
while (search) { void srcpos_update(struct srcpos *pos, const char *text, int len)
if (dtc_open_one(file, search->dir, fname)) {
return file; int i;
pos->file = current_srcfile;
pos->first_line = current_srcfile->lineno;
pos->first_column = current_srcfile->colno;
for (i = 0; i < len; i++)
if (text[i] == '\n') {
current_srcfile->lineno++;
current_srcfile->colno = 1;
} else if (text[i] == '\t') {
current_srcfile->colno =
ALIGN(current_srcfile->colno, TAB_SIZE);
} else {
current_srcfile->colno++;
}
pos->last_line = current_srcfile->lineno;
pos->last_column = current_srcfile->colno;
}
if (errno != ENOENT) struct srcpos *
goto fail; srcpos_copy(struct srcpos *pos)
{
struct srcpos *pos_new;
search = search->next; pos_new = xmalloc(sizeof(struct srcpos));
} memcpy(pos_new, pos, sizeof(struct srcpos));
return pos_new;
}
void
srcpos_dump(struct srcpos *pos)
{
printf("file : \"%s\"\n",
pos->file ? (char *) pos->file : "<no file>");
printf("first_line : %d\n", pos->first_line);
printf("first_column: %d\n", pos->first_column);
printf("last_line : %d\n", pos->last_line);
printf("last_column : %d\n", pos->last_column);
printf("file : %s\n", pos->file->name);
}
fail:
die("Couldn't open \"%s\": %s\n", fname, strerror(errno)); char *
srcpos_string(struct srcpos *pos)
{
const char *fname = "<no-file>";
char *pos_str;
int rc;
if (pos)
fname = pos->file->name;
if (pos->first_line != pos->last_line)
rc = asprintf(&pos_str, "%s:%d.%d-%d.%d", fname,
pos->first_line, pos->first_column,
pos->last_line, pos->last_column);
else if (pos->first_column != pos->last_column)
rc = asprintf(&pos_str, "%s:%d.%d-%d", fname,
pos->first_line, pos->first_column,
pos->last_column);
else
rc = asprintf(&pos_str, "%s:%d.%d", fname,
pos->first_line, pos->first_column);
if (rc == -1)
die("Couldn't allocate in srcpos string");
return pos_str;
}
void
srcpos_verror(struct srcpos *pos, char const *fmt, va_list va)
{
const char *srcstr;
srcstr = srcpos_string(pos);
fprintf(stdout, "Error: %s ", srcstr);
vfprintf(stdout, fmt, va);
fprintf(stdout, "\n");
} }
void dtc_close_file(struct dtc_file *file) void
srcpos_error(struct srcpos *pos, char const *fmt, ...)
{ {
if (fclose(file->file)) va_list va;
die("Error closing \"%s\": %s\n", file->name, strerror(errno));
va_start(va, fmt);
srcpos_verror(pos, fmt, va);
va_end(va);
}
void
srcpos_warn(struct srcpos *pos, char const *fmt, ...)
{
const char *srcstr;
va_list va;
va_start(va, fmt);
srcstr = srcpos_string(pos);
fprintf(stderr, "Warning: %s ", srcstr);
vfprintf(stderr, fmt, va);
fprintf(stderr, "\n");
free(file->dir); va_end(va);
free(file);
} }
...@@ -17,69 +17,70 @@ ...@@ -17,69 +17,70 @@
* USA * USA
*/ */
/* #ifndef _SRCPOS_H_
* Augment the standard YYLTYPE with a filenum index into an #define _SRCPOS_H_
* array of all opened filenames.
*/
#include <stdio.h> #include <stdio.h>
struct dtc_file { struct srcfile_state {
FILE *f;
char *name;
char *dir; char *dir;
const char *name; int lineno, colno;
FILE *file; struct srcfile_state *prev;
}; };
#if ! defined(YYLTYPE) && ! defined(YYLTYPE_IS_DECLARED) extern struct srcfile_state *current_srcfile; /* = NULL */
typedef struct YYLTYPE {
FILE *srcfile_relative_open(const char *fname, char **fullnamep);
void srcfile_push(const char *fname);
int srcfile_pop(void);
struct srcpos {
int first_line; int first_line;
int first_column; int first_column;
int last_line; int last_line;
int last_column; int last_column;
struct dtc_file *file; struct srcfile_state *file;
} YYLTYPE; };
#define YYLTYPE_IS_DECLARED 1
#define YYLTYPE_IS_TRIVIAL 1
#endif
/* Cater to old parser templates. */
#ifndef YYID
#define YYID(n) (n)
#endif
#define YYLLOC_DEFAULT(Current, Rhs, N) \ #define YYLTYPE struct srcpos
do \
if (YYID (N)) \
{ \
(Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
(Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
(Current).last_line = YYRHSLOC (Rhs, N).last_line; \
(Current).last_column = YYRHSLOC (Rhs, N).last_column; \
(Current).file = YYRHSLOC (Rhs, N).file; \
} \
else \
{ \
(Current).first_line = (Current).last_line = \
YYRHSLOC (Rhs, 0).last_line; \
(Current).first_column = (Current).last_column = \
YYRHSLOC (Rhs, 0).last_column; \
(Current).file = YYRHSLOC (Rhs, 0).file; \
} \
while (YYID (0))
#define YYLLOC_DEFAULT(Current, Rhs, N) \
do { \
if (N) { \
(Current).first_line = YYRHSLOC(Rhs, 1).first_line; \
(Current).first_column = YYRHSLOC(Rhs, 1).first_column; \
(Current).last_line = YYRHSLOC(Rhs, N).last_line; \
(Current).last_column = YYRHSLOC (Rhs, N).last_column; \
(Current).file = YYRHSLOC(Rhs, N).file; \
} else { \
(Current).first_line = (Current).last_line = \
YYRHSLOC(Rhs, 0).last_line; \
(Current).first_column = (Current).last_column = \
YYRHSLOC(Rhs, 0).last_column; \
(Current).file = YYRHSLOC (Rhs, 0).file; \
} \
} while (0)
extern void yyerror(char const *); /*
extern void yyerrorf(char const *, ...) __attribute__((format(printf, 1, 2))); * Fictional source position used for IR nodes that are
* created without otherwise knowing a true source position.
* For example,constant definitions from the command line.
*/
extern struct srcpos srcpos_empty;
extern struct dtc_file *srcpos_file; extern void srcpos_update(struct srcpos *pos, const char *text, int len);
extern struct srcpos *srcpos_copy(struct srcpos *pos);
extern char *srcpos_string(struct srcpos *pos);
extern void srcpos_dump(struct srcpos *pos);
struct search_path { extern void srcpos_verror(struct srcpos *pos, char const *, va_list va)
const char *dir; /* NULL for current directory */ __attribute__((format(printf, 2, 0)));
struct search_path *prev, *next; extern void srcpos_error(struct srcpos *pos, char const *, ...)
}; __attribute__((format(printf, 2, 3)));
extern void srcpos_warn(struct srcpos *pos, char const *, ...)
__attribute__((format(printf, 2, 3)));
extern struct dtc_file *dtc_open_file(const char *fname, #endif /* _SRCPOS_H_ */
const struct search_path *search);
extern void dtc_close_file(struct dtc_file *file);
...@@ -32,8 +32,8 @@ struct boot_info *dt_from_source(const char *fname) ...@@ -32,8 +32,8 @@ struct boot_info *dt_from_source(const char *fname)
the_boot_info = NULL; the_boot_info = NULL;
treesource_error = 0; treesource_error = 0;
srcpos_file = dtc_open_file(fname, NULL); srcfile_push(fname);
yyin = srcpos_file->file; yyin = current_srcfile->f;
if (yyparse() != 0) if (yyparse() != 0)
die("Unable to parse input tree\n"); die("Unable to parse input tree\n");
...@@ -63,26 +63,20 @@ static void write_propval_string(FILE *f, struct data val) ...@@ -63,26 +63,20 @@ static void write_propval_string(FILE *f, struct data val)
{ {
const char *str = val.val; const char *str = val.val;
int i; int i;
int newchunk = 1;
struct marker *m = val.markers; struct marker *m = val.markers;
assert(str[val.len-1] == '\0'); assert(str[val.len-1] == '\0');
while (m && (m->offset == 0)) {
if (m->type == LABEL)
fprintf(f, "%s: ", m->ref);
m = m->next;
}
fprintf(f, "\"");
for (i = 0; i < (val.len-1); i++) { for (i = 0; i < (val.len-1); i++) {
char c = str[i]; char c = str[i];
if (newchunk) {
while (m && (m->offset <= i)) {
if (m->type == LABEL) {
assert(m->offset == i);
fprintf(f, "%s: ", m->ref);
}
m = m->next;
}
fprintf(f, "\"");
newchunk = 0;
}
switch (c) { switch (c) {
case '\a': case '\a':
fprintf(f, "\\a"); fprintf(f, "\\a");
...@@ -113,7 +107,14 @@ static void write_propval_string(FILE *f, struct data val) ...@@ -113,7 +107,14 @@ static void write_propval_string(FILE *f, struct data val)
break; break;
case '\0': case '\0':
fprintf(f, "\", "); fprintf(f, "\", ");
newchunk = 1; while (m && (m->offset < i)) {
if (m->type == LABEL) {
assert(m->offset == (i+1));
fprintf(f, "%s: ", m->ref);
}
m = m->next;
}
fprintf(f, "\"");
break; break;
default: default:
if (isprint(c)) if (isprint(c))
...@@ -234,10 +235,11 @@ static void write_tree_source_node(FILE *f, struct node *tree, int level) ...@@ -234,10 +235,11 @@ static void write_tree_source_node(FILE *f, struct node *tree, int level)
{ {
struct property *prop; struct property *prop;
struct node *child; struct node *child;
struct label *l;
write_prefix(f, level); write_prefix(f, level);
if (tree->label) for_each_label(tree->labels, l)
fprintf(f, "%s: ", tree->label); fprintf(f, "%s: ", l->label);
if (tree->name && (*tree->name)) if (tree->name && (*tree->name))
fprintf(f, "%s {\n", tree->name); fprintf(f, "%s {\n", tree->name);
else else
...@@ -245,8 +247,8 @@ static void write_tree_source_node(FILE *f, struct node *tree, int level) ...@@ -245,8 +247,8 @@ static void write_tree_source_node(FILE *f, struct node *tree, int level)
for_each_property(tree, prop) { for_each_property(tree, prop) {
write_prefix(f, level+1); write_prefix(f, level+1);
if (prop->label) for_each_label(prop->labels, l)
fprintf(f, "%s: ", prop->label); fprintf(f, "%s: ", l->label);
fprintf(f, "%s", prop->name); fprintf(f, "%s", prop->name);
write_propval(f, prop); write_propval(f, prop);
} }
...@@ -266,8 +268,10 @@ void dt_to_source(FILE *f, struct boot_info *bi) ...@@ -266,8 +268,10 @@ void dt_to_source(FILE *f, struct boot_info *bi)
fprintf(f, "/dts-v1/;\n\n"); fprintf(f, "/dts-v1/;\n\n");
for (re = bi->reservelist; re; re = re->next) { for (re = bi->reservelist; re; re = re->next) {
if (re->label) struct label *l;
fprintf(f, "%s: ", re->label);
for_each_label(re->labels, l)
fprintf(f, "%s: ", l->label);
fprintf(f, "/memreserve/\t0x%016llx 0x%016llx;\n", fprintf(f, "/memreserve/\t0x%016llx 0x%016llx;\n",
(unsigned long long)re->re.address, (unsigned long long)re->re.address,
(unsigned long long)re->re.size); (unsigned long long)re->re.size);
......
/*
* Copyright 2008 Jon Loeliger, Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include "util.h"
char *xstrdup(const char *s)
{
int len = strlen(s) + 1;
char *dup = xmalloc(len);
memcpy(dup, s, len);
return dup;
}
char *join_path(const char *path, const char *name)
{
int lenp = strlen(path);
int lenn = strlen(name);
int len;
int needslash = 1;
char *str;
len = lenp + lenn + 2;
if ((lenp > 0) && (path[lenp-1] == '/')) {
needslash = 0;
len--;
}
str = xmalloc(len);
memcpy(str, path, lenp);
if (needslash) {
str[lenp] = '/';
lenp++;
}
memcpy(str+lenp, name, lenn+1);
return str;
}
#ifndef _UTIL_H
#define _UTIL_H
/*
* Copyright 2008 Jon Loeliger, Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
static inline void __attribute__((noreturn)) die(char * str, ...)
{
va_list ap;
va_start(ap, str);
fprintf(stderr, "FATAL ERROR: ");
vfprintf(stderr, str, ap);
exit(1);
}
static inline void *xmalloc(size_t len)
{
void *new = malloc(len);
if (!new)
die("malloc() failed\n");
return new;
}
static inline void *xrealloc(void *p, size_t len)
{
void *new = realloc(p, len);
if (!new)
die("realloc() failed (len=%d)\n", len);
return new;
}
extern char *xstrdup(const char *s);
extern char *join_path(const char *path, const char *name);
#endif /* _UTIL_H */
#define DTC_VERSION "DTC 1.2.0" #define DTC_VERSION "DTC 1.2.0-g37c0b6a0"
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment