c-preprocessor/pp_args.c

330 lines
5.7 KiB
C

/* SPDX-License-Identifier: BSD-2 */
#include "pp_args.h"
#include "pp_defines.h"
#include "utils.h"
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#define DEFINE_FLAG "-D"
#define DEFINE_FLAG_SZ (sizeof(DEFINE_FLAG) - 1)
#define INCLUDE_FLAG "-I"
#define INCLUDE_FLAG_SZ (sizeof(INCLUDE_FLAG) - 1)
#define OUTPUT_FLAG "-o"
#define OUTPUT_FLAG_SZ (sizeof(OUTPUT_FLAG) - 1)
int _is_split_define_flag(char *flag)
{
return !strncmp(flag, DEFINE_FLAG, DEFINE_FLAG_SZ)
&& strlen(flag) == DEFINE_FLAG_SZ;
}
int _is_tied_define_flag(char *flag)
{
return !strncmp(flag, DEFINE_FLAG, DEFINE_FLAG_SZ)
&& strlen(flag) != DEFINE_FLAG_SZ;
}
int _is_include_flag(char *flag)
{
return !strncmp(flag, INCLUDE_FLAG, INCLUDE_FLAG_SZ);
}
int _is_output_flag(char *flag)
{
return !strncmp(flag, OUTPUT_FLAG, OUTPUT_FLAG_SZ);
}
int _is_in_out_file_arg(char *prev_flag)
{
return !_is_split_define_flag(prev_flag) && !_is_include_flag(prev_flag)
&& !_is_output_flag(prev_flag);
}
int _is_unrecognized_flag(char *flag)
{
return flag[0] == '-' && !_is_split_define_flag(flag)
&& !_is_include_flag(flag) && !_is_output_flag(flag) &&
!_is_tied_define_flag(flag);
}
int _calloc_and_check(char **p, int sz)
{
*p = calloc(sz, sizeof(char));
if (!(*p))
return PP_FAILED;
return PP_OK;
}
int _add_sym_mapp_to_map(void *def_map, char *sym_mapp)
{
char *sym;
char *mapp;
char *eq_pos;
int sym_len;
int mapp_len;
int ret;
int res;
sym = NULL;
mapp = NULL;
if (!strstr(sym_mapp, "=")) {
res = _calloc_and_check(&mapp, 1);
if (res == PP_FAILED) {
ret = PP_FAILED;
goto free_and_exit;
}
sym_len = strlen(sym_mapp);
_calloc_and_check(&sym, sym_len + 1);
if (res == PP_FAILED) {
ret = PP_FAILED;
goto free_and_exit;
}
strncpy(sym, sym_mapp, sym_len);
res = hashmap_put(def_map, sym, mapp);
if (res != MAP_OK)
return PP_FAILED;
else
return PP_OK;
}
eq_pos = strstr(sym_mapp, "=");
sym_len = eq_pos - sym_mapp;
ret = _calloc_and_check(&sym, sym_len + 1);
if (ret == PP_FAILED)
goto free_and_exit;
strncpy(sym, sym_mapp, sym_len);
eq_pos++;
mapp_len = strlen(eq_pos);
ret = _calloc_and_check(&mapp, mapp_len + 1);
if (ret == PP_FAILED)
goto free_and_exit;
strncpy(mapp, eq_pos, mapp_len);
ret = hashmap_put(def_map, sym, mapp);
if (ret == MAP_OK)
return PP_OK;
else
return PP_FAILED;
free_and_exit:
free(sym);
free(mapp);
return ret;
}
struct args *_create_struct_args(void)
{
struct args *ret;
ret = NULL;
ret = calloc(1, sizeof(struct args));
if (!ret)
goto free_and_exit;
ret->inc_dirs = init_str_dyn_arr(2);
if (!(ret->inc_dirs))
goto free_and_exit;
return ret;
free_and_exit:
if (ret)
free_str_dyn_arr(ret->inc_dirs);
free(ret);
return NULL;
}
int _collect_inc_dirs(struct args *args, char *inc_dir)
{
char *a_inc_dir;
int res;
a_inc_dir = l_strdup(inc_dir);
if (!a_inc_dir)
return PP_FAILED;
res = insert_str_dyn_arr(args->inc_dirs, a_inc_dir);
if (res == CHAR_DYN_ARR_OK)
return PP_OK;
else
return PP_FAILED;
}
int _add_in_file_to_args(struct args *args, char *in_file)
{
char *alloc_in_file;
int in_file_len;
int res;
in_file_len = strlen(in_file);
res = _calloc_and_check(&alloc_in_file, in_file_len + 1);
if (res == PP_FAILED)
return PP_FAILED;
strncpy(alloc_in_file, in_file, in_file_len);
args->in_file = alloc_in_file;
return PP_OK;
}
int _add_out_file_to_args(struct args *args, char *out_file)
{
char *alloc_out_file;
int out_file_len;
int res;
out_file_len = strlen(out_file);
res = _calloc_and_check(&alloc_out_file, out_file_len + 1);
if (res == PP_FAILED)
return PP_FAILED;
strncpy(alloc_out_file, out_file, out_file_len);
args->out_file = alloc_out_file;
return PP_OK;
}
struct args *pp_parse_args(int argc, char **argv, void *def_map)
{
struct args *args;
char *sym_mapp;
int i;
int in_file_found;
int out_file_found;
int is_flag;
int res;
args = _create_struct_args();
if (!args)
return NULL;
in_file_found = 0;
out_file_found = 0;
for (i = 0; i < argc; i++) {
is_flag = 0;
if (_is_unrecognized_flag(argv[i]))
goto free_and_exit;
if (_is_split_define_flag(argv[i])) {
if (i + 1 < argc) {
res = _add_sym_mapp_to_map(
def_map,
argv[i + 1]
);
if (res == PP_FAILED)
goto free_and_exit;
is_flag = 1;
} else {
goto free_and_exit;
}
continue;
}
if (_is_tied_define_flag(argv[i])) {
sym_mapp = argv[i] + DEFINE_FLAG_SZ;
res = _add_sym_mapp_to_map(def_map, sym_mapp);
if (res == PP_FAILED)
goto free_and_exit;
is_flag = 1;
continue;
}
if (_is_include_flag(argv[i])) {
if (i + 1 < argc) {
res = _collect_inc_dirs(args, argv[i + 1]);
if (res == PP_FAILED)
goto free_and_exit;
is_flag = 1;
} else {
goto free_and_exit;
}
continue;
}
if (_is_output_flag(argv[i])) {
if (i + 1 < argc) {
res = _add_out_file_to_args(args, argv[i]);
if (res == PP_FAILED)
goto free_and_exit;
is_flag = 1;
} else {
goto free_and_exit;
}
continue;
}
if (!is_flag && !in_file_found && i - 1 >= 0
&& _is_in_out_file_arg(argv[i - 1])) {
res = _add_in_file_to_args(args, argv[i]);
if (res == PP_FAILED)
goto free_and_exit;
in_file_found = 1;
} else if (!is_flag && in_file_found && i - 1 >= 0
&& _is_in_out_file_arg(argv[i - 1])) {
if (out_file_found)
goto free_and_exit;
res = _add_out_file_to_args(args, argv[i]);
if (res == PP_FAILED)
goto free_and_exit;
out_file_found = 1;
}
}
return args;
free_and_exit:
pp_free_args(args);
return NULL;
}
void pp_free_args(struct args *args)
{
if (!args)
return;
free_str_dyn_arr(args->inc_dirs);
free(args->in_file);
free(args->out_file);
free(args);
}