next up previous
Next: Apeluri POSIX Up: Controlul terminalului Previous: Controlul terminalului

ioctl

Functia ioctl manipuleaza diversi parametri de nivel scazut pentru fisierele speciale (terminale, socketi) si diverse dispozitive. Intrucat nu ar fi eficient crearea unor functii pentru fiecare caz sau dispozitiv, apelul ioctl multiplexeaza toate aceste operatii prin intermediul unor coduri numerice reprezentate de al doilea parametru din apel. Sintaxa de apel este

#include <sys/ioctl.h>

int ioctl (int d, int request, ...);

Functia poate avea doi sau trei parametri. Primul parametru (d) trebuie sa fie un descriptor de fisier valid. Al doilea parametru este o cerere care este dependenta de dispozitiv si este reprezentat de un macro care defineste simplificat rolul indeplinit; o lista cu valorile posibile pentru al doilea parametru gasiti prin accesarea paginii de manual ($ man 2 ioctl_list). In functie de acest parametru este posibila prezenta parametrului trei sau nu. Acesta este, in general, un pointer la o structura specfica dispozitivului (in cazul terminalului aceasta este chiar struct termios).

Pentru ceea ce ne intereseaza avem doua valori posibile pentru parametrul 2 al apelului ioctl:

Pentru ca nu se poate cunoaste evolutia in timp a sistemelor de operare si, in consecinta, a structurilor cu care acestea lucreaza, nu se va completa niciodata ``de la zero'' o structura struct termios. In schimb, se va citi in structura starea curenta a terminalului, se vor modifica campurile de interes si apoi se va actualiza starea terminalului in conformitate cu noul continut al structurii.

Mai jos este prezentat un exemplu care implementeaza un echivalent al functiei getch din DOS, folosind apelul ioctl. Exemplul citeste fara ecou caractere de la terminal si se opreste in momentul in care se apasa tasta 'q'.

/*
 * exemplu cu implementarea getch folosind ioctl pentru controlul
 * terminalului
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <termios.h>

struct termios old_termios, new_termios;

/*
 * stabilirea parametrilor structurii termios pentru lucrul
 * in modul necanonic fara ecou
 */

void make_raw (struct termios *termios_p)
{
        /*
         * ~ICANON este o valoare in care toti bitii sunt 1, mai
         * putin bitul corespunzator lui ICANON; facand aici un
         * si, bitul ICANON este pozitionat pe 1 si dezactiveaza
         * astfel modul canonic (vom ajunge astfel in modul
         * non-canonic)
         */
        termios_p->c_lflag &= (~ICANON);

        /* echo OFF - nu dorim ecou la apasarea unei taste */
        termios_p->c_lflag &= (~ECHO);

        /*
         * vom pune MIN pe 1 si TIME pe 0 -> asteptare nedefinita
         * pana la aparitia unui caracter
         */
        termios_p->c_cc[VMIN] = 1;
        termios_p->c_cc[VTIME] = 0;
}

/*
 * actualizare terminal pentru lucrul in modul necanonic fara ecou
 */

void start_getch (void)
{
        /* retinem in old_termios starea curenta a terminalului */
        if (ioctl (STDIN_FILENO, TCGETS, &old_termios) < 0) {
                perror ("ioctl");
                exit (EXIT_FAILURE);
        }

        /* copiem in new_termios starea terminalului pentru actualizare */
        memcpy (&new_termios, &old_termios, sizeof (struct termios));

        /* stabilire mod necanonic fara ecou */
        make_raw (&new_termios);

        /* actualizare terminal cu noile caracteristici */
        if (ioctl (STDIN_FILENO, TCSETS, &new_termios) < 0) {
                perror ("ioctl");
                exit (EXIT_FAILURE);
        }
}

/*
 * revenire la modul de lucru initial
 */

void stop_getch (void)
{
        /* readucem terminalul in starea descrisa de old_termios */
        if (ioctl (STDIN_FILENO, TCSETS, &old_termios) < 0) {
                perror ("ioctl");
                exit (EXIT_FAILURE);
        }
}

/*
 * functia getch citeste un caracter de la terminal si se intoarce;
 * citirea este fara ecou (conform actualizarii terminalului)
 */

int getch (void)
{
        char c;

        read (STDIN_FILENO, &c, 1);

        return c;
}

/*
 * in cadrul functiei main se citesc caractere in mod necanonic si
 * se afiseaza pe ecran; ne oprim la apasarea tastei 'q' sau 'Q'
 */

int main (void)
{
        char c;

        start_getch (); /* intram in mod necanonic, fara ecou */

        /* citim caractere pana cand se citeste 'q' sau 'Q' */
        while (1) {
                c = getch ();

                /* afisam pe ecran ce s-a apasat */
                write (STDOUT_FILENO, "Ati apasat ", 11);
                write (STDOUT_FILENO, &c, 1);
                write (STDOUT_FILENO, "\n", 1);

                /* la 'q' sau 'Q' ne oprim */
                if (c == 'q' || c == 'Q')
                        break;
        }

        /* revenim la starea initiala a terminalului */
        stop_getch ();

        return 0;
}


next up previous
Next: Apeluri POSIX Up: Controlul terminalului Previous: Controlul terminalului
Razvan Adrian Deaconescu 2005-10-01