aboutsummaryrefslogtreecommitdiff
path: root/src/env.c
blob: f4bc031712296b0064c98efd950bf155ca8bcdb9 (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
157
158
159
160
161
162
/* ************************************************************************** */
/*                                                                            */
/*                                                        :::      ::::::::   */
/*   env.c                                              :+:      :+:    :+:   */
/*                                                    +:+ +:+         +:+     */
/*   By: cacharle <marvin@42.fr>                    +#+  +:+       +#+        */
/*                                                +#+#+#+#+#+   +#+           */
/*   Created: 2020/02/28 09:21:24 by cacharle          #+#    #+#             */
/*   Updated: 2020/10/10 18:08:17 by charles          ###   ########.fr       */
/*                                                                            */
/* ************************************************************************** */

/*
** \file   env.c
** \brief  Environment manipulation
*/

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

#define ENV_VEC_DEFAULT_SIZE 64

/*
** \brief       Convert array of string to environment hash table
** \param envp  array of string (each in the format `name=value`)
** \return      Environment hash table or NULL on error
*/

t_env		env_from_array(char **envp)
{
	t_env	env;

	if ((env = ft_vecnew(ENV_VEC_DEFAULT_SIZE)) == NULL)
		return (NULL);
	while (*envp != NULL)
	{
		if (ft_vecpush_safe(env, ft_strdup(*envp)) == NULL)
		{
			ft_vecdestroy(env, free);
			return (NULL);
		}
		envp++;
	}
	return (ft_vecpush(env, NULL));
}

/*
** \brief              Search a key in environment
** \param env          Searched environment
** \param key          Searched key
** \param found_index  If found_index != NULL and key is found
**                     put the index in the env array of key in found_index
** \return             Value after '=' in environment variable array
**                     or NULL if not found
*/

char		*env_search(t_env env, char *key, size_t *found_index)
{
	size_t	i;
	size_t	key_len;

	i = 0;
	while (i < env->size - 1)
	{
		key_len = ft_strlen(key);
		if (ft_strncmp(env->data[i], key, key_len) == 0
			&& ft_strlen(env->data[i]) > key_len
			&& ((char**)env->data)[i][key_len] == '=')
		{
			if (found_index != NULL)
				*found_index = i;
			return (ft_strchr(env->data[i], '=') + 1);
		}
		i++;
	}
	return (NULL);
}

/*
** \brief        Insert or update an environment variable
** \param env    Updated environment
** \param key    Name of the variable to update
** \param value  New value of the variable
** \return       The full variable (i.e `key=value`) or NULL on error
*/

char		*env_export(t_env env, char *key, char *value)
{
	char	*joined;
	size_t	found_index;

	if ((joined = ft_strjoin3(key, "=", value)) == NULL)
		return (NULL);
	if (env_search(env, key, &found_index) == NULL)
	{
		if (ft_vecinsert(env, env->size - 1, joined) == NULL)
			return (NULL);
	}
	else
	{
		free(env->data[found_index]);
		env->data[found_index] = joined;
	}
	return (joined);
}

/*
** \brief   Buffer containning the string representation of the status code
**          and returned by env_search_first_match if asked for $?
*/

static char	g_status_buf[64] = {'\0'};

/*
** \brief           Search the environment for a potential key located
**                  at the start of haystack
** \param haystack  Potential key
** \return          The value assiciated with the key or NULL if not found
*/

char		*env_search_first_match(t_env env, const char *haystack)
{
	size_t	len;
	size_t	i;
	size_t	key_len;

	if (!ft_isalnum(*haystack) && *haystack != '_' && *haystack != '?')
		return ("$");
	if (ft_isdigit(*haystack))
		return (NULL);
	len = 0;
	while (ft_isalnum(haystack[len]) || haystack[len] == '_')
		len++;
	if (haystack[0] == '?')
		return (ft_itoa_cpy(g_status_buf, g_state.last_status));
	if (len == 0)
		return (NULL);
	i = -1;
	while (++i < env->size - 1)
	{
		key_len = ft_strchr(env->data[i], '=') - (char*)env->data[i];
		if (len != key_len)
			continue ;
		if (ft_strncmp((char*)env->data[i], haystack, len) == 0)
			return (ft_strchr(env->data[i], '=') + 1);
	}
	return (NULL);
}

size_t		env_key_len(char *key, bool allow_status)
{
	size_t	i;

	if (allow_status && *key == '?')
		return (1);
	if (ft_isdigit(*key))
		return (0);
	i = 0;
	while (ft_isalnum(key[i]) || key[i] == '_')
		i++;
	return (i);
}