📄 builtins.c
字号:
/* For globbing, we unconditionally ignore current and parent
directory items. Since they items always exist, there's not
reason why caller of GLOB would want to see them.
We could also change file_dirscan, but then paths with embedded
"." and ".." won't work anywhere.
*/
if (strcmp(f.f_base.ptr, ".") == 0 || strcmp(f.f_base.ptr, "..") == 0)
return;
string_new( buf );
path_build( &f, buf, 0 );
if (globbing->case_insensitive) {
downcase_inplace( buf->value );
}
for( l = globbing->patterns; l; l = l->next )
{
if( !glob( l->string, buf->value ) )
{
globbing->results = list_new( globbing->results, newstr( file ) );
break;
}
}
string_free( buf );
}
static LIST* downcase_list( LIST *in )
{
LIST* result = 0;
string s[1];
string_new( s );
while (in)
{
string_copy( s, in->string );
downcase_inplace( s->value );
result = list_append( result, list_new( 0, newstr( s->value ) ) );
in = in->next;
}
string_free( s );
return result;
}
LIST *
builtin_glob(
PARSE *parse,
FRAME *frame )
{
LIST *l = lol_get( frame->args, 0 );
LIST *r = lol_get( frame->args, 1 );
struct globbing globbing;
globbing.results = L0;
globbing.patterns = r;
globbing.case_insensitive
# if defined( OS_NT ) || defined( OS_CYGWIN )
= l; /* always case-insensitive if any files can be found */
# else
= lol_get( frame->args, 2 );
# endif
if ( globbing.case_insensitive )
{
globbing.patterns = downcase_list( r );
}
for( ; l; l = list_next( l ) )
file_dirscan( l->string, builtin_glob_back, &globbing );
if ( globbing.case_insensitive )
{
list_free( globbing.patterns );
}
return globbing.results;
}
static int has_wildcards(const char* str)
{
size_t index = strcspn(str, "[]*?");
if (str[index] == '\0')
return 0;
else
return 1;
}
/** If 'file' exists, append 'file' to 'list'.
Returns 'list'.
*/
static LIST* append_if_exists(LIST* list, char* file)
{
time_t time;
timestamp(file, &time);
if (time > 0)
return list_new(list, newstr(file));
else
return list;
}
LIST* glob1(char* dirname, char* pattern)
{
LIST* plist = list_new(L0, pattern);
struct globbing globbing;
globbing.results = L0;
globbing.patterns = plist;
globbing.case_insensitive
# if defined( OS_NT ) || defined( OS_CYGWIN )
= plist; /* always case-insensitive if any files can be found */
# else
= L0;
# endif
if ( globbing.case_insensitive )
{
globbing.patterns = downcase_list( plist );
}
file_dirscan( dirname, builtin_glob_back, &globbing );
if ( globbing.case_insensitive )
{
list_free( globbing.patterns );
}
list_free(plist);
return globbing.results;
}
LIST* glob_recursive(char* pattern)
{
LIST* result = L0;
/* Check if there's metacharacters in pattern */
if (!has_wildcards(pattern))
{
/* No metacharacters. Check if the path exists. */
result = append_if_exists(result, pattern);
}
else
{
/* Have metacharacters in the pattern. Split into dir/name */
PATHNAME path[1];
path_parse(pattern, path);
if (path->f_dir.ptr)
{
LIST* dirs = L0;
string dirname[1];
string basename[1];
string_new(dirname);
string_new(basename);
string_append_range(dirname, path->f_dir.ptr,
path->f_dir.ptr + path->f_dir.len);
path->f_grist.ptr = 0;
path->f_grist.len = 0;
path->f_dir.ptr = 0;
path->f_dir.len = 0;
path_build(path, basename, 0);
if (has_wildcards(dirname->value))
{
dirs = glob_recursive(dirname->value);
}
else
{
dirs = list_new(dirs, dirname->value);
}
if (has_wildcards(basename->value))
{
for(; dirs; dirs = dirs->next)
{
result = list_append(result,
glob1(dirs->string, basename->value));
}
}
else
{
string file_string[1];
string_new(file_string);
/** No wildcard in basename. */
for(; dirs; dirs = dirs->next)
{
path->f_dir.ptr = dirs->string;
path->f_dir.len = strlen(dirs->string);
path_build(path, file_string, 0);
result = append_if_exists(result, file_string->value);
string_truncate(file_string, 0);
}
string_free(file_string);
}
string_free(dirname);
string_free(basename);
}
else
{
/** No directory, just a pattern. */
result = list_append(result, glob1(".", pattern));
}
}
return result;
}
LIST *
builtin_glob_recursive(
PARSE *parse,
FRAME *frame )
{
LIST* result = L0;
LIST* l = lol_get( frame->args, 0 );
for(; l; l = l->next)
{
result = list_append(result, glob_recursive(l->string));
}
return result;
}
/*
* builtin_match() - MATCH rule, regexp matching
*/
LIST *
builtin_match(
PARSE *parse,
FRAME *frame )
{
LIST *l, *r;
LIST *result = 0;
string buf[1];
string_new(buf);
/* For each pattern */
for( l = lol_get( frame->args, 0 ); l; l = l->next )
{
/* Result is cached and intentionally never freed */
regexp *re = regex_compile( l->string );
/* For each string to match against */
for( r = lol_get( frame->args, 1 ); r; r = r->next )
{
if( regexec( re, r->string ) )
{
int i, top;
/* Find highest parameter */
for( top = NSUBEXP; top-- > 1; )
if( re->startp[top] )
break;
/* And add all parameters up to highest onto list. */
/* Must have parameters to have results! */
for( i = 1; i <= top; i++ )
{
string_append_range( buf, re->startp[i], re->endp[i] );
result = list_new( result, newstr( buf->value ) );
string_truncate( buf, 0 );
}
}
}
}
string_free( buf );
return result;
}
LIST *
builtin_hdrmacro(
PARSE *parse,
FRAME *frame )
{
LIST* l = lol_get( frame->args, 0 );
for ( ; l; l = list_next(l) )
{
TARGET* t = bindtarget( l->string );
/* scan file for header filename macro definitions */
if ( DEBUG_HEADER )
printf( "scanning '%s' for header file macro definitions\n",
l->string );
macro_headers( t );
}
return L0;
}
/* builtin_rulenames() - RULENAMES ( MODULE ? )
*
* Returns a list of the non-local rule names in the given MODULE. If
* MODULE is not supplied, returns the list of rule names in the
* global module.
*/
/* helper function for builtin_rulenames(), below */
static void add_rule_name( void* r_, void* result_ )
{
RULE* r = (RULE*)r_;
LIST** result = (LIST**)result_;
if ( r->exported )
*result = list_new( *result, copystr( r->name ) );
}
LIST *
builtin_rulenames(
PARSE *parse,
FRAME *frame )
{
LIST *arg0 = lol_get( frame->args, 0 );
LIST *result = L0;
module_t* source_module = bindmodule( arg0 ? arg0->string : 0 );
if ( source_module->rules )
hashenumerate( source_module->rules, add_rule_name, &result );
return result;
}
/* builtin_varnames() - VARNAMES ( MODULE ? )
*
* Returns a list of the variable names in the given MODULE. If
* MODULE is not supplied, returns the list of variable names in the
* global module.
*/
/* helper function for builtin_varnames(), below. Used with
* hashenumerate, will prepend the key of each element to a list
*/
static void add_hash_key( void* np, void* result_ )
{
LIST** result = (LIST**)result_;
*result = list_new( *result, copystr( *(char**)np ) );
}
LIST *
builtin_varnames(
PARSE *parse,
FRAME *frame )
{
LIST *arg0 = lol_get( frame->args, 0 );
LIST *result = L0;
module_t* source_module = bindmodule( arg0 ? arg0->string : 0 );
if ( source_module->variables )
hashenumerate( source_module->variables, add_hash_key, &result );
return result;
}
/*
* builtin_delete_module() - MODULE ?
*
* Clears all rules and variables from the given module.
*/
LIST *
builtin_delete_module(
PARSE *parse,
FRAME *frame )
{
LIST *arg0 = lol_get( frame->args, 0 );
LIST *result = L0;
module_t* source_module = bindmodule( arg0 ? arg0->string : 0 );
delete_module( source_module );
return result;
}
static void unknown_rule( FRAME *frame, char* key, char *module_name, char *rule_name )
{
backtrace_line( frame->prev );
printf( "%s error: rule \"%s\" unknown in module \"%s\"\n", key, rule_name, module_name );
backtrace( frame->prev );
exit(1);
}
/*
* builtin_import() - IMPORT ( SOURCE_MODULE ? : SOURCE_RULES * : TARGET_MODULE ? : TARGET_RULES * : LOCALIZE ? )
*
* The IMPORT rule imports rules from the SOURCE_MODULE into the
* TARGET_MODULE as local rules. If either SOURCE_MODULE or
* TARGET_MODULE is not supplied, it refers to the global
* module. SOURCE_RULES specifies which rules from the SOURCE_MODULE
* to import; TARGET_RULES specifies the names to give those rules in
* TARGET_MODULE. If SOURCE_RULES contains a name which doesn't
* correspond to a rule in SOURCE_MODULE, or if it contains a
* different number of items than TARGET_RULES, an error is issued.
* if LOCALIZE is specified, the rules will be executed in
* TARGET_MODULE, with corresponding access to its module local
* variables.
*/
LIST *
builtin_import(
PARSE *parse,
FRAME *frame )
{
LIST *source_module_list = lol_get( frame->args, 0 );
LIST *source_rules = lol_get( frame->args, 1 );
LIST *target_module_list = lol_get( frame->args, 2 );
LIST *target_rules = lol_get( frame->args, 3 );
LIST *localize = lol_get( frame->args, 4 );
module_t* target_module = bindmodule( target_module_list ? target_module_list->string : 0 );
module_t* source_module = bindmodule( source_module_list ? source_module_list->string : 0 );
LIST *source_name, *target_name;
for ( source_name = source_rules, target_name = target_rules;
source_name && target_name;
source_name = list_next( source_name )
, target_name = list_next( target_name ) )
{
RULE r_, *r = &r_, *imported;
r_.name = source_name->string;
if ( !source_module->rules
|| !hashcheck( source_module->rules, (HASHDATA**)&r )
)
{
unknown_rule( frame, "IMPORT", source_module->name, r_.name );
}
imported = import_rule( r, target_module, target_name->string );
if ( localize )
imported->module = target_module;
imported->exported = 0; /* this rule is really part of some other module; just refer to it here, but don't let it out */
}
if ( source_name || target_name )
{
backtrace_line( frame->prev );
printf( "import error: length of source and target rule name lists don't match!\n" );
printf( " source: " );
list_print( source_rules );
printf( "\n target: " );
list_print( target_rules );
printf( "\n" );
backtrace( frame->prev );
exit(1);
}
return L0;
}
/*
* builtin_export() - EXPORT ( MODULE ? : RULES * )
*
* The EXPORT rule marks RULES from the SOURCE_MODULE as non-local
* (and thus exportable). If an element of RULES does not name a rule
* in MODULE, an error is issued.
*/
LIST *
builtin_export(
PARSE *parse,
FRAME *frame )
{
LIST *module_list = lol_get( frame->args, 0 );
LIST *rules = lol_get( frame->args, 1 );
module_t* m = bindmodule( module_list ? module_list->string : 0 );
for ( ; rules; rules = list_next( rules ) )
{
RULE r_, *r = &r_;
r_.name = rules->string;
if ( !m->rules || !hashcheck( m->rules, (HASHDATA**)&r ) )
unknown_rule( frame, "EXPORT", m->name, r_.name );
r->exported = 1;
}
return L0;
}
/* Retrieve the file and line number that should be indicated for a
* given procedure in debug output or an error backtrace
*/
static void get_source_line( PARSE* procedure, char** file, int* line )
{
if ( procedure )
{
char* f = procedure->file;
int l = procedure->line;
if ( !strcmp( f, "+" ) )
{
f = "jambase.c";
l += 3;
}
*file = f;
*line = l;
}
else
{
*file = "(builtin)";
*line = -1;
}
}
void print_source_line( PARSE* p )
{
char* file;
int line;
get_source_line( p, &file, &line );
if ( line < 0 )
printf( "(builtin):" );
else
printf( "%s:%d:", file, line);
}
/* Print a single line of error backtrace for the given frame */
void backtrace_line( FRAME *frame )
{
if ( frame == 0 )
{
printf( "(no frame):" );
}
else
{
print_source_line( frame->procedure );
printf( " in %s\n", frame->rulename );
}
}
/* Print the entire backtrace from the given frame to the Jambase
* which invoked it.
*/
void backtrace( FRAME *frame )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -