2019-05-27 09:55:05 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2007-12-18 07:06:42 +03:00
/*
* Copyright 2007 Jon Loeliger , Freescale Semiconductor , Inc .
*/
2010-11-18 02:28:20 +03:00
# define _GNU_SOURCE
# include <stdio.h>
2007-12-18 07:06:42 +03:00
# include "dtc.h"
# include "srcpos.h"
2012-09-29 01:25:59 +04:00
/* A node in our list of directories to search for source/include files */
struct search_path {
struct search_path * next ; /* next node in list, NULL for end */
const char * dirname ; /* name of directory to search */
} ;
/* This is the list of directories that we search for source files */
static struct search_path * search_path_head , * * search_path_tail ;
2018-11-29 03:37:35 +03:00
/* Detect infinite include recursion. */
2021-02-04 00:26:03 +03:00
# define MAX_SRCFILE_DEPTH (200)
2018-11-29 03:37:35 +03:00
static int srcfile_depth ; /* = 0 */
2007-12-18 07:06:42 +03:00
2015-04-30 00:00:05 +03:00
static char * get_dirname ( const char * path )
2010-11-18 02:28:20 +03:00
{
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 ;
}
2012-01-11 04:27:52 +04:00
FILE * depfile ; /* = NULL */
2010-11-18 02:28:20 +03:00
struct srcfile_state * current_srcfile ; /* = NULL */
2018-11-29 03:37:35 +03:00
static char * initial_path ; /* = NULL */
static int initial_pathlen ; /* = 0 */
static bool initial_cpp = true ;
2007-12-18 07:06:42 +03:00
2018-11-29 03:37:35 +03:00
static void set_initial_path ( char * fname )
{
int i , len = strlen ( fname ) ;
2010-11-18 02:28:20 +03:00
2018-11-29 03:37:35 +03:00
xasprintf ( & initial_path , " %s " , fname ) ;
initial_pathlen = 0 ;
for ( i = 0 ; i ! = len ; i + + )
if ( initial_path [ i ] = = ' / ' )
initial_pathlen + + ;
}
static char * shorten_to_initial_path ( char * fname )
{
char * p1 , * p2 , * prevslash1 = NULL ;
int slashes = 0 ;
for ( p1 = fname , p2 = initial_path ; * p1 & & * p2 ; p1 + + , p2 + + ) {
if ( * p1 ! = * p2 )
break ;
if ( * p1 = = ' / ' ) {
prevslash1 = p1 ;
slashes + + ;
}
}
p1 = prevslash1 + 1 ;
if ( prevslash1 ) {
int diff = initial_pathlen - slashes , i , j ;
int restlen = strlen ( fname ) - ( p1 - fname ) ;
char * res ;
res = xmalloc ( ( 3 * diff ) + restlen + 1 ) ;
for ( i = 0 , j = 0 ; i ! = diff ; i + + ) {
res [ j + + ] = ' . ' ;
res [ j + + ] = ' . ' ;
res [ j + + ] = ' / ' ;
}
strcpy ( res + j , p1 ) ;
return res ;
}
return NULL ;
}
2012-09-29 01:25:59 +04:00
/**
* Try to open a file in a given directory .
*
* If the filename is an absolute path , then dirname is ignored . If it is a
* relative path , then we look in that directory for the file .
*
* @ param dirname Directory to look in , or NULL for none
* @ param fname Filename to look for
* @ param fp Set to NULL if file did not open
* @ return allocated filename on success ( caller must free ) , NULL on failure
*/
static char * try_open ( const char * dirname , const char * fname , FILE * * fp )
{
char * fullname ;
if ( ! dirname | | fname [ 0 ] = = ' / ' )
fullname = xstrdup ( fname ) ;
else
fullname = join_path ( dirname , fname ) ;
2015-04-30 00:00:05 +03:00
* fp = fopen ( fullname , " rb " ) ;
2012-09-29 01:25:59 +04:00
if ( ! * fp ) {
free ( fullname ) ;
fullname = NULL ;
}
return fullname ;
}
/**
* Open a file for read access
*
* If it is a relative filename , we search the full search path for it .
*
* @ param fname Filename to open
* @ param fp Returns pointer to opened FILE , or NULL on failure
* @ return pointer to allocated filename , which caller must free
*/
static char * fopen_any_on_path ( const char * fname , FILE * * fp )
{
const char * cur_dir = NULL ;
struct search_path * node ;
char * fullname ;
/* Try current directory first */
assert ( fp ) ;
if ( current_srcfile )
cur_dir = current_srcfile - > dir ;
fullname = try_open ( cur_dir , fname , fp ) ;
/* Failing that, try each search path in turn */
for ( node = search_path_head ; ! * fp & & node ; node = node - > next )
fullname = try_open ( node - > dirname , fname , fp ) ;
return fullname ;
}
2010-11-18 02:28:20 +03:00
FILE * srcfile_relative_open ( const char * fname , char * * fullnamep )
2007-12-18 07:06:42 +03:00
{
2010-11-18 02:28:20 +03:00
FILE * f ;
2008-08-07 06:24:17 +04:00
char * fullname ;
2007-12-18 07:06:42 +03:00
2010-11-18 02:28:20 +03:00
if ( streq ( fname , " - " ) ) {
f = stdin ;
fullname = xstrdup ( " <stdin> " ) ;
2008-08-07 06:24:17 +04:00
} else {
2012-09-29 01:25:59 +04:00
fullname = fopen_any_on_path ( fname , & f ) ;
2010-11-18 02:28:20 +03:00
if ( ! f )
die ( " Couldn't open \" %s \" : %s \n " , fname ,
strerror ( errno ) ) ;
2008-08-07 06:24:17 +04:00
}
2007-12-18 07:06:42 +03:00
2012-01-11 04:27:52 +04:00
if ( depfile )
fprintf ( depfile , " %s " , fullname ) ;
2010-11-18 02:28:20 +03:00
if ( fullnamep )
* fullnamep = fullname ;
else
2008-08-07 06:24:17 +04:00
free ( fullname ) ;
2007-12-18 07:06:42 +03:00
2010-11-18 02:28:20 +03:00
return f ;
2007-12-18 07:06:42 +03:00
}
2010-11-18 02:28:20 +03:00
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 ) ;
2015-04-30 00:00:05 +03:00
srcfile - > dir = get_dirname ( srcfile - > name ) ;
2010-11-18 02:28:20 +03:00
srcfile - > prev = current_srcfile ;
srcfile - > lineno = 1 ;
srcfile - > colno = 1 ;
current_srcfile = srcfile ;
2018-11-29 03:37:35 +03:00
if ( srcfile_depth = = 1 )
set_initial_path ( srcfile - > name ) ;
2010-11-18 02:28:20 +03:00
}
2007-12-18 07:06:42 +03:00
2015-04-30 00:00:05 +03:00
bool srcfile_pop ( void )
2008-08-07 06:24:17 +04:00
{
2010-11-18 02:28:20 +03:00
struct srcfile_state * srcfile = current_srcfile ;
2007-12-18 07:06:42 +03:00
2010-11-18 02:28:20 +03:00
assert ( srcfile ) ;
2007-12-18 07:06:42 +03:00
2010-11-18 02:28:20 +03:00
current_srcfile = srcfile - > prev ;
2007-12-18 07:06:42 +03:00
2010-11-18 02:28:20 +03:00
if ( fclose ( srcfile - > f ) )
die ( " Error closing \" %s \" : %s \n " , srcfile - > name ,
strerror ( errno ) ) ;
2008-08-07 06:24:17 +04:00
2010-11-18 02:28:20 +03:00
/* FIXME: We allow the srcfile_state structure to leak,
* because it could still be referenced from a location
* variable being carried through the parser somewhere . To
* fix this we could either allocate all the files from a
* table , or use a pool allocator . */
2007-12-18 07:06:42 +03:00
2015-04-30 00:00:05 +03:00
return current_srcfile ? true : false ;
2010-11-18 02:28:20 +03:00
}
2007-12-18 07:06:42 +03:00
2012-09-29 01:25:59 +04:00
void srcfile_add_search_path ( const char * dirname )
{
struct search_path * node ;
/* Create the node */
node = xmalloc ( sizeof ( * node ) ) ;
node - > next = NULL ;
node - > dirname = xstrdup ( dirname ) ;
/* Add to the end of our list */
if ( search_path_tail )
* search_path_tail = node ;
else
search_path_head = node ;
search_path_tail = & node - > next ;
}
2010-11-18 02:28:20 +03:00
void srcpos_update ( struct srcpos * pos , const char * text , int len )
{
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 {
current_srcfile - > colno + + ;
}
pos - > last_line = current_srcfile - > lineno ;
pos - > last_column = current_srcfile - > colno ;
}
2008-08-07 06:24:17 +04:00
2010-11-18 02:28:20 +03:00
struct srcpos *
srcpos_copy ( struct srcpos * pos )
{
struct srcpos * pos_new ;
2018-11-29 03:37:35 +03:00
struct srcfile_state * srcfile_state ;
if ( ! pos )
return NULL ;
2008-08-07 06:24:17 +04:00
2010-11-18 02:28:20 +03:00
pos_new = xmalloc ( sizeof ( struct srcpos ) ) ;
2018-11-29 03:37:35 +03:00
assert ( pos - > next = = NULL ) ;
2010-11-18 02:28:20 +03:00
memcpy ( pos_new , pos , sizeof ( struct srcpos ) ) ;
2018-11-29 03:37:35 +03:00
/* allocate without free */
srcfile_state = xmalloc ( sizeof ( struct srcfile_state ) ) ;
memcpy ( srcfile_state , pos - > file , sizeof ( struct srcfile_state ) ) ;
pos_new - > file = srcfile_state ;
2010-11-18 02:28:20 +03:00
return pos_new ;
}
2018-11-29 03:37:35 +03:00
struct srcpos * srcpos_extend ( struct srcpos * pos , struct srcpos * newtail )
{
struct srcpos * p ;
if ( ! pos )
return newtail ;
for ( p = pos ; p - > next ! = NULL ; p = p - > next ) ;
p - > next = newtail ;
return pos ;
}
2010-11-18 02:28:20 +03:00
char *
srcpos_string ( struct srcpos * pos )
{
const char * fname = " <no-file> " ;
char * pos_str ;
2017-03-21 17:01:08 +03:00
if ( pos - > file & & pos - > file - > name )
2010-11-18 02:28:20 +03:00
fname = pos - > file - > name ;
if ( pos - > first_line ! = pos - > last_line )
2017-01-04 19:45:20 +03:00
xasprintf ( & pos_str , " %s:%d.%d-%d.%d " , fname ,
pos - > first_line , pos - > first_column ,
pos - > last_line , pos - > last_column ) ;
2010-11-18 02:28:20 +03:00
else if ( pos - > first_column ! = pos - > last_column )
2017-01-04 19:45:20 +03:00
xasprintf ( & pos_str , " %s:%d.%d-%d " , fname ,
pos - > first_line , pos - > first_column ,
pos - > last_column ) ;
2010-11-18 02:28:20 +03:00
else
2017-01-04 19:45:20 +03:00
xasprintf ( & pos_str , " %s:%d.%d " , fname ,
pos - > first_line , pos - > first_column ) ;
2010-11-18 02:28:20 +03:00
return pos_str ;
}
2018-11-29 03:37:35 +03:00
static char *
srcpos_string_comment ( struct srcpos * pos , bool first_line , int level )
{
char * pos_str , * fname , * first , * rest ;
bool fresh_fname = false ;
if ( ! pos ) {
if ( level > 1 ) {
xasprintf ( & pos_str , " <no-file>:<no-line> " ) ;
return pos_str ;
} else {
return NULL ;
}
}
if ( ! pos - > file )
fname = " <no-file> " ;
else if ( ! pos - > file - > name )
fname = " <no-filename> " ;
else if ( level > 1 )
fname = pos - > file - > name ;
else {
fname = shorten_to_initial_path ( pos - > file - > name ) ;
if ( fname )
fresh_fname = true ;
else
fname = pos - > file - > name ;
}
if ( level > 1 )
xasprintf ( & first , " %s:%d:%d-%d:%d " , fname ,
pos - > first_line , pos - > first_column ,
pos - > last_line , pos - > last_column ) ;
else
xasprintf ( & first , " %s:%d " , fname ,
first_line ? pos - > first_line : pos - > last_line ) ;
if ( fresh_fname )
free ( fname ) ;
if ( pos - > next ! = NULL ) {
rest = srcpos_string_comment ( pos - > next , first_line , level ) ;
xasprintf ( & pos_str , " %s, %s " , first , rest ) ;
free ( first ) ;
free ( rest ) ;
} else {
pos_str = first ;
}
return pos_str ;
}
char * srcpos_string_first ( struct srcpos * pos , int level )
{
return srcpos_string_comment ( pos , true , level ) ;
}
char * srcpos_string_last ( struct srcpos * pos , int level )
{
return srcpos_string_comment ( pos , false , level ) ;
}
2015-04-30 00:00:05 +03:00
void srcpos_verror ( struct srcpos * pos , const char * prefix ,
const char * fmt , va_list va )
2010-11-18 02:28:20 +03:00
{
2015-04-30 00:00:05 +03:00
char * srcstr ;
2010-11-18 02:28:20 +03:00
2015-04-30 00:00:05 +03:00
srcstr = srcpos_string ( pos ) ;
2007-12-18 07:06:42 +03:00
2015-04-30 00:00:05 +03:00
fprintf ( stderr , " %s: %s " , prefix , srcstr ) ;
vfprintf ( stderr , fmt , va ) ;
fprintf ( stderr , " \n " ) ;
2010-11-18 02:28:20 +03:00
2015-04-30 00:00:05 +03:00
free ( srcstr ) ;
2010-11-18 02:28:20 +03:00
}
2015-04-30 00:00:05 +03:00
void srcpos_error ( struct srcpos * pos , const char * prefix ,
const char * fmt , . . . )
2010-11-18 02:28:20 +03:00
{
va_list va ;
2008-08-07 06:24:17 +04:00
2015-04-30 00:00:05 +03:00
va_start ( va , fmt ) ;
srcpos_verror ( pos , prefix , fmt , va ) ;
2010-11-18 02:28:20 +03:00
va_end ( va ) ;
2007-12-18 07:06:42 +03:00
}
2012-09-29 01:25:59 +04:00
void srcpos_set_line ( char * f , int l )
{
current_srcfile - > name = f ;
current_srcfile - > lineno = l ;
2018-11-29 03:37:35 +03:00
if ( initial_cpp ) {
initial_cpp = false ;
set_initial_path ( f ) ;
}
2012-09-29 01:25:59 +04:00
}