Мобильное программирование приложений реального времени в стандарте POSIX

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. Пример программы, использующей псевдотерминалы.
Закрыть окно



Содержание раздела