i am implementing setenv && unsetenv
My logic is to edit the .bashrc file, seeing as using IPC didn't work for me
My problem is with the _unsetenv function, when I try to remove an environment variable, it removes it but adds extra text to the last line
for example, I have these variable set(from line 122 - 126) and i want to delete 'FOO':
export R='make re'
export FOO=BAR
export PATH=/home/marlon/learning_programming/C/shell:$PATH
export CRAB=VALUE
export SOME='CHANGED'
now after executing _unsetenv my .bashrc file looks like this:
export R='make re'
export PATH=/home/marlon/learning_programming/C/shell:$PATH
export CRAB=VALUE
export SOME='CHANGED'
SOME='CHANGED'
why is it adding the line: SOME='CHANGED'?
here's some helper functions:
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/mman.h>
/**
* string_count - counts the words in a string separated by a delimiter
* and the letters befor a delimiter.
* @str: string to be counted.
* @token: string of delimiters.
*
* Return: an array of:
* a pointer to the number of words
* an array of the letters before each delimiter.
*/
int **string_count(char *str, char *token)
{
int words, *before_delim, letters, i, j, k;
int **how_many;
char flag;
how_many = malloc(sizeof(int *) * 2);
if (!how_many)
return (NULL);
words = 0;
for (i = 0; str[i]; i++)
{
for (j = 0; token[j]; j++)
{
if (str[i] == token[j])
words++;
}
}
words++;
/* count the letters before delimiters */
before_delim = malloc(sizeof(int) * words);
if (!before_delim)
return (NULL);
i = 0;
for (k = 0; k < words; k++)
{
flag = 0;
letters = 0;
for (; str[i]; i++)
{
for (j = 0; token[j]; j++)
{
if (str[i] == token[j])
{
flag = 1;
i++;
}
}
if (flag)
{
break;
}
else
letters++;
}
before_delim[k] = letters;
}
how_many[0] = &words;
how_many[1] = before_delim;
return (how_many);
}
/**
* file_count - counts a file.
* Description: COUNT[0]: number of lines in the file
* COUNT[1]: line number where sub occurs, 0 if not found or empty.
* COUNT[2]: number of letters on each line.
* A string can be searched for in a file using sub.
* Set sub to "" if no string should be searched for.
* @stream: an opened file descriptor.
* @sub: an optional string to be searched for in a file.
* Can be set to "" for no search.
*
* Return: an array of pointers on the heap to:
* the number of lines in the file
* the line number where sub occurs
* the number of letters on each line
*/
int **file_count(char *filename, char *sub)
{
char *buffer = 0, flag = 0;
size_t n = 0, l1;
ssize_t nread;
FILE *stream;
int **count, i, j, k;
int *letters;
/* opening file */
stream = fopen(filename, "r");
if (!stream)
return (NULL);
count = malloc(sizeof(int *) * 3);
if (!count)
return (NULL);
i = j = 0;
count[0] = 0;
l1 = strlen(sub);
/* reading file line by line */
while ((nread = getline(&buffer, &n, stream)) != -1)
{
/* if found string to be searched, stop incrementing j */
if (!(strncmp(sub, buffer, l1)))
{
j++;
flag = 1;
}
/* counting lines */
i++;
/* counting till string to be searched for is found */
if (flag == 0)
j++;
}
if (!l1 || !flag)
j = 0;
count[0] = &i;
count[1] = &j;
/* closing file for letter count */
free(buffer);
fclose(stream);
/* counting letters on each line */
/* opening file */
stream = fopen(filename, "r");
if (!stream)
return (NULL);
letters = malloc(sizeof(int) * i);
if (!letters)
return (NULL);
buffer = 0;
n = 0;
i = 0;
while ((nread = getline(&buffer, &n, stream)) != -1)
{
for (k = 0; buffer[k]; k++)
;
letters[i] = k;
i++;
}
count[2] = letters;
free(buffer);
fclose(stream);
return (count);
}
/**
* strsplt - splits a string by delimiter into an array of each word of the string.
* @str: string to split.
* @token: string of delimiters.
* @new_delim: string to split new array by.
*
* Return: a new array of strings.
*/
char **strsplt(char *str, char *token, char new_delim)
{
char **split;
int *array;
int index, watch, assign, letters;
int **str_count, wc;
str_count = string_count(str, token);
wc = **str_count;
split = malloc(sizeof(char *) * (wc + 1));
if (!split)
return (NULL);
array = str_count[1];
assign = 0;
for (index = 0; index < wc; index++)
{
letters = array[index];
split[index] = malloc(sizeof(char) * letters + 2);
if (!split[index])
return (NULL);
for (watch = 0; watch < letters; watch++)
{
split[index][watch] = str[assign++];
}
assign++;
split[index][watch] = new_delim;
split[index][watch + 1] = 0;
}
split[index] = NULL;
free(str_count);
free(array);
return (split);
}
here is _unsetenv with main:
/**
* _unsetenv - removes an environment variable.
* @name: variable to be removed.
*
* Return: zero on success, or -1 on error.
*/
int _unsetenv(const char *name)
{
char *map, *to_search, **split, **temp_split;
char *shell, *home, *filename;
size_t ln;
int s_size, **f_count, occurrence, i = 0;
int ls, lh, f_size, f_d, lines, j;
struct stat st;
FILE *stream;
map = NULL;
split = NULL;
ln = strlen(name);
/* checking for errors */
if (!name || !ln || strchr(name, '='))
{
errno = EINVAL;
return (-1);
}
/* creating variable to search for */
s_size = 7 + ln + 2;
to_search = malloc(sizeof(char) * s_size);
if (!to_search)
return (-1);
strcpy(to_search, "export ");
strcat(to_search, name);
strcat(to_search, "=");
/* creating filename */
home = getenv("HOME");
lh = strlen(home);
/* getting shell name */
shell = getenv("SHELL");
shell = &shell[5];
ls = strlen(shell);
/* creating file to open */
f_size = lh + 2 + ls + 3;
filename = malloc(sizeof(char) * f_size);
if (!filename)
return (-1);
strcpy(filename, home);
strcat(filename, "/.");
strcat(filename, shell);
strcat(filename, "rc");
/* searching for variable */
f_count = file_count(filename, to_search);
occurrence = f_count[1][0];
lines = **f_count;
temp_split = malloc(sizeof(char) * lines - 1);
if (!temp_split)
return (0);
/* if variable doesn't exist, return success */
if (!occurrence)
return (0);
/* else remove it */
else
{
/* open filename */
stream = fopen(filename, "r+");
if (!stream)
return (-1);
f_d = stream->_fileno;
if (fstat(f_d, &st) == -1)
return (-1);
map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, f_d, 0);
/* splitting string to edit file */
split = strsplt(map, "\n", '\n');
free(split[occurrence - 1]);
split[occurrence - 1] = NULL;
for (j = 0; j < lines - 1; j++, i++)
{
if (j == occurrence - 1)
i++;
temp_split[j] = split[i];
if (fputs(temp_split[j], stream) == EOF)
return (-1);
printf("temp_split[%d]: %s\n", j, temp_split[j]);
}
return (0);
}
return (-1);
}
/**
* main - tests _unsetenv().
* @argc: argument count.
* argv: argument vector.
*
* Return: 0.
*/
int main(void)
{
int i;
char *name = "FOO";
if ((i = _unsetenv(name)) == -1)
printf("%s not removed\n", name);
else
printf("%s removed\n", name);
return (0);
}