2026-01-14 23:56:35 +01:00
# define CONFIG_FILE "IBUILD"
# define MAX_STATEMENTS 50
# define MAX_TOKENS 200
# define MAX_FILES_IN_DIR 100
# define MAX_C_FILES 200
# define MAX_H_FILES 200
# define MAX_CPP_FILES 200
2026-01-09 21:29:18 +01:00
# include "deps/utils/src/arena_alloc.h"
# include <stdio.h>
# include <stdlib.h>
# include <sys/wait.h>
# include <unistd.h>
# include <string.h>
2026-01-10 15:43:52 +01:00
# include <errno.h>
# include <stdarg.h>
2026-01-14 23:56:35 +01:00
# include <assert.h>
# include <dirent.h>
2026-01-13 23:32:03 +01:00
2026-01-10 15:43:52 +01:00
# define DIE(fmt, ...) die_t(__func__, __LINE__, fmt, ##__VA_ARGS__)
2026-01-13 23:32:03 +01:00
# define LOG_ERROR(fmt, ...) log_write(__func__, fmt, ## __VA_ARGS__)
# define LOG_USER(fmt, ...) log_write(NULL, fmt, ## __VA_ARGS__)
/*** allocated memory ***/
// There shall never be another heap allocation outside of thy block.
// Each system and/or type of allocation shall have its own memory.
// There shall be no arena managed in this state, if the allocated memory is redundant and will not affect performance.
// Arenas shall never be arena_free'd during program execution, only before exit. Use arena_reset if you wish to achieve
// the same functionality without free() calls.
typedef struct
{
Arena file_contents ;
Arena configuration ;
Arena strings ;
Arena parser ;
2026-01-14 23:56:35 +01:00
Arena discovery ;
2026-01-13 23:32:03 +01:00
} Memory ;
static Memory memory ;
void memory_free ( )
{
arena_free ( & memory . file_contents ) ;
arena_free ( & memory . configuration ) ;
arena_free ( & memory . strings ) ;
arena_free ( & memory . parser ) ;
2026-01-14 23:56:35 +01:00
arena_free ( & memory . discovery ) ;
2026-01-13 23:32:03 +01:00
}
/*** logging ***/
2026-01-10 15:43:52 +01:00
// Developer-reporting error interface, along with steps to reproduce the error.
// Include this log in your issues
void die_t ( const char * func , int line , const char * fmt , . . . )
{
2026-01-14 23:56:35 +01:00
assert ( func ! = NULL ) ;
assert ( fmt ! = NULL ) ;
2026-01-10 15:43:52 +01:00
va_list args ;
va_start ( args , fmt ) ;
2026-01-13 23:32:03 +01:00
printf ( " ibuild exception(f:%s-l:%d): " , func , line ) ;
2026-01-10 15:43:52 +01:00
vprintf ( fmt , args ) ;
printf ( " \n " ) ;
printf ( " ******Last syscall error: %s \n " , strerror ( errno ) ) ;
2026-01-14 23:56:35 +01:00
va_end ( args ) ;
2026-01-10 15:43:52 +01:00
exit ( 1 ) ;
}
2026-01-09 21:29:18 +01:00
2026-01-13 23:32:03 +01:00
// User-reporting interface
// func_name: MSG
void log_write ( const char * func , const char * fmt , . . . )
2026-01-09 21:29:18 +01:00
{
2026-01-13 23:32:03 +01:00
if ( fmt = = NULL ) DIE ( " fmt must not be null! " ) ;
2026-01-10 15:43:52 +01:00
va_list args ;
va_start ( args , fmt ) ;
2026-01-13 23:32:03 +01:00
if ( func ! = NULL )
printf ( " %s: " , func ) ;
2026-01-10 15:43:52 +01:00
vprintf ( fmt , args ) ;
printf ( " \n " ) ;
va_end ( args ) ;
2026-01-09 21:29:18 +01:00
}
2026-01-13 23:32:03 +01:00
/*** file management ***/
2026-01-14 23:56:35 +01:00
typedef struct
{
const char * path ;
unsigned char type ;
} DirEntry ;
int dirent_get_next ( DIR * d , DirEntry * e , const char * p )
{
assert ( d ! = NULL ) ;
struct dirent * file = readdir ( d ) ;
if ( file = = NULL )
return 1 ;
switch ( file - > d_type )
{
case DT_DIR :
e - > type = DT_DIR ;
break ;
case DT_REG :
e - > type = DT_REG ;
break ;
default :
return 1 ;
}
size_t fs = strlen ( file - > d_name ) ;
char * buf = ( char * ) arena_alloc ( & memory . strings , fs + 1 ) ;
memcpy ( buf , file - > d_name , fs + 1 ) ;
buf [ fs ] = ' \0 ' ;
e - > path = buf ;
return 0 ;
}
size_t dirent_get_recursive ( const char * p )
{
if ( p = = NULL ) DIE ( " p must not be NULL " ) ;
DIR * dir = opendir ( p ) ;
DirEntry current ;
size_t count = 0 ;
while ( dirent_get_next ( dir , & current , p ) = = 0 )
{
if ( current . type = = DT_DIR & & ( strcmp ( current . path , " . " ) = = 0 | | strcmp ( current . path , " .. " ) = = 0 | | strcmp ( current . path , " .git " ) = = 0 ) )
continue ;
DirEntry * ptr = ( DirEntry * ) arena_alloc ( & memory . discovery , sizeof ( DirEntry ) ) ;
size_t size = strlen ( current . path ) + 2 + strlen ( p ) ;
char * buf = ( char * ) arena_alloc ( & memory . strings , size ) ;
snprintf ( buf , size , " %s/%s " , p , current . path ) ;
current . path = buf ;
* ptr = current ;
count + + ;
if ( current . type = = DT_DIR )
{
count + = dirent_get_recursive ( buf ) ;
continue ;
}
}
closedir ( dir ) ;
return count ;
}
2026-01-13 23:32:03 +01:00
long file_get_size ( FILE * fd )
{
if ( fd = = NULL ) DIE ( " fd cannot be NULL. " ) ;
if ( fseek ( fd , 0 , SEEK_END ) ! = 0 ) DIE ( " file exists, fseek SEEK_END fail. " ) ;
long size = ftell ( fd ) ;
if ( fseek ( fd , 0 , SEEK_SET ) ! = 0 ) DIE ( " file exists, fseek SEEK_SET fail. " ) ;
return size ;
}
char * file_get_content ( Arena * a , const char * fp )
{
if ( fp = = NULL ) DIE ( " fp cannot be NULL " ) ;
FILE * fd = fopen ( fp , " r " ) ;
long size = file_get_size ( fd ) ;
char * buf = ( char * ) arena_alloc ( a , size + 1 ) ;
size_t ret = fread ( buf , size , 1 , fd ) ;
if ( ret ! = 1 ) DIE ( " fread returned %d " , ret ) ;
buf [ size ] = ' \0 ' ;
return buf ;
}
bool file_has_r_access ( const char * f )
{
if ( access ( f , F_OK | R_OK ) = = 0 )
return true ;
return false ;
}
2026-01-14 23:56:35 +01:00
/*** discovery phase ***/
typedef struct
{
DirEntry * * c_files ;
DirEntry * * h_files ;
DirEntry * * cpp_files ;
DirEntry * * o_files ;
} Discovery ;
void discover ( Discovery * d )
{
size_t amount = dirent_get_recursive ( " . " ) ;
if ( amount = = 0 ) DIE ( " Directory is empty! If you have symlinks in the directory, ibuild does not support them. " ) ;
size_t c_c = 0 ;
size_t h_c = 0 ;
size_t cpp_c = 0 ;
for ( size_t i = 0 ; i < amount ; i + + )
{
char * current = NULL ;
if ( ( current = strrchr ( ( ( DirEntry * ) memory . discovery . start ) [ i ] . path , ' . ' ) ) = = NULL )
continue ;
DirEntry * current_dirent = & ( ( DirEntry * ) memory . discovery . start ) [ i ] ;
if ( strcmp ( current , " .c " ) = = 0 )
{
if ( c_c > MAX_C_FILES )
DIE ( " Maximum C file limit was reached with the ibuild project. To extend, you must edit the source code and decide whether there is enough memory. " ) ;
d - > c_files [ c_c ] = current_dirent ;
c_c + + ;
}
else if ( strcmp ( current , " .h " ) = = 0 )
{
if ( h_c > MAX_H_FILES )
DIE ( " Maximum H file limit was reached with the ibuild project. To extend, you must edit the source code and decide whether there is enough memory. " ) ;
d - > h_files [ h_c ] = current_dirent ;
h_c + + ;
} else if ( strcmp ( current , " .cpp " ) = = 0 )
{
if ( cpp_c > MAX_CPP_FILES )
DIE ( " Maximum CPP file limit was reached with the ibuild project. To extend, you must edit the source code and decide whether there is enough memory. " ) ;
d - > cpp_files [ cpp_c ] = current_dirent ;
cpp_c + + ;
}
}
LOG_USER ( " Found %d C files, %d H files, %d CPP files. " , c_c , h_c , cpp_c ) ;
}
2026-01-13 23:32:03 +01:00
/*** compilation process ***/
2026-01-09 21:29:18 +01:00
typedef struct
{
char * compiler_path ;
char * build_dir ;
char * target_exec ;
char * src_dir ;
2026-01-14 23:56:35 +01:00
char * * src_files ;
2026-01-09 21:29:18 +01:00
char * version ;
2026-01-13 23:32:03 +01:00
char * dep_searcher ;
char * dep_searcher_flags ;
} Configuration ;
2026-01-09 21:29:18 +01:00
2026-01-13 23:32:03 +01:00
void launch_compile ( Configuration * co )
2026-01-09 21:29:18 +01:00
{
2026-01-13 23:32:03 +01:00
if ( co = = NULL ) DIE ( " co has to be valid " ) ;
if ( co - > compiler_path = = NULL ) DIE ( " requires a valid compiler path " ) ;
2026-01-14 23:56:35 +01:00
int fildes [ 2 ] ;
pipe ( fildes ) ;
2026-01-09 21:29:18 +01:00
pid_t p = fork ( ) ;
if ( p < 0 )
2026-01-10 15:43:52 +01:00
{
2026-01-13 23:32:03 +01:00
DIE ( " fork error " ) ;
2026-01-10 15:43:52 +01:00
}
2026-01-09 21:29:18 +01:00
else if ( p = = 0 )
2026-01-10 15:43:52 +01:00
{
char * args [ ] = { co - > compiler_path , " ibuild.c " , " -o " , co - > target_exec , NULL } ;
2026-01-14 23:56:35 +01:00
close ( STDOUT_FILENO ) ;
dup ( fildes [ 1 ] ) ;
close ( fildes [ 0 ] ) ;
close ( fildes [ 1 ] ) ;
2026-01-10 15:43:52 +01:00
if ( ( execvp ( co - > compiler_path , args ) ) = = - 1 )
DIE ( " launch_compile() execvp error " ) ;
2026-01-14 23:56:35 +01:00
exit ( 0 ) ;
2026-01-10 15:43:52 +01:00
}
}
2026-01-09 21:29:18 +01:00
/*** configuration lexer ***/
typedef struct
{
char * src ;
} Tokenizer ;
typedef enum
{
T_INVALID = - 1 ,
T_IDENTIFIER = 0 ,
T_STRING = 1 ,
T_IS = 2 ,
T_EOF = 3 ,
} TokenType ;
typedef struct
{
TokenType type ;
char * value ;
int line ;
} Token ;
# define TOKEN_CONST {T_INVALID, NULL, 0}
bool is_alpha_uppercase ( char s )
{
return ( s > = ' A ' & & s < = ' Z ' ) ;
}
bool is_alpha_lowercase ( char s )
{
return ( s > = ' a ' & & s < = ' z ' ) ;
}
bool is_whitespace ( char s )
{
return s = = ' ' | | s = = ' \t ' | | s = = ' \r ' | | s = = ' \n ' ;
}
bool is_part_of_key ( char s )
{
return is_alpha_uppercase ( s ) | | s = = ' _ ' ;
}
size_t skip_group ( Tokenizer * t , bool ( * func ) ( char ) )
{
2026-01-14 23:56:35 +01:00
assert ( func ! = NULL ) ;
2026-01-09 21:29:18 +01:00
size_t len = 0 ;
while ( func ( * t - > src ) )
{
len + + ;
t - > src + = 1 ;
}
return len ;
}
Token tokenize_identifier ( Tokenizer * t )
{
char * temp = t - > src ;
size_t len = skip_group ( t , & is_part_of_key ) ;
2026-01-13 23:32:03 +01:00
char * buf = ( char * ) arena_alloc ( & memory . strings , sizeof ( char ) * len + 1 ) ;
2026-01-09 21:29:18 +01:00
memcpy ( buf , temp , len ) ;
buf [ len ] = ' \0 ' ;
return ( Token ) { T_IDENTIFIER , buf } ;
}
Token tokenize_string ( Tokenizer * t )
{
t - > src + = 1 ;
char * temp = t - > src ;
size_t len = 0 ;
while ( * t - > src ! = ' " ' & & * t - > src ! = ' \0 ' )
{
len + + ;
t - > src + = 1 ;
}
if ( * t - > src = = ' " ' ) t - > src + + ;
2026-01-13 23:32:03 +01:00
char * buf = ( char * ) arena_alloc ( & memory . strings , ( sizeof ( char ) * len ) + 1 ) ;
2026-01-09 21:29:18 +01:00
memcpy ( buf , temp , len ) ;
buf [ len ] = ' \0 ' ;
return ( Token ) { T_STRING , buf } ;
}
Token tokenizer_next ( Tokenizer * t )
{
if ( is_whitespace ( * t - > src ) ) skip_group ( t , & is_whitespace ) ;
if ( is_alpha_uppercase ( * t - > src ) )
{
return tokenize_identifier ( t ) ;
}
switch ( * t - > src )
{
case ' " ' :
return tokenize_string ( t ) ;
case ' = ' :
t - > src + + ;
return ( Token ) { T_IS , NULL } ;
}
if ( * t - > src = = ' \0 ' ) return ( Token ) { T_EOF , NULL } ;
t - > src + + ;
return ( Token ) { T_INVALID , NULL } ;
}
2026-01-14 23:56:35 +01:00
size_t tokenizer_tokenize ( Tokenizer * t , Token * ts )
{
size_t t_count = 0 ;
while ( 1 )
{
if ( t_count > MAX_TOKENS ) DIE ( " Maximum number of tokens reached! \n Could not read configuration file. " ) ;
Token token = tokenizer_next ( t ) ;
if ( token . type = = T_INVALID ) DIE ( " illegal token! " ) ;
ts [ t_count ] = token ;
t_count + + ;
if ( token . type = = T_EOF ) break ;
}
return t_count ;
}
2026-01-09 21:29:18 +01:00
/*** configuration parser ***/
typedef enum
{
2026-01-09 23:03:27 +01:00
K_NA = - 1 ,
2026-01-09 21:29:18 +01:00
K_UNKNOWN = 0 ,
K_COMPILER_PATH = 1 ,
K_SRC_DIR = 2 ,
2026-01-10 15:43:52 +01:00
K_SRC_FILES = 3 ,
K_BUILD_DIR = 4 ,
K_TARGET_EXEC = 5 ,
2026-01-13 23:32:03 +01:00
K_DEP_SEARCHER = 6 ,
K_DEP_SEARCHER_FLAGS = 7 ,
K_VERSION = 8 ,
2026-01-09 21:29:18 +01:00
} Key ;
typedef enum
{
N_STRING = 0 ,
2026-01-10 15:43:52 +01:00
N_ARRAY = 1 ,
N_PAIR = 2 ,
2026-01-09 21:29:18 +01:00
} NodeType ;
typedef struct
{
NodeType type ;
Key key ;
void * value ;
} Node ;
typedef struct
{
2026-01-13 23:32:03 +01:00
Token * tokens ;
2026-01-09 21:29:18 +01:00
size_t loc ;
size_t cap ;
} Parser ;
typedef struct
{
Key key ;
const char * value ;
} KeyMap ;
static KeyMap keyword_mappings [ ] = {
{ K_COMPILER_PATH , " COMPILER_PATH " } ,
{ K_SRC_DIR , " SRC_DIR " } ,
2026-01-10 15:43:52 +01:00
{ K_SRC_FILES , " SRC_FILES " } ,
2026-01-09 21:29:18 +01:00
{ K_BUILD_DIR , " BUILD_DIR " } ,
2026-01-09 23:03:27 +01:00
{ K_TARGET_EXEC , " TARGET_EXEC " } ,
2026-01-13 23:32:03 +01:00
{ K_DEP_SEARCHER , " DEP_SEARCHER " } ,
{ K_DEP_SEARCHER_FLAGS , " DEP_SEARCHER_FLAGS " } ,
2026-01-09 21:29:18 +01:00
{ K_UNKNOWN , NULL } ,
} ;
Key key_lookup ( char * s )
{
if ( s = = NULL ) return K_UNKNOWN ;
for ( const KeyMap * ptr = keyword_mappings ; ptr - > value ! = NULL ; ptr + + )
{
if ( strcmp ( ptr - > value , s ) = = 0 )
{
return ptr - > key ;
}
}
return K_UNKNOWN ;
}
Token parser_peek ( Parser * p , size_t o )
{
if ( p - > loc + o > = p - > cap )
{
2026-01-13 23:32:03 +01:00
return p - > tokens [ p - > loc - 1 ] ;
2026-01-09 21:29:18 +01:00
}
2026-01-13 23:32:03 +01:00
Token t = p - > tokens [ p - > loc + o ] ;
return t ;
2026-01-09 21:29:18 +01:00
}
Token parser_previous ( Parser * p )
{
if ( p - > loc - 1 < 0 )
{
2026-01-10 15:43:52 +01:00
DIE ( " parser logic error. " ) ;
2026-01-09 21:29:18 +01:00
}
2026-01-13 23:32:03 +01:00
return p - > tokens [ p - > loc - 1 ] ;
2026-01-09 21:29:18 +01:00
}
Token parser_advance ( Parser * p )
{
if ( p - > loc + 1 > = p - > cap )
{
2026-01-13 23:32:03 +01:00
return p - > tokens [ p - > loc ] ;
2026-01-09 21:29:18 +01:00
}
p - > loc + + ;
2026-01-13 23:32:03 +01:00
return p - > tokens [ p - > loc ] ;
2026-01-09 23:03:27 +01:00
}
Token parser_expect ( Parser * p , TokenType tt , char * s )
{
2026-01-14 23:56:35 +01:00
assert ( p ! = NULL ) ;
assert ( s ! = NULL ) ;
2026-01-09 23:03:27 +01:00
if ( parser_peek ( p , 1 ) . type ! = tt )
2026-01-10 15:43:52 +01:00
DIE ( s ) ;
2026-01-09 23:03:27 +01:00
return parser_advance ( p ) ;
2026-01-09 21:29:18 +01:00
}
Node * parser_expression ( Parser * p )
{
2026-01-09 23:03:27 +01:00
Token t = parser_advance ( p ) ;
2026-01-09 21:29:18 +01:00
if ( t . type = = T_STRING )
{
2026-01-13 23:32:03 +01:00
Node * node = ( Node * ) arena_alloc ( & memory . parser , sizeof ( Node ) ) ;
2026-01-09 23:03:27 +01:00
node - > key = K_NA ;
2026-01-09 21:29:18 +01:00
node - > value = ( void * ) t . value ;
node - > type = N_STRING ;
2026-01-09 23:03:27 +01:00
parser_advance ( p ) ;
2026-01-09 21:29:18 +01:00
return node ;
}
2026-01-10 15:43:52 +01:00
DIE ( " Syntax error: Invalid expression. " ) ;
2026-01-09 21:29:18 +01:00
}
Node * parser_statement ( Parser * p )
{
2026-01-09 23:03:27 +01:00
Token t = parser_peek ( p , 0 ) ;
2026-01-09 21:29:18 +01:00
if ( t . type = = T_IDENTIFIER )
{
Key k = key_lookup ( t . value ) ;
2026-01-10 15:43:52 +01:00
if ( k = = K_UNKNOWN ) DIE ( " Syntax error: Unexpected identifer encountered " ) ;
2026-01-09 23:03:27 +01:00
parser_expect ( p , T_IS , " Syntax error: Expected '=' after identifier " ) ;
2026-01-09 21:29:18 +01:00
Node * expression = parser_expression ( p ) ;
2026-01-13 23:32:03 +01:00
Node * node = ( Node * ) arena_alloc ( & memory . parser , sizeof ( Node ) ) ;
2026-01-09 21:29:18 +01:00
node - > key = k ;
node - > value = ( void * ) expression ;
node - > type = N_PAIR ;
2026-01-13 23:32:03 +01:00
return node ;
2026-01-09 21:29:18 +01:00
}
else
{
2026-01-13 23:32:03 +01:00
DIE ( " Syntax error: expected an identifier, got: %d " , t . type ) ;
2026-01-09 21:29:18 +01:00
}
}
2026-01-13 23:32:03 +01:00
Node * parser_parse_next ( Parser * p )
2026-01-09 21:29:18 +01:00
{
2026-01-13 23:32:03 +01:00
return parser_statement ( p ) ;
2026-01-09 21:29:18 +01:00
}
2026-01-14 23:56:35 +01:00
size_t parser_parse ( Parser * p , Node * * s )
{
assert ( p ! = NULL ) ;
assert ( s ! = NULL ) ;
size_t p_count = 0 ;
while ( p_count < MAX_STATEMENTS & & p - > loc < p - > cap - 1 )
{
s [ p_count ] = parser_parse_next ( p ) ;
p_count + + ;
}
return p_count ;
}
2026-01-13 23:32:03 +01:00
# ifdef DEBUG
2026-01-09 23:03:27 +01:00
void debug_parser ( Node * n , int indent )
{
for ( int i = 0 ; i < indent ; i + + )
{
printf ( " " ) ;
}
switch ( n - > type )
{
case N_PAIR :
printf ( " PAIR STATEMENT " ) ;
printf ( " Key: %10d \n " , n - > key ) ;
if ( n - > value ! = NULL )
debug_parser ( ( Node * ) n - > value , 2 ) ;
break ;
case N_STRING :
printf ( " STRING EXPRESSION " ) ;
printf ( " Value: %s \n " , ( char * ) n - > value ) ;
break ;
}
2026-01-13 23:32:03 +01:00
}
2026-01-09 23:03:27 +01:00
2026-01-13 23:32:03 +01:00
# endif
2026-01-09 21:29:18 +01:00
2026-01-13 23:32:03 +01:00
/*** configuration process ***/
2026-01-13 23:42:32 +01:00
void configuration_set_option ( Configuration * co , Key k , char * val )
2026-01-09 21:29:18 +01:00
{
2026-01-13 23:32:03 +01:00
switch ( k )
{
2026-01-14 23:56:35 +01:00
case K_NA : DIE ( " Node with an NA key hit configuration_set_option " ) ; break ;
case K_UNKNOWN : DIE ( " Unknown node encountered! " ) ; break ;
2026-01-13 23:32:03 +01:00
case K_COMPILER_PATH : co - > compiler_path = val ; break ;
case K_BUILD_DIR : co - > build_dir = val ; break ;
case K_TARGET_EXEC : co - > target_exec = val ; break ;
case K_DEP_SEARCHER : co - > dep_searcher = val ; break ;
case K_DEP_SEARCHER_FLAGS : co - > dep_searcher_flags = val ; break ;
case K_VERSION : co - > version = val ; break ;
2026-01-14 23:56:35 +01:00
case K_SRC_DIR : co - > src_dir = val ; break ;
case K_SRC_FILES : DIE ( " Not implemented! " ) ; break ;
2026-01-13 23:32:03 +01:00
default :
DIE ( " Invalid compiler option was supplied! " ) ;
}
2026-01-09 21:29:18 +01:00
}
2026-01-13 23:42:32 +01:00
void configuration_process_node ( Configuration * co , Node * n )
2026-01-09 23:03:27 +01:00
{
2026-01-13 23:32:03 +01:00
switch ( n - > type )
{
case N_PAIR :
Key k = n - > key ;
2026-01-13 23:42:32 +01:00
configuration_set_option ( co , k , ( char * ) ( ( Node * ) n - > value ) - > value ) ;
2026-01-13 23:32:03 +01:00
break ;
}
}
2026-01-09 23:03:27 +01:00
2026-01-13 23:42:32 +01:00
Configuration configuration_struct_setup ( int len , Node * * st )
2026-01-09 21:29:18 +01:00
{
2026-01-13 23:32:03 +01:00
Configuration config ;
config . compiler_path = " /usr/bin/gcc " ;
config . build_dir = " . " ;
config . src_dir = " . " ;
config . target_exec = " iexec " ;
config . dep_searcher = " /usr/bin/gcc " ;
config . dep_searcher_flags = " -MM " ;
2026-01-09 21:29:18 +01:00
2026-01-13 23:32:03 +01:00
for ( size_t i = 0 ; i < len ; i + + )
2026-01-13 23:42:32 +01:00
configuration_process_node ( & config , st [ i ] ) ;
2026-01-09 23:03:27 +01:00
2026-01-13 23:32:03 +01:00
LOG_USER ( " Configured IBUILD options. " ) ;
return config ;
}
2026-01-09 21:29:18 +01:00
2026-01-13 23:32:03 +01:00
/*** configuration file management ***/
2026-01-09 21:29:18 +01:00
2026-01-14 23:56:35 +01:00
Configuration process_config ( const char * fn )
2026-01-13 23:32:03 +01:00
{
2026-01-14 23:56:35 +01:00
if ( ! file_has_r_access ( fn ) )
2026-01-13 23:32:03 +01:00
{
2026-01-14 23:56:35 +01:00
return configuration_struct_setup ( 0 , NULL ) ;
2026-01-13 23:32:03 +01:00
}
2026-01-09 21:29:18 +01:00
2026-01-13 23:32:03 +01:00
LOG_USER ( " IBUILD Configuration file detected. \n " ) ;
2026-01-14 23:56:35 +01:00
char * config_mem = file_get_content ( & memory . file_contents , fn ) ;
2026-01-13 23:32:03 +01:00
Token tokens [ MAX_TOKENS ] ;
Tokenizer t = { . src = config_mem } ;
2026-01-09 21:29:18 +01:00
2026-01-14 23:56:35 +01:00
size_t t_count = tokenizer_tokenize ( & t , tokens ) ;
if ( t_count = = 0 )
2026-01-09 21:29:18 +01:00
{
2026-01-14 23:56:35 +01:00
return configuration_struct_setup ( 0 , NULL ) ;
}
2026-01-09 21:29:18 +01:00
2026-01-13 23:32:03 +01:00
Parser parser = { . tokens = tokens , . loc = 0 , . cap = t_count } ;
Node * statements [ MAX_STATEMENTS ] ;
2026-01-14 23:56:35 +01:00
size_t p_count = parser_parse ( & parser , statements ) ;
2026-01-13 23:32:03 +01:00
# ifdef DEBUG
for ( size_t i = 0 ; i < p_count ; i + + )
debug_parser ( statements [ i ] , 0 ) ;
2026-01-09 21:29:18 +01:00
2026-01-13 23:32:03 +01:00
# endif
2026-01-14 23:56:35 +01:00
return configuration_struct_setup ( p_count , statements ) ;
2026-01-09 21:29:18 +01:00
}
2026-01-14 23:56:35 +01:00
# ifndef TESTING
2026-01-09 21:29:18 +01:00
int main ( int argc , char * * argv )
{
2026-01-13 23:32:03 +01:00
LOG_USER ( " Build version: %s " , VERSION ) ;
2026-01-14 23:56:35 +01:00
Configuration c = process_config ( CONFIG_FILE ) ;
dirent_get_recursive ( " . " ) ;
Discovery d ;
d . c_files = ( DirEntry * * ) arena_alloc ( & memory . discovery , MAX_C_FILES * sizeof ( DirEntry * ) ) ;
d . h_files = ( DirEntry * * ) arena_alloc ( & memory . discovery , MAX_H_FILES * sizeof ( DirEntry * ) ) ;
discover ( & d ) ;
// Hand over discovery to the dependency checker.
// Compile
//launch_compile(&c);
2026-01-13 23:32:03 +01:00
memory_free ( ) ;
2026-01-09 21:29:18 +01:00
return 0 ;
}
2026-01-14 23:56:35 +01:00
# endif