1111
1212extern Platform_Info platform;
1313
14+ Config_Crash_Handler crash_handler_hook;
15+
16+ static void __require_non_null (const void *value, const char *function_name, const char *parameter_name) {
17+ if (value == nullptr ) [[unlikely]] {
18+ char temp_buffer[512 ];
19+ Memory_Arena temp_arena (temp_buffer, 512 );
20+ print (&temp_arena, " Invalid '%' value passed to '%': value must NOT BE Null\n " , parameter_name, function_name);
21+ crash_handler_hook (EXIT_FAILURE);
22+ }
23+ }
24+ #define require_non_null (PARAM ) __require_non_null(PARAM, __FUNCTION__, #PARAM)
25+
26+ static void __require_non_empty (const char *value, const char *function_name, const char *parameter_name) {
27+ if (value[0 ] == ' \0 ' ) [[unlikely]] {
28+ char temp_buffer[512 ];
29+ Memory_Arena temp_arena (temp_buffer, 512 );
30+ print (&temp_arena, " Invalid '%' value passed to '%': value must NOT BE empty\n " , parameter_name, function_name);
31+ crash_handler_hook (EXIT_FAILURE);
32+ }
33+ }
34+ #define require_non_empty (PARAM ) __require_non_empty(PARAM, __FUNCTION__, #PARAM)
35+
1436const char * get_argument_or_default (const Arguments *args, const char *key, const char *default_value) {
1537 if (key == nullptr ) return default_value;
1638 if (key[0 ] == ' \0 ' ) return default_value;
1739 if (is_empty_list (&args->args )) return default_value;
1840
1941 auto key_length = strlen (key);
2042 for (auto arg: args->args ) {
21- if (arg.type == Argument::Type::Flag) continue ;
22-
23- if (strncmp (arg.key , key, key_length) == 0 ) return arg.value ;
43+ if ((strlen (arg.key ) == key_length) &&
44+ (strncmp (arg.key , key, key_length) == 0 )) {
45+ return (arg.type == Argument::Type::Flag) ? key : arg.value ;
46+ }
2447 }
2548
2649 return default_value;
2750}
2851
2952bool find_toolchain_by_type (Project *project, Toolchain_Type type, Toolchain_Configuration *out_configuration) {
53+ require_non_null (project);
54+ require_non_null (out_configuration);
55+
3056 auto [status, result] = lookup_toolchain_by_type (&project->arena , type);
3157 check_status (status);
3258
@@ -36,6 +62,8 @@ bool find_toolchain_by_type (Project *project, Toolchain_Type type, Toolchain_Co
3662}
3763
3864void overwrite_toolchain (Project *project, Toolchain_Configuration toolchain) {
65+ require_non_null (project);
66+
3967 /*
4068 #REWORK:
4169 This is a temporary solution for 2 reasons:
@@ -51,42 +79,53 @@ void overwrite_toolchain (Project *project, Toolchain_Configuration toolchain) {
5179}
5280
5381void set_toolchain (Project *project, Toolchain_Type type) {
82+ require_non_null (project);
83+
5484 auto [status, result] = lookup_toolchain_by_type (&project->arena , type);
5585 if (!status) {
5686 print (&project->arena , " FATAL ERROR: Requested toolchain wasn't found on the system.\n " );
57- exit (EXIT_FAILURE);
87+ crash_handler_hook (EXIT_FAILURE);
5888 }
5989
6090 overwrite_toolchain (project, result);
6191}
6292
6393void disable_registry (Project *project) {
94+ require_non_null (project);
95+
6496 project->registry_disabled = true ;
6597}
6698
6799void register_action (Project *project, const char *name, Action_Type action) {
100+ require_non_null (project);
101+ require_non_null (name);
102+ require_non_empty (name);
103+
68104 add (&project->arena , &project->user_defined_commands , {
69105 .name = copy_string (&project->arena , String (name)),
70106 .proc = action
71107 });
72108}
73109
74110void set_output_location (Project *project, const char *folder_path) {
111+ require_non_null (project);
112+ require_non_null (folder_path);
113+ require_non_empty (folder_path);
114+
75115 project->output_location = copy_string (&project->arena , folder_path);
76116}
77117
78118static Target * create_target (Project *project, const char *name) {
79- auto arena = &project->arena ;
119+ require_non_null (project);
120+ require_non_null (name);
121+ require_non_empty (name);
80122
81- if (name == nullptr ) {
82- print (arena, " FATAL ERROR: Annonymous targets (target without a name) are not allowed." );
83- exit (EXIT_FAILURE);
84- }
123+ auto arena = &project->arena ;
85124
86125 auto name_length = strlen (name);
87126 if (name_length > Target::Max_Name_Limit) {
88127 print (arena, " Target's name length is limited to % symbols. If your case requires a longer target name, please submit an issue on the project's Github page\n " , Target::Max_Name_Limit);
89- exit (EXIT_FAILURE);
128+ crash_handler_hook (EXIT_FAILURE);
90129 }
91130
92131 for (auto cursor = name; *cursor; cursor++) {
@@ -95,15 +134,15 @@ static Target * create_target (Project *project, const char *name) {
95134 (value >= ' A' && value <= ' Z' ) ||
96135 (value >= ' 0' && value <= ' 9' ) ||
97136 (value == ' _' ))) {
98- print (arena, " FATAL ERROR: Target name contains disallowed characters, only alphanumeric characters are allow and '_'" );
99- exit (EXIT_FAILURE);
137+ print (arena, " FATAL ERROR: Target name contains disallowed characters, only alphanumeric characters are allow and '_'\n " );
138+ crash_handler_hook (EXIT_FAILURE);
100139 }
101140 }
102141
103142 for (auto t: project->targets ) {
104143 if (compare_strings (t->name , name)) {
105144 print (&project->arena , " FATAL ERROR: Target '%' already defined in the project. It's not allowed to have multiple targets with the same name\n " , name);
106- exit (EXIT_FAILURE);
145+ crash_handler_hook (EXIT_FAILURE);
107146 }
108147 }
109148
@@ -140,43 +179,60 @@ Target * add_executable (Project *project, const char *name) {
140179 return target;
141180}
142181
143- void add_source_file (Target *target, const char *_file_path) {
182+ void add_source_file (Target *target, const char *file_path) {
183+ require_non_null (target);
184+ require_non_null (file_path);
185+ require_non_empty (file_path);
186+
144187 auto arena = &target->project ->arena ;
145188
146- auto file_path = get_absolute_path (arena, _file_path);
147- add (arena, &target->files , *file_path);
189+ auto abs_file_path = get_absolute_path (arena, file_path);
190+ if (!check_file_exists (&abs_file_path)) {
191+ print (arena, " File '%' wasn't found, please check the correctness of the specified path and that the file exists\n " , *abs_file_path);
192+ crash_handler_hook (EXIT_FAILURE);
193+ }
194+
195+ add (arena, &target->files , *abs_file_path);
148196
149197 target->project ->total_files_count += 1 ;
150198}
151199
152- void exclude_source_file (Target *target, const char *_file_path) {
200+ void exclude_source_file (Target *target, const char *file_path) {
201+ require_non_null (target);
202+ require_non_null (file_path);
203+ require_non_empty (file_path);
204+
153205 auto arena = &target->project ->arena ;
154206
155207 if (is_empty_list (&target->files )) return ;
156208
157- auto [status, file_path ] = get_absolute_path (arena, _file_path );
158- if (!status ) {
159- print (arena, " File '%' not found, please check the correctness of the specified path\n " , _file_path );
160- exit (EXIT_FAILURE);
209+ auto [status, abs_file_path ] = get_absolute_path (arena, file_path );
210+ if (!check_file_exists (&abs_file_path) ) {
211+ print (arena, " File '%' not found, please check the correctness of the specified path\n " , file_path );
212+ crash_handler_hook (EXIT_FAILURE);
161213 }
162214
163215 auto [found, position] =
164216 find_position (&target->files , [&] (const File_Path *node) {
165- return compare_strings (*node, file_path );
217+ return compare_strings (*node, abs_file_path );
166218 });
167219
168220 if (!found) {
169- print (arena, " File '%' not included for the target %\n " , _file_path , target->name );
221+ print (arena, " File '%' not included for the target %\n " , file_path , target->name );
170222 return ;
171223 }
172224
173225 if (!remove_at (&target->files , position)) {
174- print (arena, " Couldn't remove file '%' from the target due to an internal error, please report this case.\n " , _file_path );
226+ print (arena, " Couldn't remove file '%' from the target due to an internal error, please report this case.\n " , file_path );
175227 return ;
176228 }
177229}
178230
179231void add_include_search_path (Target *target, const char *include_path) {
232+ require_non_null (target);
233+ require_non_null (include_path);
234+ require_non_empty (include_path);
235+
180236 auto arena = &target->project ->arena ;
181237
182238 auto file_path = get_absolute_path (arena, include_path);
@@ -185,42 +241,76 @@ void add_include_search_path (Target *target, const char *include_path) {
185241}
186242
187243void add_all_sources_from_directory (Target *target, const char *directory, const char *extension, bool recurse) {
244+ require_non_null (target);
245+ require_non_null (directory);
246+ require_non_empty (directory);
247+ require_non_null (extension);
248+ require_non_empty (extension);
249+
250+ auto arena = &target->project ->arena ;
251+
252+ auto folder_path = get_absolute_path (arena, directory);
253+ if (!folder_path.status ) {
254+ print (arena, " Couldn't get absolute path for '%'\n " , directory);
255+ crash_handler_hook (EXIT_FAILURE);
256+ }
257+
258+ if (!check_directory_exists (&folder_path)) {
259+ print (arena, " Directory '%' specified for 'add_all_sources_from_directory' wasn't found, please ensure that the path is correct and the directory exists\n " , folder_path);
260+ crash_handler_hook (EXIT_FAILURE);
261+ }
262+
188263 auto existing_target_count = target->files .count ;
189264 list_files_in_directory (&target->project ->arena , &target->files , directory, extension, recurse);
190265 target->project ->total_files_count += (target->files .count - existing_target_count);
191266}
192267
193268void add_compiler_option (Target *target, const char *option) {
194- if (option == nullptr ) return ;
269+ require_non_null (target);
270+ require_non_null (option);
271+ require_non_empty (option);
195272
196273 auto arena = &target->project ->arena ;
197274 add (arena, &target->options .compiler , copy_string (arena, option));
198275}
199276
200277void add_linker_option (Target *target, const char *option) {
201- if (option == nullptr ) return ;
278+ require_non_null (target);
279+ require_non_null (option);
280+ require_non_empty (option);
202281
203282 auto arena = &target->project ->arena ;
204283 add (arena, &target->options .linker , copy_string (arena, option));
205284}
206285
207286void link_with_target (Target *target, Target *dependency) {
208- if (dependency == nullptr ) return ;
287+ require_non_null (target);
288+ require_non_null (dependency);
209289
210290 auto arena = &target->project ->arena ;
291+
292+ if (target == dependency) {
293+ print (arena, " Invalid 'dependency' value passed to 'link_with_target': the target cannot be linked with itself\n " );
294+ crash_handler_hook (EXIT_FAILURE);
295+ }
296+
211297 add (arena, &target->depends_on , const_cast <const Target *>(dependency));
212298 add (arena, &dependency->required_by , const_cast <const Target *>(target));
213299}
214300
215301void link_with_library (Target *target, const char *library_name) {
216- if (library_name == nullptr || library_name[0 ] == ' \0 ' ) return ;
302+ require_non_null (target);
303+ require_non_null (library_name);
304+ require_non_empty (library_name);
217305
218306 auto arena = &target->project ->arena ;
219307 auto copied = copy_string (arena, library_name);
220308 add (arena, &target->link_libraries , copied);
221309}
222310
223311void add_target_hook (Target *target, Hook_Type type, Hook_Func func) {
312+ require_non_null (target);
313+
224314 switch (type) {
225315 case Hook_Type_After_Target_Linked: {
226316 target->hooks .on_linked = func;
@@ -230,5 +320,7 @@ void add_target_hook (Target *target, Hook_Type type, Hook_Func func) {
230320}
231321
232322const char * get_target_name (const Target *target) {
323+ require_non_null (target);
324+
233325 return target->name .value ;
234326}
0 commit comments