aboutsummaryrefslogtreecommitdiff
path: root/src/preprocess.c
blob: 103406884302f448cca48531b3cc1e4df4271541 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/* ************************************************************************** */
/*                                                                            */
/*                                                        :::      ::::::::   */
/*   preprocess.c                                       :+:      :+:    :+:   */
/*                                                    +:+ +:+         +:+     */
/*   By: charles <charles.cabergs@gmail.com>        +#+  +:+       +#+        */
/*                                                +#+#+#+#+#+   +#+           */
/*   Created: 2020/04/03 08:58:49 by charles           #+#    #+#             */
/*   Updated: 2020/06/12 11:57:17 by charles          ###   ########.fr       */
/*                                                                            */
/* ************************************************************************** */

#include "minishell.h"
#include "ms_glob.h"
#include "lexer.h"

static bool		st_escapable(char c, enum e_token_tag tag)
{
	if (tag & LTAG_STR)
		return (true);
	if ((tag & LTAG_STR_DOUBLE) && (c == '\\' || c == '"' || c == '$'))
		return (true);
	return (false);
}

static char		*st_iterpolate_env(char *str, enum e_token_tag tag, t_env env)
{
	size_t		i;
	t_ftdstr	*dstr;
	char		*match;

	if ((dstr = ft_dstrwrap(str)) == NULL)
		return (NULL);
	i = -1;
	while (++i < dstr->length)
		if (dstr->str[i] == '\\' && st_escapable(dstr->str[i + 1], tag))
			ft_dstrerase(dstr, i, 1);
		else if (dstr->str[i] == '$')
		{
			if ((match = env_search_first_match(env, dstr->str + i + 1)) == NULL)
			{
				ft_dstrerase(dstr, i, utils_var_end(dstr->str + i + 1));
				i--;
			}
			else
			{
				if (ft_dstrsubstitute(dstr, match, i, utils_var_end(dstr->str + i + 1)) == NULL)
				{
					ft_dstrdestroy(dstr);
					return (NULL);
				}
				i += ft_strlen(match) - 1;
			}
		}
	return (ft_dstrunwrap(dstr));
}

static char		*st_iterpolate_globs(char *str)
{
	char	**strs;
	int		i;

	if ((strs = ft_splitf(str, ' ')) == NULL)
		return (NULL);
	i = 0;
	while (strs[i] != NULL)
	{
		if (ft_strchr(strs[i], '*') != NULL
			&& (strs[i] = ms_globf(strs[i])) == NULL)
		{
			ft_split_destroy(strs);
			return (NULL);
		}
		i++;
	}
	return (ft_strsjoinf(strs, " "));
}

static int		st_splat_arg(t_ftvec *argv, int i)
{
	t_token	*splated;
	char	**strs;
	int		j;

	if ((splated = ft_vectake(argv, i)) == NULL
		|| (strs = ft_split(splated->content, ' ')) == NULL)
	{
		token_destroy(splated);
		return (-1);
	}
	j = 0;
	while (strs[j] != NULL)
	{
		if (ft_vecinsert_safe(argv, i + j, token_new(LTAG_STR, strs[j])) == NULL)
		{
			token_destroy(splated);
			ft_split_destroy(strs);
			return (-1);
		}
		j++;
	}
	token_destroy(splated);
	ft_split_destroy(strs);
	return (i + j - 1);
}

static void		st_iter_func_unwrap_token(void **addr)
{
	char	*content;

	content = (*(t_token**)addr)->content;
	free(*(t_token**)addr);
	*(char**)addr = content;
}

char			**preprocess(t_ftvec *argv, t_env env)
{
	size_t	i;
	t_token	*token;

	i = -1;
	while (++i < argv->size)
	{
		token = argv->data[i];
		if (token->tag & LTAG_STR_SINGLE)
			continue ;
		token->content = st_iterpolate_env(token->content, token->tag, env);
		if (token->tag & LTAG_STR)
		{
			if (ft_strchr(token->content, '*') != NULL)
				token->content = st_iterpolate_globs(token->content);
			if ((i = st_splat_arg(argv, i)) == (size_t)-1)
				return (NULL);
		}
	}

	t_token *next;
	i = -1;
	while (++i < argv->size - 1)
	{
		token = argv->data[i];
		while (token->tag & LTAG_STICK && i + 1 < argv->size)
		{
			next = argv->data[i + 1];
			token->content = ft_strjoinf_fst(token->content, next->content);
			if (token->content == NULL)
				return (NULL);
			token->tag &= next->tag;
			ft_vecremove(argv, i + 1, (void (*)(void*))token_destroy);
		}
	}

	ft_veciter_addr(argv, st_iter_func_unwrap_token);
	ft_vecpush(argv, NULL);
	return ((char**)ft_vecunwrap(argv));
}