int priority, const char
#include <syslog.h> void syslog ( int priority, const char *message, ... /* аргументы */); int setlogmask (int maskpri); void openlog (const char *ident, int logopt, int facility); void closelog (void); |
Листинг 9.1. Описание функций для работы с системным журналом. |
Закрыть окно |
/* * * * * * * * * * * * * * * * * */ /* Пример использования функций */ /* для работы с системным журналом */ /* * * * * * * * * * * * * * * * * */ #include <stdio.h> #include <syslog.h> int main (void) { int logmask; /* Прежняя маска журналирования */ /* Будем включать в журналируемые сообщения */ /* идентификатор процесса и выдавать их при */ /* возникновении проблем на системную консоль */ openlog ("Intuit syslog test", LOG_PID | LOG_CONS, LOG_USER); /* Пренебрежем предупреждениями и менее серьезными сообщениями */ logmask = setlogmask (LOG_MASK (LOG_EMERG) | LOG_MASK (LOG_ALERT) | LOG_MASK (LOG_CRIT) | LOG_MASK (LOG_ERR)); printf ("Подразумеваемая маска журналирования: %x\n", logmask); /* Поместим сообщение в журнал */ syslog (LOG_ALERT | LOG_USER, "Как читать системный журнал?"); /* Восстановим прежнюю маску журналирования */ (void) setlogmask (logmask); closelog (); return 0; } |
Листинг 9.2. Пример применения функций для работы с системным журналом. |
Закрыть окно |
Подразумеваемая маска журналирования: ff |
Листинг 9.3. Возможные результаты применения функций для работы с системным журналом. |
Закрыть окно |
#include <fmtmsg.h> int fmtmsg ( long classification, const char *label, int severity, const char *text, const char *action, const char *tag); |
Листинг 9.4. Описание функции fmtmsg(). |
Закрыть окно |
#include <stdio.h> #include <fmtmsg.h> int main (void) { if (fmtmsg (MM_SOFT + MM_OPSYS + MM_RECOVER + MM_PRINT + MM_CONSOLE, "POSIX:fmtmsg", MM_INFO, "Отсутствует функция fmtmsg()", "Установите функцию fmtmsg() или не пользуйтесь ею\n", "См. functions/fmtmsg.html") != MM_OK) { perror ("FMTMSG"); return (1); } return 0; } |
Листинг 9.5. Пример использования функции fmtmsg(). |
Закрыть окно |
POSIX:fmtmsg: INFO: Отсутствует функция fmtmsg() TO FIX: Установите функцию fmtmsg() или не пользуйтесь ею См. functions/fmtmsg.html |
Листинг 9.6. Возможные результаты выполнения программы, использующей функцию fmtmsg(). |
Закрыть окно |
#include <utmpx.h> struct utmpx *getutxent (void); struct utmpx *getutxid ( const struct utmpx *id); struct utmpx *getutxline ( const struct utmpx *line); struct utmpx *pututxline ( const struct utmpx *utmpx); void setutxent (void); void endutxent (void); |
Листинг 9.7. Описание функций для работы с базой данных учетной информации о пользователях. |
Закрыть окно |
/* * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Пример использования функций для работы */ /* с базой данных учетной информации о пользователях */ /* * * * * * * * * * * * * * * * * * * * * * * * * * */ #include <stdio.h> #include <limits.h> #include <time.h> #include <utmpx.h> #include <string.h> int main (void) { struct utmpx *utmpx_ptr; /* Указатель на текущую запись */ char dtbuf [LINE_MAX]; /* Буфер для данных о времени */ struct utmpx spat; /* Шаблон для поиска в базе */ /* Прочитаем и распечатаем все записи в базе */ printf ("Содержимое базы данных учетной информации " "о пользователях\n"); while ((utmpx_ptr = getutxent ()) != NULL) { (void) strftime (dtbuf, sizeof (dtbuf), "%c", localtime (&(utmpx_ptr->ut_tv.tv_sec))); switch (utmpx_ptr->ut_type) { case EMPTY: printf ("Пустая запись\n"); break; case BOOT_TIME: printf ("Время загрузки системы: %s\n", dtbuf); break; case OLD_TIME: printf ("Время изменения показаний системных " "часов: %s\n", dtbuf); break; case NEW_TIME: printf ("Показания системных часов после " "изменения: %s\n", dtbuf); break; case USER_PROCESS: printf ("Процесс пользователя: %s, идентификатор: " "%d,\n", utmpx_ptr->ut_user, utmpx_ptr->ut_pid); printf ("Инициализационный идентификатор процесса: " "%s,\n", utmpx_ptr->ut_id); printf ("Имя устройства: %s,\n", utmpx_ptr->ut_line); printf ("Время создания записи: %s\n", dtbuf); break; case LOGIN_PROCESS: printf ("Входной процесс: %s, идентификатор: %d,\n", utmpx_ptr->ut_user, utmpx_ptr->ut_pid); printf ("Инициализационный идентификатор процесса: " "%s,\n", utmpx_ptr->ut_id); printf ("Время создания записи: %s\n", dtbuf); break; case INIT_PROCESS: printf ("Процесс, порожденный системным процессом " "init:\n"); printf ("Идентификатор: %d,\n", utmpx_ptr->ut_pid); printf ("Инициализационный идентификатор процесса: " "%s,\n", utmpx_ptr->ut_id); printf ("Время создания записи: %s\n", dtbuf); break; case DEAD_PROCESS: printf ("Лидер сеанса, завершивший выполнение:\n"); printf ("Идентификатор: %d,\n", utmpx_ptr->ut_pid); printf ("Инициализационный идентификатор процесса: " "%s,\n", utmpx_ptr->ut_id); printf ("Время создания записи: %s\n", dtbuf); break; default: printf ("Нестандартный тип записи: %x\n", utmpx_ptr->ut_type); break; } } /* Найдем и распечатаем записи, */ /* инициализационный идентификатор которых */ /* равняется S4 */ spat.ut_type = INIT_PROCESS; (void) strncpy (spat.ut_id, "S4", sizeof (spat.ut_id)); /* Позиционируемся на начало базы */ setutxent (); printf ("Записи, инициализационный идентификатор " "которых равняется S4:\n"); while ((utmpx_ptr = getutxid (&spat)) != NULL) { switch (utmpx_ptr->ut_type) { case USER_PROCESS: printf ("Процесс пользователя: %s, " "идентификатор: %d\n", utmpx_ptr->ut_user, utmpx_ptr->ut_pid); break; case LOGIN_PROCESS: printf ("Входной процесс: %s, идентификатор: " "%d\n",utmpx_ptr->ut_user, utmpx_ptr->ut_pid); break; case INIT_PROCESS: printf ("Процесс, порожденный системным процессом " "init:\n"); printf ("Идентификатор: %d\n", utmpx_ptr->ut_pid); break; case DEAD_PROCESS: printf ("Лидер сеанса, завершивший " "выполнение:\n"); printf ("Идентификатор: %d\n", utmpx_ptr->ut_pid); break; default: printf ("Нестандартный тип результата поиска: " "%x\n", utmpx_ptr->ut_type); break; } /* Обеспечим сдвиг поиска с текущей записи */ utmpx_ptr->ut_id [0] = 0; } endutxent (); return 0; } |
Листинг 9.8. Пример применения функций для работы с базой данных учетной информации о пользователях. |
Закрыть окно |
Содержимое базы данных учетной информации о пользователях Лидер сеанса, завершивший выполнение: Идентификатор: 17, Инициализационный идентификатор процесса: si, Время создания записи: Tue Apr 27 10:08:42 2004 Время загрузки системы: Tue Apr 27 10:08:42 2004 Нестандартный тип записи: 1 Лидер сеанса, завершивший выполнение: Идентификатор: 284, Инициализационный идентификатор процесса: l5, Время создания записи: Tue Apr 27 10:09:15 2004 Лидер сеанса, завершивший выполнение: Идентификатор: 1115, Инициализационный идентификатор процесса: ud, Время создания записи: Tue Apr 27 10:09:15 2004 . . . Входной процесс: LOGIN, идентификатор: 1123, Инициализационный идентификатор процесса: S3, Время создания записи: Tue Apr 27 10:09:15 2004 Процесс пользователя: galat, идентификатор: 1124, Инициализационный идентификатор процесса: S4, Имя устройства: ttyS4, Время создания записи: Tue Apr 27 12:52:51 2004 Процесс пользователя: sambor, идентификатор: 1125, Инициализационный идентификатор процесса: S5, Имя устройства: ttyS5, Время создания записи: Tue Apr 27 13:57:31 2004 Процесс пользователя: kost, идентификатор: 1126, Инициализационный идентификатор процесса: S6, Имя устройства: ttyS6, Время создания записи: Tue Apr 27 10:09:30 2004 . . . Процесс, порожденный системным процессом init: Идентификатор: 1128, Инициализационный идентификатор процесса: x, Время создания записи: Tue Apr 27 10:09:15 2004 . . . Лидер сеанса, завершивший выполнение: Идентификатор: 11708, Инициализационный идентификатор процесса: /1, Время создания записи: Tue Apr 27 11:19:33 2004 . . . Записи, инициализационный идентификатор которых равняется S4: Процесс пользователя: galat, идентификатор: 1124 |
Листинг 9.9. Фрагмент возможных результатов выполнения программы, применяющей функции для работы с базой данных учетной информации о пользователях. |
Закрыть окно |
#include <ndbm.h> DBM *dbm_open (const char *file, int open_flags, mode_t file_mode); void dbm_close (DBM *db); datum dbm_fetch (DBM *db, datum key); int dbm_store (DBM *db, datum key, datum content, int store_mode); int dbm_delete (DBM *db, datum key); datum dbm_firstkey (DBM *db); datum dbm_nextkey (DBM *db); int dbm_error (DBM *db); int dbm_clearerr (DBM *db); |
Листинг 9.10. Описание функций для работы с простыми базами данных. |
Закрыть окно |
/* * * * * * * * * * * * * * * * * * * * * * * * */ /* Программа перебирает все ключи в базе данных */ /* и выдает ассоциированную с ними информацию. */ /* Предполагается, что ключи и данные – текстовые*/ /* * * * * * * * * * * * * * * * * * * * * * * * */ #include <ndbm.h> #include <stdio.h> #include <fcntl.h> int main (int argc, char *argv []) { DBM *dbdes; /* Дескриптор открытой базы */ datum ckey; /* Текущий ключ */ datum cdat; /* Текущие данные */ int nkeys = 0; /* Число ключей */ if (argc != 2) { fprintf (stderr, "Использование: %s имя_базы\n", argv [0]); return (1); } if ((dbdes = dbm_open (argv [1], O_RDONLY, 0777)) == (DBM *) NULL) { fprintf (stderr, " Не удалось открыть базу данных %s\n", argv [1]); return (2); } for (ckey = dbm_firstkey (dbdes); ckey.dptr != NULL; ckey = dbm_nextkey (dbdes)) { nkeys++; printf ("Длина ключа номер %d: %d\n", nkeys, ckey.dsize); printf ("Ключ номер %d: %s\n", nkeys, ckey.dptr); if (cdat = dbm_fetch (dbdes, ckey), cdat.dptr != NULL) { printf ("Длина данных для ключа номер %d: %d\n", nkeys, cdat.dsize); printf ("Данные для ключа номер %d: %s\n", nkeys, cdat.dptr); } else { fprintf (stderr, "Отсутствуют данные для " "ключа номер %d\n", nkeys); } } printf ("Число ключей в базе: %d\n", nkeys); dbm_close (dbdes); return 0; } |
Листинг 9.11. Пример применения функций для работы с простыми базами данных. |
Закрыть окно |
Длина ключа номер 1: 16 Ключ номер 1: YP_LAST_MODIFIED Длина данных для ключа номер 1: 10 Данные для ключа номер 1: 0898782331 Длина ключа номер 2: 14 Ключ номер 2: mailer-daemon Длина данных для ключа номер 2: 11 Данные для ключа номер 2: postmaster Длина ключа номер 3: 14 Ключ номер 3: YP_MASTER_NAME Длина данных для ключа номер 3: 3 Данные для ключа номер 3: t41 Длина ключа номер 4: 11 Ключ номер 4: postmaster Длина данных для ключа номер 4: 5 Данные для ключа номер 4: root Длина ключа номер 5: 7 Ключ номер 5: nobody Длина данных для ключа номер 5: 10 Данные для ключа номер 5: /dev/null Длина ключа номер 6: 2 Ключ номер 6: @ Длина данных для ключа номер 6: 2 Данные для ключа номер 6: @ Число ключей в базе: 6 |
Листинг 9.12. Возможные результаты выполнения программы, применяющей функции для работы с простыми базами данных. |
Закрыть окно |
#include <stdlib.h> void *bsearch (const void *key, const void *base, size_t nel, size_t width, int (*compar) (const void *, const void *)); |
Листинг 9.13. Описание функции бинарного поиска bsearch(). |
Закрыть окно |
#include <stdlib.h> void qsort (void *base, size_t nel, size_t width, int (*compar) (const void *, const void *)); |
Листинг 9.14. Описание функции быстрой сортировки qsort(). |
Закрыть окно |
/* * * * * * * * * * * * * * * * * * * * * */ /* Программа сортирует массив указателей */ /* на случайные цепочки символов, а затем */ /* выполняет в этом массиве бинарный поиск */ /* * * * * * * * * * * * * * * * * * * * * */ #include <stdlib.h> #include <stdio.h> #include <string.h> /* Размер области для хранения цепочек символов */ #define SPACE_SIZE 10000000 /* Число элементов в таблице указателей на цепочки символов */ #define TAB_SIZE 1000000 /* Длина одной цепочки символов */ /* (включая завершающий нулевой байт) */ #define STRING_SIZE 10 /* Область для хранения цепочек символов */ static char StringSpace [SPACE_SIZE]; /* Массив указателей на цепочки символов */ static char *PtsTable [TAB_SIZE]; /* Число занятых элементов в массиве указателей */ static size_t nelst; /* * * * * * * * * * * * * * * * * * * * * */ /* Формирование случайной цепочки символов */ /* * * * * * * * * * * * * * * * * * * * * */ static void str_rnd (char *buf, size_t str_siz) { for ( ; str_siz > 1; str_siz--) { *buf++ = 'A' + rand () % 26; } if (str_siz > 0) { *buf = 0; } } /* * * * * * * * * * * * * * * * * */ /* Заполнение массива указателями */ /* на случайные цепочки символов */ /* * * * * * * * * * * * * * * * * */ static void tabl_fill (void) { char *pss; /* Указатель на свободное место */ /* в области StringSpace */ int i; for (pss = StringSpace, i = 0; i < TAB_SIZE; pss += STRING_SIZE, i++) { if (((pss + STRING_SIZE) – (StringSpace + SPACE_SIZE)) > 0) { fprintf (stderr, "tabl_fill: исчерпано " "пространство цепочек\n"); nelst = i; return; } str_rnd (pss, STRING_SIZE); PtsTable [i] = pss; } nelst = TAB_SIZE; } /* * * * * * * * * * */ /* Функция сравнения */ /* * * * * * * * * * */ static int str_compar (const void *pkey, const void *pelem) { return strcoll (*((char **) pkey), *((char **) pelem)); } /* * * * * * * * * * * */ /* Сортировка и поиск */ /* * * * * * * * * * * */ int main (void) { char *skey; /* Указатель на искомую цепочку символов */ char **res; /* Результат бинарного поиска */ /* Буфер для формирования случайных цепочек */ char sbuf [STRING_SIZE]; double ntr; /* Номер найденной случайной цепочки */ /* Заполнение массивов */ tabl_fill (); /* Сортировка массива указателей */ qsort (PtsTable, nelst, sizeof (PtsTable [0]), str_compar); /* Формирование ключа поиска */ /* (будем искать первую из случайных цепочек) */ skey = StringSpace; if ((res = (char **) bsearch (&skey, PtsTable, nelst, sizeof (PtsTable [0]), str_compar)) != NULL) { printf ("Указатель на первую цепочку %s\n" "после сортировки стал %d-м элементом массива\n", skey, (res – PtsTable) / sizeof (PtsTable [0])); } else { printf ("Не удалось найти цепочку %s\n", skey); } /* Будем формировать и искать новые случайные цепочки */ skey = sbuf; ntr = 0; do { str_rnd (skey, STRING_SIZE); ntr++; } while (bsearch (&skey, PtsTable, nelst, sizeof (PtsTable [0]), str_compar) == NULL); printf ("Удалось найти %g-ю по счету случайную цепочку" " %s\n", ntr, skey); return 0; } |
Листинг 9.15. Пример применения функций быстрой сортировки и бинарного поиска. |
Закрыть окно |
Указатель на первую цепочку NWLRBBMQB после сортировки стал 133253-м элементом массива Удалось найти 168221-ю по счету случайную цепочку VBBDZTNMZ real 15.67 user 15.57 sys 0.10 |
Листинг 9.16. Возможные результаты выполнения программы, применяющей функции быстрой сортировки и бинарного поиска. |
Закрыть окно |
#include <search.h> void *lsearch (const void *key, void *base, size_t *nelp, size_t width, int (*compar) (const void *, const void *)); void *lfind (const void *key, const void *base, size_t *nelp, size_t width, int (*compar) (const void *, const void *)); |
Листинг 9.17. Описание функций последовательного поиска. |
Закрыть окно |
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Программа генерирует случайные цепочки символов до первого */ /* повторения (или до исчерпания отведенного пространства). */ /* Для выявления повторения применяется */ /* последовательный поиск с вставкой */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include <search.h> #include <stdio.h> #include <stdlib.h> #include <string.h> /* Размер области для хранения цепочек символов */ #define SPACE_SIZE 200000 /* Число элементов в таблице указателей на цепочки символов */ #define TAB_SIZE 20000 /* Длина одной цепочки символов */ /* (включая завершающий нулевой байт) */ #define STRING_SIZE 7 /* Область для хранения цепочек символов */ static char StringSpace [SPACE_SIZE]; /* Массив указателей на цепочки символов */ static char *PtsTable [TAB_SIZE]; /* * * * * * * * * * */ /* Функция сравнения */ /* * * * * * * * * * */ static int str_compar (const void *pkey, const void *pelem) { return strcoll (*((char **) pkey), *((char **) pelem)); } /* * * * * * * * * * * * * * * * * * * * * */ /* Формирование случайной цепочки символов */ /* * * * * * * * * * * * * * * * * * * * * */ static void str_rnd (char *buf, size_t str_siz) { for ( ; str_siz > 1; str_siz--) { *buf++ = 'A' + rand () % 26; } if (str_siz > 0) { *buf = 0; } } /* * * * * * * * * * * * * * * * * * * * * * * * */ /* Поиск первого повтора в последовательности */ /* случайных цепочек символов */ /* * * * * * * * * * * * * * * * * * * * * * * * */ int main (int argc, char *argv []) { char *pss; /* Указатель на свободное место */ /* в области StringSpace */ char **res; /* Результат поиска с вставкой */ size_t nelst; /* Число занятых элементов */ /* в массиве указателей */ size_t onelst; /* Число элементов в массиве */ /* до поиска с вставкой */ for (pss = StringSpace, nelst = 0; nelst < TAB_SIZE; pss += STRING_SIZE) { if (((pss + STRING_SIZE) – (StringSpace + SPACE_SIZE)) > 0) { fprintf (stderr, "%s: Исчерпано пространство " "цепочек\n", argv [0]); return (1); } str_rnd (pss, STRING_SIZE); onelst = nelst; res = (char **) lsearch (&pss, PtsTable, &nelst, sizeof (PtsTable [0]), str_compar); if (onelst == nelst) { /* Искомая цепочка уже была порождена ранее */ printf ("Для случайных цепочек длины %d\n" "первое совпадение получено на цепочке " "%s\n", STRING_SIZE, pss); printf ("Первый раз цепочка была порождена " "под номером %d,\n" "второй – под номером " "%d\n", (res – PtsTable) / sizeof (PtsTable [0]) + 1, nelst + 1); return 0; } } /* for */ printf ("Из %d случайных цепочек длины %d все " "оказались уникальными\n", TAB_SIZE, STRING_SIZE); return 0; } |
Листинг 9.18. Пример применения последовательного поиска с вставкой. |
Закрыть окно |
Для случайных цепочек длины 7 первое совпадение получено на цепочке GLPCSX Первый раз цепочка была порождена под номером 2548, второй - под номером 12530 real 34.80 user 13.70 sys 0.03 |
Листинг 9.19. Возможные результаты выполнения программы, применяющей функцию последовательного поиска с вставкой. |
Закрыть окно |
#include <search.h> int hcreate (size_t nel); void hdestroy (void); ENTRY *hsearch ( ENTRY item, ACTION action); |
Пример 9.20. Описание функций управления хэш-таблицами поиска. |
Закрыть окно |
typedef struct entry { char *key; /* Ключ поиска */ void *data; /* Дополнительные данные, */ /* ассоциированные с ключом */ } ENTRY; |
Листинг 9.21. Описание типа ENTRY. |
Закрыть окно |
enum { FIND, ENTER } ACTION; |
Листинг 9.22. Определение типа ACTION. |
Закрыть окно |
/* * * * * * * * * * * * * * * * * * * * */ /* Программа помещает в хэш-таблицу */ /* заданное число элементов с указателями*/ /* на случайные цепочки символов, */ /* а затем выполняет в этой таблице */ /* поиск новых случайных цепочек, */ /* пока он не окажется успешным */ /* * * * * * * * * * * * * * * * * * * * */ #include <search.h> #include <stdlib.h> #include <stdio.h> /* Размер области для хранения цепочек символов */ #define SPACE_SIZE 10000000 /* Число элементов, помещаемых в хэш-таблицу */ #define TAB_NEL 1000000 /* Размер хэш-таблицы */ #define TAB_SIZE (2 * TAB_NEL) /* Длина одной цепочки символов */ /* (включая завершающий нулевой байт) */ #define STRING_SIZE 10 /* Область для хранения цепочек символов */ static char StringSpace [SPACE_SIZE]; /* * * * * * * * * * * * * * * * * * * * * */ /* Формирование случайной цепочки символов */ /* * * * * * * * * * * * * * * * * * * * * */ static void str_rnd (char *buf, size_t str_siz) { for ( ; str_siz > 1; str_siz--) { *buf++ = 'A' + rand () % 26; } if (str_siz > 0) { *buf = 0; } } /* * * * * * * * * * * * * * * * * * * * * * * * */ /* Заполнение хэш-таблицы, поиск повтора в */ /* последовательности случайных цепочек символов */ /* * * * * * * * * * * * * * * * * * * * * * * * */ int main (int argc, char *argv []) { ENTRY item; /* Искомый элемент */ char sbuf [STRING_SIZE]; /* Буфер для формирования */ /* случайных цепочек */ double ntr; /* Номер найденной */ /* случайной цепочки */ size_t i; if (hcreate (TAB_SIZE) == 0) { fprintf (stderr, "%s: Не удалось создать хэш-таблицу" " размера %d\n", argv [0], TAB_SIZE); return (1); } item.data = NULL; /* Нет ассоциированных данных */ /* Заполним таблицу */ for (item.key = StringSpace, i = 0; i < TAB_NEL; item.key += STRING_SIZE, i++) { if (((item.key + STRING_SIZE) – (StringSpace + SPACE_SIZE)) > 0) { fprintf (stderr, "%s: Исчерпано пространство " "цепочек\n", argv [0]); return (2); } str_rnd (item.key, STRING_SIZE); if (hsearch (item, ENTER) == NULL) { fprintf (stderr, "%s: Переполнена хэш-таблица\n", argv [0]); return (3); } } /* for */ /* Будем формировать и искать новые случайные цепочки */ item.key = sbuf; ntr = 0; do { str_rnd (item.key, STRING_SIZE); ntr++; } while (hsearch (item, FIND) == NULL); printf ("Удалось найти %g-ю по счету случайную цепочку %s\n", ntr, item.key); hdestroy (); return 0; } |
Листинг 9.23. Пример применения функций, управляющих хэш-таблицами поиска. |
Закрыть окно |
Удалось найти 168221- ю по счету случайную цепочку VBBDZTNMZ real 9.61 user 9.36 sys 0.25 |
Листинг 9.24. Возможные результаты выполнения программы, применяющей функции управления хэш-таблицами поиска. |
Закрыть окно |
#include <search.h> void *tsearch (const void *key, void **rootp, int (*compar) (const void *, const void *)); void *tfind (const void *key, void *const *rootp, int (*compar) (const void *, const void *)); void *tdelete (const void *restrict key, void **restrict rootp, int (*compar) (const void *, const void *)); void twalk (const void *root, void (*action) (const void *, VISIT, int)); |
Листинг 9.25. Описание функций управления бинарными деревьями поиска. |
Закрыть окно |
enum { preorder, postorder, endorder, leaf } VISIT; |
Листинг 9.26. Определение типа VISIT. |
Закрыть окно |
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Программа осуществляет поиск с вставкой в бинарном */ /* дереве, помещая в него заданное число элементов с */ /* указателями на случайные цепочки символов. */ /* Затем подсчитывается число узлов и высота дерева. */ /* Следующим действием является распечатка */ /* нескольких первых цепочек. */ /* После этого выполняется поиск новых случайных цепочек,*/ /* пока он не окажется успешным. */ /* Найденный элемент удаляется из дерева */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include <search.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <setjmp.h> /* Размер области для хранения цепочек символов */ #define SPACE_SIZE 10000000 /* Число элементов, помещаемых в дерево */ #define TREE_NEL 1000000 /* Длина одной цепочки символов */ /* (включая завершающий нулевой байт) */ #define STRING_SIZE 10 /* Область для хранения цепочек символов */ static char StringSpace [SPACE_SIZE]; /* Число узлов в бинарном дереве поиска */ static size_t node_count; /* Максимальный уровень узла дерева */ static int max_level; /* Буфер для функций setjmp и longjmp */ static jmp_buf buf_env; /* * * * * * * * * * * * * * * * * * * * * */ /* Формирование случайной цепочки символов */ /* * * * * * * * * * * * * * * * * * * * * */ static void str_rnd (char *buf, size_t str_siz) { for ( ; str_siz > 1; str_siz--) { *buf++ = 'A' + rand () % 26; } if (str_siz > 0) { *buf = 0; } } /* * * * * * * * * * * * * * * * * * * * * * * * */ /* Функция, которая вызывается при обходе дерева */ /* с целью подсчета числа узлов и высоты */ /* * * * * * * * * * * * * * * * * * * * * * * * */ static void tw_nnh (const void *pnode, VISIT nv, int level) { if (nv == preorder) { node_count++; } else if (nv == leaf) { node_count++; if (level > max_level) { max_level = level; } } } /* * * * * * * * * * * * * * * * * * * * * * * * */ /* Функция, которая вызывается при обходе дерева */ /* с целью распечатки нескольких первых */ /* по алфавиту цепочек символов */ /* * * * * * * * * * * * * * * * * * * * * * * * */ static void tw_pfs (const void *pnode, VISIT nv, int level) { if (node_count <= 0) { /* Нужное число цепочек выведено,*/ /* прерываем обход дерева */ longjmp (buf_env, 1); } if ((nv == postorder) || (nv == leaf)) { printf ("%s\n", *((char **) pnode)); node_count--; } } /* * * * * * * * * * * * * * * * * * */ /* Создание бинарного дерева поиска, */ /* определение его характеристик, */ /* поиск повтора в последовательности*/ /* случайных цепочек символов */ /* * * * * * * * * * * * * * * * * * */ int main (int argc, char *argv []) { void *root; /* Указатель на корень дерева */ char *key; /* Указатель на искомую */ /* цепочку символов */ char sbuf [STRING_SIZE]; /* Буфер для формирования */ /* случайных цепочек */ double ntr; /* Номер найденной случайной */ /* цепочки */ size_t i; /* Создадим бинарное дерево поиска */ root = NULL; for (key = StringSpace, i = 0; i < TREE_NEL; key += STRING_SIZE, i++) { if (((key + STRING_SIZE) – (StringSpace + SPACE_SIZE)) > 0) { fprintf (stderr, "%s: Исчерпано пространство " "цепочек\n", argv [0]); return (1); } str_rnd (key, STRING_SIZE); if (tsearch (key, &root, (int (*) (const void *, const void *)) strcoll) == NULL) { fprintf (stderr, "%s: Поиск с вставкой в бинарное" " дерево " "завершился неудачей\n", argv [0]); return (2); } } /* for */ /* Подсчитаем число узлов и высоту созданного дерева */ node_count = 0; max_level = 0; twalk (root, tw_nnh); printf ("В дереве оказалось %d узлов\n", node_count); printf ("Его высота равна %d\n", max_level); /* Распечатаем несколько первых (по алфавиту) цепочек, */ /* помещенных в созданное дерево */ node_count = 10; printf ("Первые %d по алфавиту цепочек в дереве:\n", node_count); if (setjmp (buf_env) == 0) { twalk (root, tw_pfs); } /* Будем формировать и искать новые случайные цепочки */ ntr = 0; do { str_rnd (sbuf, STRING_SIZE); ntr++; } while (tdelete (sbuf, &root, (int (*) (const void *, const void *)) strcoll) == NULL); printf ("Удалось найти и удалить из дерева %g-ю по счету " "случайную цепочку %s\n", ntr, sbuf); return 0; } |
Листинг 9.27. Пример применения функций управления бинарными деревьями поиска. |
Закрыть окно |
В дереве оказалось 1000000 узлов Его высота равна 25 Первые 10 по алфавиту цепочек в дереве: AAAATNRAS AAACHCCLB AAACSJQBP AAADLHFAZ AAAFWLRXM AAAFXGQEC AAAGBMHHA AAAGFAXFI AAAHKLCWW AAAHLOSVQ Удалось найти и удалить из дерева 168221-ю по счету случайную цепочку VBBDZTNMZ real 20.24 user 20.25 sys 0.15 |
Листинг 9.28. Возможные результаты выполнения программы, применяющей функции управления бинарными деревьями поиска. |
Закрыть окно |
#include <search.h> void insque (void *element, void *pred); void remque (void *element); |
Листинг 9.29. Описание функций, выполняющих операции над очередями. |
Закрыть окно |
#include <search.h> . . . struct qelem { struct qelem *q_forw; struct qelem *q_back; char *data; . . . }; struct qelem element1; struct qelem element2; . . . element1.q_forw = &element1; element1.q_back = &element1; insque (&element2, &element1); . . . |
Листинг 9.30. Пример инициализации циклической очереди и вставки в нее второго элемента. |
Закрыть окно |
a b c d d e f g e f h h |
Листинг 9.31. Пример исходных данных для служебной программы tsort. |
Закрыть окно |
a c h b d e f g |
Листинг 9.32. Возможный результат применения служебной программы tsort. |
Закрыть окно |
#include <ucontext.h> int getcontext (ucontext_t *ucp); void makecontext (ucontext_t *ucp, void (*func) (void), int argc, ...); int setcontext (const ucontext_t *ucp); int swapcontext (ucontext_t *restrict oucp, const ucontext_t *restrict ucp); |
Листинг 9.33. Описание функций, манипулирующих пользовательскими контекстами потоков управления. |
Закрыть окно |
/* * * * * * * * * * * * * * * * * * * * * * * */ /* Программа демонстрирует применение функций, */ /* манипулирующих пользовательскими контекстами*/ /* * * * * * * * * * * * * * * * * * * * * * * */ #include <stdio.h> #include <ucontext.h> /* Размер стеков в формируемых пользовательских контекстах */ #define STACK_SIZE 4096 /* Пространство для стеков */ static char st1 [STACK_SIZE]; static char st2 [STACK_SIZE]; static ucontext_t ctx [3]; static void f1 (int arg) { printf ("Вызвана функция %s с аргументом %d\n", "f1", arg); if (swapcontext (&ctx [1], &ctx [2]) != 0) { perror ("SWAPCONTEXT-1"); } printf ("Выход из функции %s\n", "f1"); } static void f2 (int arg1, int arg2) { printf ("Вызвана функция %s с аргументами %d, %d\n", "f2", arg1, arg2); if (swapcontext (&ctx [2], &ctx [1]) != 0) { perror ("SWAPCONTEXT-2"); } printf ("Выход из функции %s\n", "f2"); } int main (void) { (void) getcontext (&ctx [1]); printf ("Параметры первоначального контекста:\n" "адрес стека %p, размер стека %d\n", ctx[1].uc_stack.ss_sp, ctx[1].uc_stack.ss_size); /* В соответствии с общими рекомендациями */ /* позаботимся о стеке для модифицируемых контекстов */ ctx[1].uc_stack.ss_sp = st1; ctx[1].uc_stack.ss_size = sizeof (st1); ctx[1].uc_link = &ctx [0]; makecontext (&ctx [1], (void (*) (void)) f1, 1, 2); (void) getcontext (&ctx [2]); ctx[2].uc_stack.ss_sp = st2; ctx[2].uc_stack.ss_size = sizeof (st2); ctx[2].uc_link = &ctx [1]; makecontext (&ctx [2], (void (*) (void)) f2, 2, 3, 4); if (swapcontext (&ctx [0], &ctx [2]) != 0) { perror ("SWAPCONTEXT-3"); return (1); } return 0; } |
Листинг 9.34. Пример применения функций, манипулирующих пользовательскими контекстами. |
Закрыть окно |
Параметры первоначального контекста: адрес стека (nil), размер стека 0 Вызвана функция f2 с аргументами 3, 4 Вызвана функция f1 с аргументом 2 Выход из функции f2 Выход из функции f1 |
Листинг 9.35. Возможные результаты выполнения программы, применяющей функции манипулирования пользовательскими контекстами. |
Закрыть окно |
#include <fenv.h> int fegetenv (fenv_t *fenvp); int fesetenv (const fenv_t *fenvp); |
Листинг 9.36. Описание функций опроса и установки текущей среды вещественной арифметики. |
Закрыть окно |
#include <fenv.h> int feholdexcept (fenv_t *fenvp); |
Листинг 9.37. Описание функции feholdexcept(). |
Закрыть окно |
#include <fenv.h> int feupdateenv (const fenv_t *fenvp); |
Листинг 9.38. Описание функции feupdateenv(). |
Закрыть окно |
#include <fenv.h> int fegetexceptflag (fexcept_t *flagp, int excepts); int fesetexceptflag (const fexcept_t *flagp, int excepts); |
Листинг 9.39. Описание функций опроса и установки флагов состояния среды вещественной арифметики. |
Закрыть окно |
#include <fenv.h> int fetestexcept (int excepts); int feclearexcept (int excepts); int feraiseexcept (int excepts); |
Листинг 9.40. Описание функций проверки, сброса и возбуждения исключительных ситуаций. |
Закрыть окно |
#include <fenv.h> int fegetround (void); int fesetround (int round); |
Листинг 9.41. Описание функций опроса и установки режима округления. |
Закрыть окно |
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Программа демонстрирует применение некоторых функций */ /* управления средой вещественной арифметики */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include <stdio.h> #include <fenv.h> #pragma STDC FENV_ACCESS ON int main (void) { double d1, d2, d3, s; int res; printf ("Представление флагов состояния вещественной " "арифметики\n"); printf (" FE_DIVBYZERO: %x\n", FE_DIVBYZERO); printf (" FE_INEXACT: %x\n", FE_INEXACT); printf (" FE_INVALID: %x\n", FE_INVALID); printf (" FE_OVERFLOW: %x\n", FE_OVERFLOW); printf (" FE_UNDERFLOW: %x\n", FE_UNDERFLOW); printf ("Представление режимов округления\n"); printf (" FE_DOWNWARD: %x\n", FE_DOWNWARD); printf (" FE_TONEAREST: %x\n", FE_TONEAREST); printf (" FE_TOWARDZERO: %x\n", FE_TOWARDZERO); printf (" FE_UPWARD: %x\n", FE_UPWARD); printf ("Текущие исключительные ситуации: %x\n", fetestexcept (FE_ALL_EXCEPT)); printf ("Текущий режим округления: %x\n", fegetround ()); feclearexcept (FE_ALL_EXCEPT); /* Вызовем ситуацию исчезновения порядка */ d1 = 1; do { d1 /= 2; } while ((res = fetestexcept (FE_ALL_EXCEPT)) == 0); printf ("Исключительные ситуации: %x\n", res); printf ("2^-inf: %g\n", d1); feclearexcept (res); /* Вызовем ситуацию переполнения */ d2 = 1; do { d2 *= 2; } while ((res = fetestexcept (FE_ALL_EXCEPT)) == 0); printf ("Исключительные ситуации: %x\n", res); printf ("2^+inf: %g\n", d2); feclearexcept (res); /* Вызовем ситуацию деления на нуль */ d3 = 1 / d1; res = fetestexcept (FE_ALL_EXCEPT); printf ("Исключительные ситуации: %x\n", res); printf ("1/0: %g\n", d3); feclearexcept (res); /* Пример того, как может возникать потеря точности */ s = 1; do { s = (s + 2 / s) * 0.5; } while ((s * s – 2) > 0); printf ("Исключительные ситуации: %x\n", fetestexcept (FE_ALL_EXCEPT)); printf ("sqrt (2): %g\n", s); return 0; } |
Листинг 9.42. Пример применения некоторых функций управления средой вещественной арифметики. |
Закрыть окно |
Представление флагов состояния вещественной арифметики FE_DIVBYZERO: 4 FE_INEXACT: 20 FE_INVALID: 1 FE_OVERFLOW: 8 FE_UNDERFLOW: 10 Представление режимов округления FE_DOWNWARD: 400 FE_TONEAREST: 0 FE_TOWARDZERO: c00 FE_UPWARD: 800 Текущие исключительные ситуации: 0 Текущий режим округления: 0 Исключительные ситуации: 30 2^-inf: 0 Исключительные ситуации: 28 2^+inf: inf Исключительные ситуации: 4 1/0: inf Исключительные ситуации: 20 sqrt (2): 1.41421 |
Листинг 9.43. Возможные результаты выполнения программы, применяющей некоторые функции управления средой вещественной арифметики. |
Закрыть окно |
/* * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Программа реализует некоторые операции */ /* интервальной арифметики */ /* * * * * * * * * * * * * * * * * * * * * * * * * * */ #include <stdio.h> #include <fenv.h> #pragma STDC FENV_ACCESS ON /* Интервальное представление числа */ typedef struct ditvl { double lb; double ub; } ditvl_t; /* * * * * * * * * * * * * * * * * * * * */ /* Сложение интервалов. */ /* Сумма помещается в выходной аргумент. */ /* Нормальный результат равен нулю */ /* * * * * * * * * * * * * * * * * * * * */ int ditvl_add (const ditvl_t *a1, const ditvl_t *a2, ditvl_t *res) { fenv_t cfenv; /* Сохраним текущую среду вещественной арифметики */ if (fegetenv (&cfenv) != 0) { perror ("FEGETENV"); return (-1); } /* Нижние границы нужно складывать с округлением вниз */ if (fesetround (FE_DOWNWARD) != 0) { perror ("FESETROUND"); return (-1); } res->lb = a1->lb + a2->lb; /* Верхние границы складываются с округлением вверх */ if (fesetround (FE_UPWARD) != 0) { perror ("FESETROUND"); return (-1); } res->ub = a1->ub + a2->ub; /* Восстановим среду вещественной арифметики */ if (fesetenv (&cfenv) != 0) { perror ("FESETENV"); return (-1); } return 0; } /* * * * * * * * */ /* Унарный минус */ /* * * * * * * * */ int ditvl_uminus (const ditvl_t *a, ditvl_t *res) { res->lb = -(a->ub); res->ub = -(a->lb); return 0; } /* * * * * * * * */ /* Вызов функций */ /* * * * * * * * */ int main (void) { ditvl_t pi = {3.141592, 3.141593}; ditvl_t e = {2.718281, 2.718282}; ditvl_t res; ditvl_t tmp; printf ("Представление числа pi: (%f, %f)\n", pi.lb, pi.ub); printf ("Представление числа e: (%f, %f)\n", e.lb, e.ub); /* Вычислим сумму pi и e */ (void) ditvl_add (&pi, &e, &res); printf ("Сумма pi и e: (%f, %f)\n", res.lb, res.ub); /* Вычислим разность pi и e */ (void) ditvl_uminus (&e, &tmp); (void) ditvl_add (&pi, &tmp, &res); printf ("Разность pi и e: (%f, %f)\n", res.lb, res.ub); printf ("Текущие исключительные ситуации: %x\n", fetestexcept (FE_ALL_EXCEPT)); printf ("Текущие режимы округления: %x\n", fegetround ()); return 0; } |
Листинг 9.44. Пример использования различных режимов округления. |
Закрыть окно |
Представление числа pi: (3.141592, 3.141593) Представление числа e: (2.718281, 2.718282) Сумма pi и e: (5.859873, 5.859875) Разность pi и e: (0.423310, 0.423312) Текущие исключительные ситуации: 0 Текущие режимы округления: 0 |
Листинг 9.45. Возможные результаты выполнения программы, реализующей некоторые операции интервальной арифметики. |
Закрыть окно |
#include <ftw.h> int ftw (const char *path, int (*fn) (const char *, const struct stat *, int), int depth); int nftw (const char *path, int (*fn) (const char *, const struct stat *, int, struct FTW *), int depth, int flags); |
Листинг 9.46. Описание функций обхода файловой иерархии. |
Закрыть окно |
/* * * * * * * * * * * * * * * * * * * * */ /* Программа определяет суммарный размер */ /* и высоту файловой иерархии */ /* * * * * * * * * * * * * * * * * * * * */ #define _XOPEN_SOURCE 600 #include <ftw.h> #include <stdio.h> /* Суммарный размер файлов в иерархии */ static off_t fsize = 0; /* Максимальный уровень файлов в иерархии */ static int flevel = 0; /* * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Функция, вызываемая для каждого файла в иерархии */ /* * * * * * * * * * * * * * * * * * * * * * * * * * */ static int nftwfunc (const char *filename, const struct stat *statptr, int filetype, struct FTW *pfwt) { /* Если установлен флаг FTW_NS, завершим обход */ if (filetype == FTW_NS) { perror ("STAT"); fprintf (stderr, "Отсутствуют данные о файле %s\n", filename); return 1; } fsize += statptr->st_size; if (pfwt->level > flevel) { flevel = pfwt->level; } return 0; } /* * * * * * * * * * * */ /* Организация обхода */ /* * * * * * * * * * * */ int main (int argc, char *argv []) { if (argc != 2) { fprintf (stderr, "Использование: %s корень_иерархии\n", argv [0]); return (1); } if (nftw (argv [1], nftwfunc, 16, FTW_MOUNT | FTW_PHYS) == -1) { perror ("NFTW"); } printf ("Суммарный размер обработанных файлов: %ld\n", fsize); printf ("Высота иерархии файлов: %d\n", flevel); return 0; } |
Листинг 9.47. Пример программы, осуществляющей обход файловой иерархии. |
Закрыть окно |
STAT: Permission denied Отсутствуют данные о файле /tmp/gaga/ gugu Суммарный размер обработанных файлов: 2645778 Высота иерархии файлов: 2 |
Листинг 9.48. Возможные результаты выполнения программы, осуществляющей обход файловой иерархии. |
Закрыть окно |
#include <stdlib.h> #include <fcntl.h> int posix_openpt (int oflag); |
Листинг 9.49. Описание функции открытия главного устройства псевдотерминала. |
Закрыть окно |
#include <stdlib.h> int unlockpt (int masterfd); |
Листинг 9.50. Описание функции разблокирования подчиненного устройства псевдотерминала. |
Закрыть окно |
#include <stdlib.h> int grantpt (int masterfd); |
Листинг 9.51. Описание функции формирования прав доступа к подчиненному устройству псевдотерминала. |
Закрыть окно |
#include <stdlib.h> char *ptsname (int masterfd); |
Листинг 9.52. Описание функции получения имени подчиненного устройства псевдотерминала. |
Закрыть окно |
/* * * * * * * * * * * * * * * * * * * * * * * * */ /* Программа запускает shell на псевдотерминале */ /* * * * * * * * * * * * * * * * * * * * * * * * */ #define _XOPEN_SOURCE 600 #include <stdlib.h> #include <unistd.h> #include <stdio.h> #include <fcntl.h> #include <termios.h> #include <signal.h> #include <poll.h> #include <sys/resource.h> #include <curses.h> /* * * * * * * * * * * * * * * * * * */ /* Действия при завершении процесса */ /* * * * * * * * * * * * * * * * * * */ static void termination (int errcode) { endwin (); exit (errcode); } /* * * * * * * * * * * * * * * * * * */ /* Функция обработки сигнала SIGCHLD */ /* * * * * * * * * * * * * * * * * * */ static void chldied (int dummy) { /* Просто кончимся */ termination (34); } /* * * * * * * * * * * * * * * * * * * * */ /* Организация работы с псевдотерминалом */ /* * * * * * * * * * * * * * * * * * * * */ int main (void) { WINDOW *win1, *win2; /* win1 – окно только для рамки */ /* win2 – окно для shell'а */ int pty, tty; /* Дескрипторы обеих сторон */ /* псевдотерминала */ int fr; /* Результат fork'а */ unsigned char ch; /* Прочитанный символ */ struct termios pt; /* Структура характеристик */ /* псевдотерминала */ struct pollfd fds [2]; /* Массив параметров для */ /* вызова poll */ int w2lines, w2cols; /* Размер создаваемого окна */ int x, y; /* Координаты в окне */ struct sigaction sact; int i; initscr (); cbreak (); noecho (); win1 = newwin (LINES, COLS, 0, 0); box (win1, 0, 0); wrefresh (win1); w2lines = LINES – 2; w2cols = COLS – 4; win2 = newwin (w2lines, w2cols, 1, 2); scrollok (win2, TRUE); /* Откроем псевдотерминал */ if (((pty = posix_openpt (O_RDWR | O_NOCTTY)) < 0) || (unlockpt (pty) == -1) || (grantpt (pty) == -1) || ((tty = open (ptsname (pty), O_RDWR)) < 0)) { fprintf (stderr, "Не удалось открыть псевдотерминал\n"); perror ("POSIX_OPENPT"); return (1); } /* Установим подходящие характеристики псевдотерминала */ if (tcgetattr (pty, &pt) < 0) { perror ("PTY TERMIOS GET ERROR"); return (2); } pt.c_iflag = 0; pt.c_oflag = ONLCR; pt.c_cflag = CS8 | HUPCL; pt.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK; pt.c_cc [VINTR] = 3; /* CTRL+C */ pt.c_cc [VEOF] = 4; /* CTRL+D */ if (tcsetattr (pty, TCSADRAIN, &pt) < 0) { perror ("PTY TERMIOS SET ERROR"); return (3); } /* То же – для стандартного ввода */ (void) tcgetattr (0, &pt); pt.c_lflag &= ~ISIG; (void) tcsetattr (0, TCSADRAIN, &pt); /* Установим обработку сигнала о завершении потомка */ sact.sa_handler = chldied; (void) sigemptyset (&sact.sa_mask); sact.sa_flags = 0; (void) sigaction (SIGCHLD, &sact, (struct sigaction *) NULL); /* Раздвоимся на процесс чтения с клавиатуры */ /* и вывода на экран и на процесс, */ /* в рамках которого запустим shell */ if ((fr = fork ()) < 0) { perror ("FORK1 ERROR"); termination (-1); } else if (fr) { /* Это процесс, читающий с клавиатуры */ /* и выводящий на экран */ close (tty); /* Будем ждать ввода с клавиатуры или псевдотерминала */ fds [0].fd = 0; fds [0].events = POLLIN; fds [1].fd = pty; fds [1].events = POLLIN; while (1) { if (poll (fds, 2, -1) < 0) { perror ("POLL ERROR"); termination (0); } if (fds [0].revents & POLLIN) { /* Пришел символ со стандартного ввода */ read (0, &ch, 1); write (pty, &ch, 1); } if (fds [1].revents & POLLIN) { /* Пришел символ с псевдотерминала */ read (pty, &ch, 1); switch (ch) { case '\n': { /* Проинтерпретируем перевод строки */ getyx (win2, y, x); if (y == (w2lines – 1)) { wmove (win2, y, w2cols – 1); waddch (win2, (chtype) ch); } else { wmove (win2, y + 1, 0); } break; } default: { /* Символ не интерпретируется */ waddch (win2, (chtype) ch); break; } } wrefresh (win2); } } /* Просто кончимся */ termination (0); } else { /* Порожденный процесс – запустим в нем shell */ /* Закроем все файлы, кроме псевдотерминала */ for (i = 0; i < RLIMIT_NOFILE; i++) { if (i != tty) { (void) close (i); } } /* Сделаем процесс лидером сеанса */ (void) setsid (); /* Свяжем стандартные ввод, вывод и протокол */ /* с псевдотерминалом */ (void) fcntl (tty, F_DUPFD, 0); (void) fcntl (tty, F_DUPFD, 0); (void) fcntl (tty, F_DUPFD, 0); close (tty); /* Поместим в окружение параметры псевдотерминала */ { char lnbuf [20]; char clbuf [20]; sprintf (lnbuf, "LINES=%2d", w2lines); sprintf (clbuf, "COLUMNS=%2d", w2cols); putenv (lnbuf); putenv (clbuf); } if (execl ("/bin/sh", "sh", (char *) NULL) < 0) { perror ("EXECL ERROR"); exit (-1); } } return 0; } |
Листинг 9.53. Пример программы, использующей псевдотерминалы. |
Закрыть окно |