Студопедия.Орг Главная | Случайная страница | Контакты | Мы поможем в написании вашей работы!  
 

Массив environ



Теперь, когда мы разобрались, что такое окружение, самое время написать программу для взаимодействия с окружением. Чтобы показать, как это все работает, сначала изобретем велосипед.

В заголовочном файле 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 | Нарушение авторского права страницы | Мы поможем в написании вашей работы!



studopedia.org - Студопедия.Орг - 2014-2024 год. Студопедия не является автором материалов, которые размещены. Но предоставляет возможность бесплатного использования (0.021 с)...