Главная Случайная страница Контакты | Мы поможем в написании вашей работы! | ||
|
Теперь, когда мы разобрались, что такое окружение, самое время написать программу для взаимодействия с окружением. Чтобы показать, как это все работает, сначала изобретем велосипед.
В заголовочном файле unistd.h объявлен внешний двумерный массив environ:
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
extern char ** environ;
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
В этом массиве хранится копия окружения процесса. Массив не константный, но не рекомендуется изменять его - это опасно (для программы) и является плохим стилем программирования. Для изменения environ есть специальные механизмы, которые мы рассмотрим чуть позже.
Напишем одноименную программу (environ), которой в качестве аргумента передается имя переменной. Программа будет проверять, существует ли эта переменная в окружении, и если существует, то каково ее значение. Как мы позже узнаем, это можно было бы сделать значительно проще.
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/* environ.c */
#include<stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
extern char ** environ; /* Environment itself */
int main (int argc, char ** argv)
{
int i;
if (argc < 2)
{
fprintf (stderr, "environ: Too few arguments\n");
fprintf (stderr, "Usage: environ <variable>\n");
exit (1);
}
for (i = 0; environ[i]!= NULL; i++)
{
if (!strncmp (environ[i], argv[1], strlen (argv[1])))
{
printf ("'%s' found\n", environ[i]);
exit (0);
}
}
printf ("'%s' not found\n", argv[1]);
exit (0);
}
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
А вот Make file для этой программы:
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
# Makefile for environ
environ: environ.c
gcc -o environ environ.c
clean:
rm -f environ
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Проверяем:
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
$ make
gcc -o environ environ.c
$./environ
environ: Too few arguments
Usage: environ <variable>
$./environ USER
'USER=df00' found
$./environ ABRAKADABRA
'ABRAKADABRA' not found
$
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
В приведенном примере мы осуществили простой синтаксический анализ массива environ, так как переменные и значения представлены в нем в обычном виде (ПЕРЕМЕННАЯ=ЗНАЧЕНИЕ).
Чтение окружения: getenv()
В заголовочном файле stdlib.h объявлена функция getenv, которая доказывает, что в предыдущем примере мы изобрели велосипед. Ниже приведен адаптированный прототип этой функции.
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
char * getenv (const char * name);
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Функция эта работает очень просто: если в качестве аргумента указано имя существующей переменной окружения, то функция возвращает указатель на строку, содержащую значение этой переменной; если переменная отсутствует, возвращается NULL.
Как видим, функция getenv() позволяет не осуществлять синтаксический разбор environ. Напишем новую программу, которая делает то же, что и предыдущая, только более простым способом. Назовем ее getenv по имени функции.
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/* getenv.c */
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char ** argv)
{
if (argc < 2)
{
fprintf (stderr, "getenv: Too few arguments\n");
fprintf (stderr, "Usage: getenv <variable>\n");
exit (1);
}
char * var = getenv (argv[1]);
if (var == NULL)
{
printf ("'%s' not found\n", argv[1]);
exit (0);
}
printf ("'%s=%s' found\n", argv[1], var);
exit (0);
}
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Запись окружения: setenv()
Пришла пора модифицировать окружение! Еще раз напоминаю: каждый процесс получает не доступ к окружению, а копию окружения родительского процесса (в нашем случае это командная оболочка). Чтобы добавить в окружение новую переменную или изменить существующую, используется функция setenv, объявленная в файле stdlib.h. Ниже приведен адаптированный прототип этой функции.
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
int setenv (const char * name, const char * value, int overwrite);
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Функция setenv() устанавливает значение (второй аргумент, value) для переменной окружения (первый аргумент, name). Третий аргумент - это флаг перезаписи. При ненулевом флаге уже существующая переменная перезаписывается, при нулевом флаге переменная, если уже существует, - не перезаписывается. В случае успешного завершения setenv() возвращает нуль (даже если существующая переменная не перезаписалась при overwrite==0). Если в окружении нет места для новой переменной, то setenv() возвращает -1.
Наша новая программа setenv читает из командной строки два аргумента: имя переменной и значение этой переменной. Если переменная не может быть установлена, выводится ошибка, если ошибки не произошло, выводится результат в формате ПЕРЕМЕННАЯ=ЗНАЧЕНИЕ. Вот эта программа:
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/* setenv.c */
#include <stdio.h>
#include <stdlib.h>
#define FL_OVWR 0 /* Overwrite flag. You may change it. */
int main (int argc, char ** argv)
{
if (argc < 3)
{
fprintf (stderr, "setenv: Too few arguments\n");
fprintf (stderr,
"Usage: setenv <variable><value>\n");
exit (1);
}
if (setenv (argv[1], argv[2], FL_OVWR)!= 0)
{
fprintf (stderr, "setenv: Cannot set '%s'\n", argv[1]);
exit (1);
}
printf ("%s=%s\n", argv[1], getenv (argv[1]));
exit (0);
}
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Изменяя константу FL_OVWR можно несколько изменить поведение программы по отношению к существующим переменным окружения. Еще раз напоминаем: у каждого процесса своя копия окружения, которая уничтожается при завершении процесса. Экспериментируйте!
Сырая модификация окружения: putenv()
Функция putenv(), объявленная в заголовочном файле stdlib.h вызывается с единственным аргументом - строкой формата ПЕРЕМЕННАЯ=ЗНАЧЕНИЕ или просто ПЕРЕМЕННАЯ. Обычно такие преформатированные строки называют запросами. Если переменная отсутствует, то в окружение добавляется новая запись. Если переменная уже существует, то текущее значение перезаписывается. Если в качестве аргумента фигурирует просто имя переменной, то переменная удаляется из окружения. В случае удачного завершения, putenv() возвращает нуль и -1 - в случае ошибки.
У функции putenv() есть одна особенность: указатель на строку, переданный в качестве аргумента, становится частью окружения. Если в дальнейшем строка будет изменена, будет изменено и окружение. Это очень важный момент, о котором не следует забывать. Ниже приведен адаптированный прототип функции putenv:
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
int putenv (char * str);
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Теперь напишем программу, использующую putenv().
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/* putenv.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define QUERY_MAX_SIZE 32
char * query_str;
void print_evar (const char * var)
{
char * tmp = getenv (var);
if (tmp == NULL)
{
printf ("%s is not set\n", var);
return;
}
printf ("%s=%s\n", var, tmp);
}
int main (void)
{
int ret;
query_str = (char *) calloc (QUERY_MAX_SIZE, sizeof(char));
if (query_str == NULL) abort ();
strncpy (query_str, "FOO=foo_value1", QUERY_MAX_SIZE-1);
ret = putenv (query_str);
if (ret!= 0) abort ();
print_evar ("FOO");
strncpy (query_str, "FOO=foo_value2", QUERY_MAX_SIZE-1);
print_evar ("FOO");
strncpy (query_str, "FOO", QUERY_MAX_SIZE-1);
ret = putenv (query_str);
if (ret!= 0) abort ();
print_evar ("FOO");
free (query_str);
exit (0);
}
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Программа немного сложнее тех, что приводились ранее, по – этому разберем все по порядку. Сначала создаем для удобства функцию print_evar (PRINTEnvironmentVARiable), которая будет отражать текущее состояние переменной окружения, переданной в качестве аргумента. В функции main() сначала выделяем в куче (heap) память для буфера, в который будут помещаться запросы; заносим адрес буфера в query_str. Теперь формируем строку, и посылаем запрос в функцию putenv(). Здесь нет ничего необычного. Дальше изменение содержимого памяти по адресу, хранящемуся в query_str приводит к изменению окружения; это видно из вывода функции print_evar(). Наконец, вызываем putenv() со строкой, не содержащей символа '=' (равно). Это запрос на удаление переменной из окружения. Функция print_evar() подтверждает это.
Заметим, что putenv() поддерживается не всеми версиями Unix. Если нет крайней необходимости, лучше использовать setenv() для пополнения/модификации окружения.
Удаление переменной окружения: unsetenv()
Функция unsetenv(), объявленная в stdlib.h, удаляет переменную из окружения. Ниже приведен адаптированный прототип этой функции.
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
int unsetenv (const char * name);
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Прежде всего, обратим внимание на то, что раньше функция unsetenv() ничего не возвращала (void). С выходом версии 2.2.2 библиотеки glibc (январь 2001 года) функция стала возвращать int.
Функция unsetenv() использует в качестве аргумента имя переменной окружения. Возвращаемое значение - нуль при удачном завершении и -1 в случае ошибки. Рассмотрим простую программу, которая удаляет переменную окружения USER (!!!). Каждый процесс работает с собственной копией окружения, никак не связанной с копиями окружения других процессов, за исключением дочерних процессов, которых у нас нет. Ниже приведен исходный код программы, учитывающий исторические изменения прототипа функции unsetenv().
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/* unsetenv.c */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <gnu/libc-version.h>
#define OLD_LIBC_VERSION 0
#define NEW_LIBC_VERSION 1
#define E_VAR "USER"
int libc_cur_version (void)
{
int ret = strcmp (gnu_get_libc_version (), "2.2.2");
if (ret < 0) return OLD_LIBC_VERSION;
return NEW_LIBC_VERSION;
}
int main (void)
{
int ret;
char * str;
if (libc_cur_version () == OLD_LIBC_VERSION)
{
unsetenv (E_VAR);
} else
{
ret = unsetenv (E_VAR);
if (ret!= 0)
{
fprintf (stderr, "Cannot unset '%s'\n", E_VAR);
exit (1);
}
}
str = getenv (E_VAR);
if (str == NULL)
{
printf ("'%s' has removed from environment\n", E_VAR);
} else
{
printf ("'%s' hasn't removed\n", E_VAR);
}
exit (0);
}
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
В программе показан один из самых «варварских» способов подстроить код под версию библиотеки. Это сделано исключительно для демонстрации двух вариантов unsetenv(). Никогда не делайте так в реальных программах. Намного проще и дешевле (в плане времени), не получая ничего от unsetenv() проверить факт удаления переменной при помощи getenv().
Очистка окружения: clearenv()
Функция clearenv(), объявленная в заголовочном файле stdlib.h, используется крайне редко для полной очистки окружения. clearenv() поддерживается не всеми версиями Unix.
Ниже приведен ее прототип.
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
int clearenv (void);
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
При успешном завершении clearenv() возвращает нуль. В случае ошибки возвращается ненулевое значение.
В большинстве случаев вместо clearenv() можно использовать следующую инструкцию:
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
environ = NULL;
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Дата публикования: 2014-11-29; Прочитано: 219 | Нарушение авторского права страницы | Мы поможем в написании вашей работы!