-
Notifications
You must be signed in to change notification settings - Fork 0
Documentation
This section of this project is dedicated to handling arguments given by the user from the command line. The users calls the program using "./minirt" followed by an arbitrary number of non repeating flags with possible arguments as well as one scene file in the ".rt" format, which describes the contents of the scene. All arguments can be called in any given order.
Flag parsing is done in a highly modular way. A Flag is created in the header by defining it's FULL and SHORT string as well as their data type (e.g. --save, -s, "STRING"). A data type can also have an '*', which signifies an optional argument. A data type can be either "NULL"(takes no arguments), "STRING", "FLOAT", "VECTOR" (all with optional argument setting).
This function begins the process of checking the flag format as well as their arguments. The function checks the full and short options flags and updates the options structure accordingly.
Parameters
-
argv: The command line arguments. -
options: The options structure to be updated.
Return Value
- Returns
0if the file format is successfully checked and updated,-1otherwise.
int option_preferences(char **argv, t_options *options)
{
if (check_file_format(argv, options, ft_strdup(OPTS_FULL), 0) == -1)
return (-1);
if (check_file_format(argv, options, ft_strdup(OPTS_SHORT), 1) == -1)
return (-1);
return (0);
}This function checks each command line argument for a match with a list of flags. It uses the args_to_opts function to compare each argument against a list of flags. If an argument does not match any flags, the function returns -1. Otherwise, it updates the options structure using binary assignment with opt_binary_assignment and processes the argument values with value_containers. If any step fails, the function returns -1.
Parameters
-
argv: The command line arguments. -
options: The options structure to store the converted options. -
flag: The flag to be used for conversion. -
type: The type of conversion to be performed.
Return Value
- Returns
0if the file format is valid,-1otherwise.
int check_file_format(char **argv, t_options *options, char *flag, int type)
{
int i;
int ato_ret;
i = 1;
while (argv[i])
{
ato_ret = args_to_opts(argv[i], ft_strdup(flag), type);
if (ato_ret == -2)
return (-1);
else
{
if (opt_binary_assignment(ato_ret, options) == -1)
return (-1);
if (value_containers(ato_ret, options, argv[i + 1], argv[i]) == -1)
return (-1);
}
i++;
}
return (0);
}This function converts a string to an option index based on a given flag and type. It splits the flag into options using a comma as a delimiter and compares each option with the given string. If a match is found, the function returns the index of the option. If the string is not a number and starts with a (-), an error message is printed and -2 is returned. If no match is found, -1 is returned.
Parameters
-
str: The string to be converted to an option index. -
flag: The flag used to split into options. -
type: The type of the flag.
Return Value
- Returns the index of the option if a match is found.
- Returns
-2if the string is a non-valid flag. - Returns
-1if no match is found.
int args_to_opts(char *str, char *flag, int type)
{
char **opts;
int i;
opts = ft_split(flag, ',');
i = 0;
while (opts[i])
{
if (ft_strcmp(opts[i], str) == 0)
return (i);
i++;
}
if (is_number(str) == 1)
{
if ((type == 0 && str[0] == '-' && str[1] == '-' )
|| (type == 1 && str[0] == '-' && str[1] != '-'))
{
ft_dprintf(2, "%s '%s'\n", ERR_INVALID_OPT, str);
return (-2);
}
}
return (-1);
}This function assigns a binary value to an option flag in the provided t_options structure. It checks if the value is less than 0 and returns 0 if true. It also checks if the flag is already set and returns -1 if true, printing an error message. If the flag is not set, it sets the flag and returns 0.
Parameters
-
value: The binary position index to assign (1) to the flag. -
options: Pointer to thet_optionsstructure.
Return Value
- Returns
0if the flag was successfully set. - Returns
-1if the flag is already set.
int opt_binary_assignment(int value, t_options *options)
{
if (value < 0)
return (0);
if (options->opts_flags & (1 << value))
{
ft_dprintf(2, "%s\n", ERR_DOUBLE_OPT);
return (-1);
}
options->opts_flags |= (1 << value);
return (0);
}This function is a starting point for populating the options->values linked list with flag arguments. It takes the value of the flag, a pointer to a t_options struct, an argument string, and a flag. It groups the flag, flag type, and argument string into a single array of strings, flag_join. Then, it calls the process_flag function with the appropriate arguments to create a new value node and append it to the options->values linked list. It returns 0 if successful and -1 if an error occurs.
Parameters
-
value: The value for the flag. -
options: A pointer to at_optionsstruct. -
str: A string of the flag's argument. -
flag: The flag string.
Return Value
- Returns
0if successful. - Returns
-1if an error occurs.
int value_containers(int value, t_options *options, char *str, char *flag)
{
char **f_types;
char **flag_join;
char *opts_value;
opts_value = ft_strdup(OPTS_VALUE);
if (value < 0)
return (0);
f_types = ft_split(opts_value, ',');
flag_join = gc_malloc(sizeof(char *) * 4);
flag_join[0] = ft_strdup(flag);
flag_join[1] = ft_strdup(f_types[value]);
if (str)
flag_join[2] = ft_strdup(str);
else
flag_join[2] = NULL;
flag_join[3] = NULL;
if (process_flag(flag_join[1], options, value, flag_join) == -1)
return (-1);
return (0);
}This function compares the flag's corresponding input type against a preset type list and creates a new option node. It processes the flag's arguments based on the flag's type. If the flag type matches a given type, it calls the create_option function. If the flag type is "NULL", it calls the handle_null_value function. If the argument for a flag is invalid, it prints an error message to stderr and returns -1.
Parameters
-
f_type: The type of the flag. -
options: The options structure to update. -
value: The value of the flag. -
flag_join: An array of strings that holds relevant flag information.
Return Value
- Returns
0if the flag was processed successfully. - Returns
-1otherwise.
int process_flag(char *f_type, t_options *options, int value, char **flag_join)
{
if (ft_strnstr(f_type, "STRING", ft_strlen(f_type))
|| ft_strnstr(f_type, "FLOAT", ft_strlen(f_type))
|| ft_strnstr(f_type, "VECTOR", ft_strlen(f_type)))
{
if (create_option(options, value, flag_join) == -1)
return (-1);
}
if (ft_strnstr(f_type, "NULL", ft_strlen(f_type)))
{
if (handle_null_value(flag_join[2]) == 1)
{
ft_dprintf(2, "Error: Option '%s' %s\n", flag_join[0], ERR_NO_ARG);
return (-1);
}
}
return (0);
}This function creates a t_value node and appends it to the options->values linked list if the flag's argument is valid. It checks if the flag's argument is valid against its relevant flag type. If the flag's argument is valid, it creates a new t_value node and appends it to the back of the options->values linked list. If the flag's argument is invalid, it prints an error message to stderr and returns -1.
Parameters
-
options: The options list to add the new node to. -
value: The value of the option. -
flag_join: The array of relevant flag information.
Return Value
- Returns
0if the option node was successfully created and added. - Returns
-1otherwise.
int create_option(t_options *options, int value, char **flag_join)
{
t_value *new_value_node;
char *arg;
arg = check_if_option(flag_join[2]);
if (flag_join[1][0] == '*' && arg == NULL)
new_value_node = create_value_node(value, flag_join[1], NULL);
else if (arg == NULL)
{
ft_dprintf(2, "Error: Option '%s' %s\n", flag_join[0], ERR_REQ_ARG);
return (-1);
}
else
new_value_node = create_value_node(value, flag_join[1], arg);
if (new_value_node == NULL)
return (-1);
append_value_node(options, new_value_node);
return (0);
}This function creates a new t_value node with the specified type, value type, and data. It compares the value type against a list of known types and runs the appropriate function to check and handle the flag's argument. If the flag's argument is valid, it creates a new value node and returns a pointer to it. If the flag's argument is invalid, it prints an error message to stderr and returns NULL.
Parameters
-
type: Enum of the flag's type. -
value_type: String holding the value type. -
data: Argument string.
Return Value
- Returns a pointer to the newly created value node if successful.
- Returns
NULLif an error occurred.
t_value *create_value_node(t_opts_type type, char *value_type, char *data)
{
t_value *new_value_node;
new_value_node = (t_value *)gc_malloc(sizeof(t_value));
new_value_node->type = type;
if (ft_strnstr(value_type, "STRING", ft_strlen(value_type)))
{
if (handle_string_value(new_value_node, data) == -1)
return (NULL);
}
else if (ft_strnstr(value_type, "FLOAT", ft_strlen(value_type)))
{
if (handle_float_value(new_value_node, data) == -1)
return (NULL);
}
else if (ft_strnstr(value_type, "VECTOR", ft_strlen(value_type)))
{
if (handle_vector_value(new_value_node, data) == -1)
return (NULL);
}
new_value_node->next = (NULL);
return (new_value_node);
}This function appends a new value node to the options->values linked list. If the options->values list is empty, it initializes it with the new value node. Otherwise, it traverses the list to find the last node and appends the new value node to the end.
Parameters
-
options: The options structure to append the value node to. -
new_value_node: The new value node to append.
void append_value_node(t_options *options, t_value *new_value_node)
{
t_value *last;
if (options->values == NULL)
{
options->values = new_value_node;
return ;
}
last = options->values;
while (last->next != NULL)
last = last->next;
last->next = new_value_node;
}This function checks if a flag of type NULL holds no arguments. It evaluates whether the flag's argument is null or invalid (e.g., another flag or a number with a negative sign). It returns 0 if the argument is considered invalid; otherwise, it returns 1. The outer function will handle the error message.
Parameters
-
str: The input string to be checked.
Return Value
- Returns
0if the string is null or is not a number and has a negative sign. - Returns
1otherwise.
int handle_null_value(char *str)
{
if (!str)
return (0);
if ((is_number(str) == 1) && str[0] == '-')
return (0);
return (1);
}This function is responsible for assigning a string value to the specified t_value node of type string. If the data is NULL, the string value of the t_value node will be set to NULL. Otherwise, it will first check the format of the string using the check_string_format function. If the format check fails, the function returns -1. Otherwise, it allocates memory for the string value using ft_strdup and returns 0.
Parameters
-
new_value_node: Pointer to thet_valuenode to assign the string value to. -
data: The string value to assign.
Return Value
- Returns
0on success. - Returns
-1if the format check fails.
int handle_string_value(t_value *new_value_node, char *data)
{
if (data == NULL)
{
new_value_node->value.string.string_value = NULL;
}
else
{
if (check_string_format(data) == -1)
return (-1);
else
new_value_node->value.string.string_value = ft_strdup(data);
}
return (0);
}This function is responsible for assigning a float value to the specified t_value node of type float. If the data is NULL, the float value of the t_value node will be set to 0. Otherwise, it will first check the format of the float using the check_float_format function. If the format check fails, the function returns -1. Otherwise, it converts the string into a double and returns 0.
Parameters
-
new_value_node: Pointer to thet_valuenode to assign the float value to. -
data: The float value to assign.
Return Value
- Returns
0on success. - Returns
-1if the format check fails.
int handle_float_value(t_value *new_value_node, char *data)
{
if (data == NULL)
{
new_value_node->value.float_value.float_value = 0;
}
else
{
if (check_float_format(data) == -1)
return (-1);
else
new_value_node->value.float_value.float_value = ft_atob(data);
}
return (0);
}This function is responsible for assigning values to vector components (x, y, z) in a t_value node. If the data is NULL, the vector values of the t_value node will be set to 0 by default. Otherwise, it first checks the format of the data value using the check_vector_format function. If the format check fails, the function returns -1. If the format check is successful, the function converts the string into a set of three doubles and returns 0.
Parameters
-
new_value_node: Pointer to thet_valuenode to assign the vector values to. -
data: The string containing vector values to assign.
Return Value
- Returns
0on success. - Returns
-1if the format check fails or if there is an error with the vector argument.
int handle_vector_value(t_value *new_value_node, char *data)
{
char **vector;
int i;
i = 0;
if (data == NULL)
set_vector_values(new_value_node, NULL);
else
{
if (check_vector_format(data) == -1)
return (-1);
else
{
vector = ft_split(data, ',');
while (vector[i] != NULL)
i++;
if (i == 3)
set_vector_values(new_value_node, vector);
else
{
ft_dprintf(1, "%s\n", ERR_VEC_ARG);
return (-1);
}
}
}
return (0);
}This function sets the values of a vector (x, y, z) in a given value node. It is used as a helper function for handle_vector_value to assign vector components to the appropriate fields in a t_value node.
Parameters
-
new_value_node: The value node to set the vector values in. -
vector: The vector values to set. IfNULL, the vector components are set to 0.
Return Value
- This function does not return a value.
void set_vector_values(t_value *new_value_node, char **vector)
{
if (vector == NULL)
{
new_value_node->value.vector.x = 0;
new_value_node->value.vector.y = 0;
new_value_node->value.vector.z = 0;
}
else
{
new_value_node->value.vector.x = ft_atob(vector[0]);
new_value_node->value.vector.y = ft_atob(vector[1]);
new_value_node->value.vector.z = ft_atob(vector[2]);
}
}This function checks if a given flag's string has a valid format. The valid format consists of uppercase letters (A-Z), lowercase letters (a-z), and underscores (_). If the string contains any other characters, an error message is printed to the standard error stream, and the function returns -1. Otherwise, the function returns 0.
Parameters
-
str: The flag's string argument to be checked.
Return Value
- Returns
0if the string has a valid format. - Returns
-1if the string contains invalid characters.
int check_string_format(char *str)
{
int i;
i = 0;
while (str[i])
{
if ((str[i] < 65 || str[i] > 90)
&& (str[i] < 97 || str[i] > 122) && str[i] != '_')
{
if (str[i] != '_')
ft_dprintf(2, "%s '%c'\n", ERR_INVALID_CHAR, str[i]);
return (-1);
}
i++;
}
return (0);
}This function checks if the given string represents a valid float value. The valid format consists of digits (0-9), a single decimal point (.), and an optional negative sign (-) at the beginning of the string. If the string contains any other characters or multiple decimal points, an error message is printed to the standard error stream, and the function returns -1. Otherwise, it returns 0.
Parameters
-
str: The flag's float value as a string to be checked.
Return Value
- Returns
0if the format is valid. - Returns
-1if the format is invalid.
int check_float_format(char *str)
{
int i;
int dot_count;
i = 0;
dot_count = 0;
while (str[i])
{
if ((str[i] < 48 || str[i] > 57) && str[i] != '.' && str[i] != '-')
{
ft_dprintf(2, "%s '%c'\n", ERR_INVALID_CHAR, str[i]);
return (-1);
}
if (str[i] == '.')
dot_count++;
i++;
}
if (dot_count > 1)
{
ft_dprintf(2, "%s\n", ERR_DOT_COUNT);
return (-1);
}
return (0);
}This function checks if the given string represents a valid vector value. The valid format consists of digits (0-9), a single decimal point (.), and an optional negative sign (-) at the beginning of the value. The vector values (x, y, and z) must be separated by commas (,). If the string contains any other characters or multiple decimal points before a comma, an error message is printed to the standard error stream, and the function returns -1. Otherwise, it returns 0.
Parameters
-
str: The flag's vector value as a string to be checked.
Return Value
- Returns
0if the format is valid. - Returns
-1if the format is invalid.
int check_vector_format(char *str)
{
int i;
int dot_count;
i = 0;
dot_count = 0;
while (str[i])
{
if ((str[i] < 48 || str[i] > 57) && str[i] != '.'
&& str[i] != '-' && str[i] != ',')
{
ft_dprintf(2, "%s '%c'\n", ERR_INVALID_CHAR, str[i]);
return (-1);
}
else if (str[i] == '.')
dot_count++;
if (dot_count > 1)
{
ft_dprintf(2, "%s\n", ERR_DOT_COUNT);
return (-1);
}
else if (str[i] == ',')
dot_count = 0;
i++;
}
return (0);
}This function checks if the given string has a valid format for a flag. It also considers negative numbers with the (-) sign to be invalid and ignores them. If the string is a valid option, it is duplicated and returned. Otherwise, NULL is returned.
Parameters
-
str: The string to be checked.
Return Value
- Returns a pointer to the duplicated string if it is a valid option.
- Returns
NULLif the string is not a valid option.
char *check_if_option(char *str)
{
char *ret;
if (!str)
return (NULL);
if (check_scene_file(str) == 0)
return (NULL);
if ((is_number(str) == 1) && str[0] == '-')
return (NULL);
ret = ft_strdup(str);
return (ret);
}This function checks if a given string is a valid number. It iterates through each character of the string and verifies if it falls within the range of valid characters for a number. Valid characters include digits (0-9), decimal point (.), minus sign (-), and comma (,).
Parameters
-
str: The string to be checked.
Return Value
- Returns
0if the string is a valid number. - Returns
1otherwise.
int is_number(char *str)
{
int i;
i = 0;
while (str[i])
{
if ((str[i] < 48 || str[i] > 57) && str[i] != '.'
&& str[i] != '-' && str[i] != ',')
return (1);
i++;
}
return (0);
}This function converts a string to a double value. It processes the string to handle optional negative signs, integer parts, and fractional parts. The conversion is done by using the parse_num and parse_frac functions to handle the respective parts of the number.
Parameters
-
str: The string to be converted.
Return Value
- Returns the converted double value.
double ft_atob(char *str)
{
int i;
double result;
bool is_negative;
i = 0;
is_negative = false;
if (str[i] == '-')
{
is_negative = true;
i++;
}
else if (str[i] == '+')
i++;
result = parse_num(str, &i, false, 10.0);
if (str[i] == '.')
{
i++;
result += parse_frac(str, &i, 10.0);
}
if (is_negative)
result = -result;
return (result);
}This function parses a number from a string, handling both integer and floating-point formats. It iterates through the string, converting characters to a double value. If an invalid character is encountered, an error message is printed to the standard error stream, and -1 is returned.
Parameters
-
str: The string to parse the number from. -
i: A pointer to the current index in the string. -
isf: A boolean flag indicating if the number is a floating-point number. -
frac_div: The divisor used to calculate the fractional part of the number.
Return Value
- Returns the parsed number as a double value, or
-1if an error occurred.
static double parse_num(const char *str, int *i, bool isf, double frac_div)
{
double result;
result = 0.0;
while (str[*i] != '\0' && (ft_isdigit(str[*i]) || (str[*i] == '.' && !isf)))
{
if (ft_isdigit(str[*i]))
{
if (isf)
{
result += (str[*i] - '0') / frac_div;
frac_div *= 10;
}
else
result = result * 10 + (str[*i] - '0');
}
else if (str[*i] == '.')
isf = true;
else
{
ft_dprintf(2, "%s '%c'\n", ERR_INVALID_ATOB, str[*i]);
return (-1);
}
(*i)++;
}
return (result);
}This function parses the fractional part of a number from a string and returns the corresponding double value. It processes characters following the decimal point and calculates the fractional value based on a given divisor.
Parameters
-
str: The string to parse the fraction from. -
i: A pointer to the current index in the string. -
frac_div: The divisor used to calculate the fraction.
Return Value
- Returns the parsed fraction as a double value.
static double parse_frac(const char *str, int *i, double frac_div)
{
double frac;
frac = 0.0;
while (str[*i] != '\0' && ft_isdigit(str[*i]))
{
frac += (str[*i] - '0') / frac_div;
frac_div *= 10;
(*i)++;
}
return (frac);
}