313 lines
5.5 KiB
C
313 lines
5.5 KiB
C
/* SPDX-License-Identifier: BSD-2 */
|
|
|
|
#include "pp_args.h"
|
|
#include "pp_defines.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(string_map_t define_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(define_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(define_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:
|
|
free_str_dyn_arr(ret->inc_dirs);
|
|
free(ret);
|
|
return NULL;
|
|
}
|
|
|
|
int _collect_inc_dirs(struct args *args, char *inc_dir)
|
|
{
|
|
int res;
|
|
|
|
res = insert_str_dyn_arr(args->inc_dirs, 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, string_map_t define_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(define_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(define_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);
|
|
}
|
|
|