~nloomans/libft

ec9beb42782fea8281a34fabb28b474cd93ef188 — Noah Loomans 8 months ago 94c1004 getopt
add ft_getopt

This functions has been designed to be as close as possible to the
POSIX getopt, while still being norm and without using global variables.

Reference: http://man7.org/linux/man-pages/man3/getopt.3p.html
4 files changed, 142 insertions(+), 0 deletions(-)

M Makefile
M libft.h
M meson.build
A src/ft_getopt.c
M Makefile => Makefile +1 -0
@@ 98,6 98,7 @@ SRC_FILES=		\
				strreplace \
				arraydel \
				strfoversplit \
				getopt \

INC_FILES=		libft.h inc/ft_getline.h
OBJ_FILES=		$(patsubst %,$(OBJ_DIR)/ft_%.o,$(SRC_FILES))

M libft.h => libft.h +14 -0
@@ 15,6 15,7 @@

# include <string.h>
# include <stdint.h>
# include <stdbool.h>

/*
** TYPES


@@ 27,6 28,17 @@ typedef struct	s_list
	struct s_list	*next;
}				t_list;

struct			s_ft_getopt
{
	char	*arg;
	int		index;
	int		group_index;
	char	opt;
	bool	illegal;
};

# define FT_GETOPT_DEFAULT (struct s_ft_getopt){0, 1, 1, 0, false}

/*
** PART 1 - LIBC FUNCTIONS
*/


@@ 129,5 141,7 @@ int				ft_getline(const int fd, char **line);
void			ft_strreplace(char **to_replace, char *new);
void			ft_arraydel(void ***array, void delf(void **));
char			**ft_strfoversplit(const char *s, int should_split(int c));
bool			ft_getopt(struct s_ft_getopt *opt, int argc, char **argv,
					const char *optstring);

#endif

M meson.build => meson.build +1 -0
@@ 75,6 75,7 @@ src_files = files([
  'src/ft_strtrim.c',
  'src/ft_tolower.c',
  'src/ft_toupper.c',
  'src/ft_getopt.c',
])

libft = static_library(

A src/ft_getopt.c => src/ft_getopt.c +126 -0
@@ 0,0 1,126 @@
/* ************************************************************************** */
/*                                                                            */
/*                                                        ::::::::            */
/*   ft_getopt.c                                        :+:    :+:            */
/*                                                     +:+                    */
/*   By: nloomans <marvin@codam.nl>                   +#+                     */
/*                                                   +#+                      */
/*   Created: 2020/02/12 18:03:23 by nloomans      #+#    #+#                 */
/*   Updated: 2020/02/12 18:03:24 by nloomans      ########   odam.nl         */
/*                                                                            */
/* ************************************************************************** */

#include <stdbool.h>
#include <unistd.h>
#include "libft.h"

/*
** ft_getopt parses the options for you. Example usage:
**
** int     main(int argc, char **argv)
** {
**     struct s_ft_getopt  opt;
**     bool                opt_a;
**     char                *opt_b_arg;
**     bool                opt_c;
**
**     opt = FT_GETOPT_DEFAULT;
**     opt_a = false;
**     opt_b_arg = NULL;
**     opt_c = false;
**     while (ft_getopt(&opt, argc, argv, "ab:c"))
**     {
**         if (opt.opt == 'a')
**             opt_a = true;
**         else if (opt.opt == 'b')
**             opt_b_arg = opt.arg;
**         else if (opt.opt == 'c')
**             opt_c = true;
**     }
**     if (opt.illegal)
**         return (1);
**     // use options
**     return (0);
** }
*/

static void	print_error(char *argv0, char *msg, char opt)
{
	write(STDERR_FILENO, argv0, ft_strlen(argv0));
	write(STDERR_FILENO, msg, ft_strlen(msg));
	write(STDERR_FILENO, &opt, 1);
	write(STDERR_FILENO, "\n", sizeof("\n"));
}

static int	process_arg(struct s_ft_getopt *opt, char **argv)
{
	if (argv[opt->index][opt->group_index + 1])
		opt->arg = argv[opt->index] + opt->group_index + 1;
	else if (argv[opt->index + 1])
	{
		opt->arg = argv[opt->index + 1];
		opt->index++;
	}
	else
		return (-1);
	opt->group_index = 1;
	opt->index++;
	return (0);
}

static int	process(struct s_ft_getopt *opt,
				char **argv, char matched_opt, bool has_arg)
{
	opt->opt = matched_opt;
	if (has_arg)
	{
		if (process_arg(opt, argv) == -1)
		{
			opt->illegal = true;
			print_error(argv[0], ": option requires an argument -- ",
				argv[opt->index][opt->group_index]);
			return (-1);
		}
	}
	else
	{
		if (argv[opt->index][opt->group_index + 1])
			opt->group_index++;
		else
		{
			opt->group_index = 1;
			opt->index++;
		}
	}
	return (0);
}

bool		ft_getopt(struct s_ft_getopt *opt, int argc, char **argv,
				const char *optstring)
{
	size_t	i;

	if (opt->index >= argc || argv[opt->index][0] != '-')
		return (false);
	if (argv[opt->index][1] == '-')
	{
		opt->index++;
		return (false);
	}
	i = 0;
	while (i < ft_strlen(optstring))
	{
		if (ft_isalnum(optstring[i]) &&
			optstring[i] == argv[opt->index][opt->group_index])
		{
			if (process(opt, argv, optstring[i], optstring[i + 1] == ':') == -1)
				return (false);
			return (true);
		}
		i++;
	}
	opt->illegal = true;
	print_error(argv[0], ": illegal option -- ",
		argv[opt->index][opt->group_index]);
	return (false);
}