Главная · Поиск книг · Поступления книг · Top 40 · Форумы · Ссылки · Читатели

Настройка текста
Перенос строк


    Прохождения игр    
Demon's Souls |#13| Storm King
Demon's Souls |#11| Мaneater part 2
Demon's Souls |#10| Мaneater (part 1)
Demon's Souls |#9| Heart of surprises

Другие игры...


liveinternet.ru: показано число просмотров за 24 часа, посетителей за 24 часа и за сегодня
Rambler's Top100
Образование - Богатырев А. Весь текст 1009.15 Kb

Хрестоматия по программированию на Си в Unix

Предыдущая страница Следующая страница
1 ... 44 45 46 47 48 49 50  51 52 53 54 55 56 57 ... 87
            strcpy (pathname, ROOTDIR);
        else {
            strcpy (pathname, pnptr);
            if (chdir (pnptr) < 0) {
                GETWDERR ("getwd: can't change back to .");
                return (NULL);
            }
        }
        return (pathname);

    fail:
        chdir (prepend (CURDIR, pnptr));
        return (NULL);
    }
    #endif

А. Богатырев, 1992-95                  - 257 -                              Си в UNIX

    /*
     * prepend() tacks a directory name onto the front of a pathname.
     */
    static char *prepend (
            register char *dirname,         /* что добавлять    */
            register char *pathname         /* к чему добавлять */
    ) {
            register int i;         /* длина имени каталога */

            for (i = 0; *dirname != '\0'; i++, dirname++)
                    continue;
            if ((pathsize += i) < MAXPATHLEN)
                    while (i-- > 0)
                            *--pathname = *--dirname;
            return (pathname);
    }

    #ifndef CWDONLY
    void main(){
            char buffer[MAXPATHLEN+1];
            char *cwd = getwd(buffer);
            printf( "%s%s\n", cwd ? "": "ERROR:", buffer);
    }
    #endif

6.10.2.  Напишите функцию canon(), канонизирующую имя файла, т.е.  превращающую его в
полное  имя (от корневого каталога), не содержащее компонент "." и "..", а также лиш-
них символов слэш '/'. Пусть, к примеру, текущий  рабочий  каталог  есть  /usr/abs/C-
book. Тогда функция преобразует

      .                    -> /usr/abs/C-book
      ..                   -> /usr/abs
      ../..                -> /usr
      ////..               -> /
      /aa                  -> /aa
      /aa/../bb            -> /bb
      cc//dd/../ee         -> /usr/abs/C-book/cc/ee
      ../a/b/./d           -> /usr/abs/a/b/d

Ответ:

    #include 
    /* слэш, разделитель компонент пути */
    #define SLASH        '/'
    extern char *strchr (char *, char),
                *strrchr(char *, char);
    struct savech{ char *s, c; };
    #define SAVE(sv, str) (sv).s = (str); (sv).c = *(str)
    #define RESTORE(sv) if((sv).s)   *(sv).s = (sv).c
    /* Это структура для использования в таком контексте:
    void main(){
      char *d = "hello"; struct savech ss;
      SAVE(ss, d+3); *(d+3) = '\0'; printf("%s\n", d);
      RESTORE(ss);                  printf("%s\n", d);
    }
    */

    /* ОТСЕЧЬ ПОСЛЕДНЮЮ КОМПОНЕНТУ ПУТИ */
    struct savech parentdir(char *path){
       char *last  = strrchr( path, SLASH );

А. Богатырев, 1992-95                  - 258 -                              Си в UNIX

       char *first = strchr ( path, SLASH );
       struct savech sp; sp.s = NULL; sp.c = '\0';

    if( last    == NULL  ) return sp; /* не полное имя    */
    if( last[1] == '\0'  ) return sp; /* корневой каталог */
    if( last    == first ) /* единственный слэш: /DIR     */
        last++;
       sp.s = last; sp.c = *last; *last = '\0';
       return sp;
    }
    #define isfullpath(s)   (*s == SLASH)
    /* КАНОНИЗИРОВАТЬ ИМЯ ФАЙЛА */
    void canon(
         char *where, /* куда поместить ответ */
         char *cwd,   /* полное имя текущего каталога */
         char *path   /* исходное имя для канонизации */
    ){   char *s, *slash;
       /* Сформировать имя каталога - точки отсчета */
       if( isfullpath(path)){
           s = strchr(path, SLASH);   /* @ */
           strncpy(where, path, s - path + 1);
           where[s - path + 1] = '\0';
           /* или даже просто strcpy(where, "/"); */
           path = s+1; /* остаток пути без '/' в начале */
       } else strcpy(where, cwd);

       /* Покомпонентный просмотр пути */
       do{  if(slash = strchr(path, SLASH)) *slash = '\0';
       /* теперь path содержит очередную компоненту пути */
            if(*path == '\0' || !strcmp(path, ".")) ;
         /* то просто проигнорировать "." и лишние "///" */
            else  if( !strcmp(path, ".."))
                  (void) parentdir(where);
            else{ int len = strlen(where);
               /* добавить в конец разделяющий слэш */
                  if( where[len-1] != SLASH ){
                      where[len] = SLASH;
                      where[len+1] = '\0';
                  }
                  strcat( where+len, path );
                  /* +len чисто для ускорения поиска
                   * конца строки внутри strcat(); */
            }
            if(slash){ *slash = SLASH; /* восстановить */
                       path   = slash + 1;
            }
       } while (slash != NULL);
    }
    char cwd[256], input[256], output[256];
    void main(){
    /* Узнать полное имя текущего каталога.
     * getcwd() - стандартная функция, вызывающая
     * через popen() команду pwd (и потому медленная).
     */
       getcwd(cwd, sizeof cwd);
       while( gets(input)){
         canon(output, cwd, input);
         printf("%-20s -> %s\n", input, output);
       }
    }

А. Богатырев, 1992-95                  - 259 -                              Си в UNIX

В этом примере (изначально писавшемся для MS DOS) есть "странное"  место,  помеченное
/*@*/. Дело в том, что в DOS функция isfullpath была способна распознавать имена фай-
лов вроде C:\aaa\bbb, которые не обязательно начинаются со слэша.

6.11.  Мультиплексирование ввода-вывода.
     Данная глава посвящена системному вызову select, который, однако, мы  предостав-
ляем  вам  исследовать самостоятельно.  Его роль такова: он позволяет опрашивать нес-
колько дескрипторов открытых файлов (или устройств) и как только в  файле  появляется
новая  информация  -  сообщать  об этом нашей программе.  Обычно это бывает связано с
дескрипторами, ведущими к сетевым устройствам.

6.11.1.

    /* Пример использования вызова select() для мультиплексирования
     * нескольких каналов ввода. Этот вызов можно также использовать
     * для получения таймаута.
     *     Вызов: войти на терминалах tty01 tty02 и набрать на каждом
     *            sleep 30000
     *     затем  на tty00 сказать           select /dev/tty01 /dev/tty02
     *     и вводить что-либо на терминалах  tty01 и tty02
     * Сборка:      cc select.c -o select -lsocket
     */
    #include 
    #include 
    #include   /* fd_set, FD_SET, e.t.c. */
    #include   /* NOFILE */
    #include 
    #include 
    #include   /* для FIONREAD */
    #define max(a,b)        ((a) > (b) ? (a) : (b))

    char buf[512];          /* буфер чтения                      */
    int fdin, fdout;        /* дескрипторы каналов stdin, stdout */
    int nready;             /* число готовых каналов             */
    int nopen;              /* число открытых каналов            */
    int maxfd = 0;          /* максимальный дескриптор           */
    int nfds;               /* сколько первых дескрипторов проверять */
    int f;                  /* текущий дескриптор                */
    fd_set set, rset;       /* маски                             */

    /* таблица открытых нами файлов */
    struct _fds {
            int fd;         /* дескриптор */
            char name[30];  /* имя файла  */
    } fds[ NOFILE ] = { /* NOFILE - макс. число открытых файлов на процесс */
            { 0, "stdin" }, { 1, "stdout" }, { 2, "stderr" }
            /* все остальное - нули */
    };
    struct timeval timeout, rtimeout;

    /* выдать имя файла по дескриптору */
    char *N( int fd ){
            register i;
            for(i=0; i < NOFILE; i++)
                    if(fds[i].fd == fd ) return fds[i].name;
            return "???";
    }

А. Богатырев, 1992-95                  - 260 -                              Си в UNIX

    void main( int ac, char **av ){
            nopen = 3;              /* stdin, stdout, stderr */
            for( f = 3; f < NOFILE; f++ ) fds[f].fd = (-1);
            fdin = fileno(stdin);   fdout = fileno(stdout);
            setbuf(stdout, NULL);   /* отмена буферизации */
            FD_ZERO(&set);          /* очистка маски */

            for(f=1; f < ac; f++ )
                    if((fds[nopen].fd = open(av[f], O_RDONLY)) < 0 ){
                       fprintf(stderr, "Can't read %s\n", av[f] );
                       continue;
                    } else {
                       FD_SET(fds[nopen].fd, &set );   /* учесть в маске */
                          maxfd = max(maxfd, fds[nopen].fd );
                       strncpy(fds[nopen].name, av[f], sizeof(fds[0].name) - 1);
                       nopen++;
                    }

            if( nopen == 3 ){
                    fprintf(stderr, "Nothing is opened\n");
                    exit(1);
            }

            FD_SET(fdin, &set); /* учесть stdin */
               maxfd = max(maxfd, fdin );
            nopen -= 2;         /* stdout и stderr не участвуют в select */
            timeout.tv_sec = 10;    /* секунд */
            timeout.tv_usec = 0;    /* миллисекунд */

        /* nfds - это КОЛИЧЕСТВО первых дескрипторов, которые надо
         * просматривать. Здесь можно использовать
         *          nfds = NOFILE;  (кол-во ВСЕХ дескрипторов   )
         * или      nfds = maxfd+1; (кол-во = номер последнего+1)
         * ( +1 т.к. нумерация fd идет с номера 0, а количество - с 1).
         */
            nfds = maxfd + 1;
            while( nopen ){

               rset = set; rtimeout = timeout; /* копируем, т.к. изменятся */
        /* опрашивать можно FIFO-файлы, терминалы, pty, socket-ы, stream-ы */

               nready = select( nfds, &rset, NULL, NULL, &rtimeout );

        /* Если вместо &rtimeout написать NULL, то ожидание будет
         * бесконечным (пока не собьют сигналом)
         */
               if( nready <= 0 ){  /* ничего не поступило */
                    fprintf(stderr, "Timed out, nopen=%d\n", nopen);
                    continue;
               }

А. Богатырев, 1992-95                  - 261 -                              Си в UNIX

               /* опрос готовых дескрипторов */
               for(f=0; f < nfds; f++ )
                    if( FD_ISSET(f, &rset)){  /* дескриптор f готов */
                            int n;

                            /* Вызов FIONREAD позволяет запросить
                             * число байт готовых к передаче
                             * через дескриптор.
                             */
                            if(ioctl(f, FIONREAD, &n) < 0)
                                    perror("FIONREAD");
                            else printf("%s have %d bytes.\n", N(f), n);

                            if((n = read(f, buf, sizeof buf)) <= 0 ){
                    eof:
                                FD_CLR(f, &set); /* исключить */
                                close(f); nopen--;
                                fprintf(stderr, "EOF in %s\n", N(f));

                            } else {

                                fprintf(stderr, "\n%d bytes from %s:\n", n, N(f));
                                write(fdout, buf, n);
                                if( n == 4 && !strncmp(buf, "end\n", 4))
                                /* ncmp, т.к. buf может не оканчиваться \0 */
                                    goto eof;
                            }
                    }
            }
            exit(0);
    }

6.11.2.  В качестве самостоятельной работы предлагаем вам пример  программы,  ведущей
протокол сеанса работы.  Информацию о псевдотерминалах изучите самостоятельно.

А. Богатырев, 1992-95                  - 262 -                              Си в UNIX

    /*
     *              script.c
     *      Программа получения трассировки работы других программ.
     *      Используется системный вызов опроса готовности каналов
Предыдущая страница Следующая страница
1 ... 44 45 46 47 48 49 50  51 52 53 54 55 56 57 ... 87
Ваша оценка:
Комментарий:
  Подпись:
(Чтобы комментарии всегда подписывались Вашим именем, можете зарегистрироваться в Клубе читателей)
  Сайт:
 

Реклама