aboutsummaryrefslogtreecommitdiff
path: root/src/preprocess/interpolation.c
blob: c28d5455b244c8bd8fe32a09beb94b8a34b36d42 (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
/* ************************************************************************** */
/*                                                                            */
/*                                                        :::      ::::::::   */
/*   interpolation.c                                    :+:      :+:    :+:   */
/*                                                    +:+ +:+         +:+     */
/*   By: cacharle <me@cacharle.xyz>                 +#+  +:+       +#+        */
/*                                                +#+#+#+#+#+   +#+           */
/*   Created: 2020/10/09 15:27:46 by cacharle          #+#    #+#             */
/*   Updated: 2020/10/10 10:26:43 by cacharle         ###   ########.fr       */
/*                                                                            */
/* ************************************************************************** */

#include "eval.h"
#include "lexer.h"
#include "minishell.h"

static t_tok_lst	*st_field_split(char *str)
{
	t_tok_lst	*ret;
	char		*match;

	ret = NULL;
	while (*str != '\0')
	{
		if ((match = ft_strchr(str, ' ')) == NULL)
		{
			if (tok_lst_push_front(&ret, tok_lst_new(TAG_STR, str)) == NULL)
				return (tok_lst_destroy(&ret, free));
			break ;
		}
		if (tok_lst_push_front(
				&ret, tok_lst_new_until(TAG_STR, str, match - str)) == NULL)
			return (tok_lst_destroy(&ret, free));
		while (*++match == ' ')
			;
		str = match;
		if (*str == '\0' &&
			tok_lst_push_front(&ret, tok_lst_new(TAG_STR, str)) == NULL)
			return (tok_lst_destroy(&ret, free));
	}
	return ((t_tok_lst *)ft_lstreverse_ret((t_ftlst *)ret));
}

#define BEFORE 0
#define MATCH 1
#define AFTER 2

static bool			st_make_strs(char *strs[3], t_env env, char *str, size_t i)
{
	size_t	var_len;

	var_len = env_key_len(&str[i + 1], true) + 1;
	if ((strs[MATCH] = env_search_first_match(env, &str[i + 1])) == NULL)
	{
		ft_memmove(&str[i], &str[i + var_len],
				ft_strlen(&str[i + var_len]) + 1);
		return (false);
	}
	str[i] = '\0';
	strs[BEFORE] = str;
	strs[AFTER] = &str[i + var_len];
	return (true);
}

static size_t		st_merge_fields_in_curr(
	char *strs[3], t_tok_lst **curr, t_tok_lst *fields, size_t len)
{
	t_tok_lst	*last;

	last = tok_lst_last(fields);
	last->tag = (*curr)->tag;
	(*curr)->tag = TAG_STR;
	(*curr)->content = ft_strjoinf_snd(strs[BEFORE], fields->content);
	last->content = ft_strjoinf_fst(last->content, strs[AFTER]);
	free(strs[BEFORE]);
	last->next = (*curr)->next;
	(*curr)->next = fields->next;
	(*curr) = last;
	free(fields);
	return (len);
}

static size_t		st_interpolate_non_quoted(
	char *strs[3], t_tok_lst **curr, size_t i, enum e_tok prev_tag)
{
	t_tok_lst	*fields;
	size_t		len;

	fields = st_field_split(strs[MATCH]);
	if (fields == NULL)
		return (i);
	len = ft_strlen(tok_lst_last(fields)->content);
	if (!(prev_tag & TAG_STICK) && *strs[BEFORE] == '\0' &&
		*fields->content == '\0')
		ft_lstpop_front((t_ftlst **)&fields, free);
	if (!((*curr)->tag & TAG_STICK) && *strs[AFTER] == '\0' &&
		*tok_lst_last(fields)->content == '\0')
		ft_lstpop_back((t_ftlst **)&fields, free);
	if (fields != NULL && fields->next == NULL)
	{
		(*curr)->content =
			ft_strjoin3(strs[BEFORE], fields->content, strs[AFTER]);
		free(strs[BEFORE]);
		tok_lst_destroy(&fields, free);
		return (i + len);
	}
	else if (fields != NULL)
		return (st_merge_fields_in_curr(strs, curr, fields, len));
	return (i);
}

size_t				interpolate(
	void *ptrs[2], size_t i, enum e_tok prev_tag, t_env env)
{
	char		*strs[3];
	char		*str;
	t_tok_lst	**curr;

	str = ptrs[INTERPOLATION_STR];
	curr = ptrs[INTERPOLATION_CURR];
	if (!st_make_strs(strs, env, str, i))
		return (i);
	if ((*curr)->tag & TAG_STR_DOUBLE)
	{
		(*curr)->content = ft_strjoin3(strs[BEFORE], strs[MATCH], strs[AFTER]);
		free(strs[BEFORE]);
		return (i + ft_strlen(strs[MATCH]));
	}
	return (st_interpolate_non_quoted(strs, curr, i, prev_tag));
}