Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: txiki481 en 23 Abril 2018, 21:40 pm



Título: Forma canonica
Publicado por: txiki481 en 23 Abril 2018, 21:40 pm
Buenas, estoy haciendo un programa que dandole una posición y un fichero, escribe lo que pongas en la terminal y lo escribe en la posición introducida.

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

#define BUFFER_TAMAINA 512

main(int argc, const char * argv[])
{
   int a;
   int f,k;
   char buff[BUFFER_TAMAINA];
   FILE *f1;

   if (argc==3)
    {
       if (strcmp(argv[2],"0")!=0 && atoi(argv[2])==0)
       {
         write(1, "error, la posicion no es un numero\n", 36);
         exit(1);
      }

      f1=fopen(argv[1], "r+");

      if(errno==ENOENT)
      {
         write(1, "el fichero no existe\n", 28);
         exit(1);
      }
      while(fgetc(f1)!=EOF){k++;}
      fclose(f1);

      if((atoi(argv[2]))>k)
      {
         write(1,"la position es demasiado alta\n",28);
         exit(1);
      }
   
      if(atoi(argv[2])<0){
         write(1, "la position es negativa\n", 31);
         exit(1);
      }

      f = open(argv[1], O_WRONLY,00777);

      if(errno==ENOENT){
         write(1, "el fichero no existe\n", 28);
         exit(1);
      }

      lseek(f, atoi(argv[2]), SEEK_SET);

      while ((a=read(0,buff,BUFFER_TAMAINA))>0)
      {   
         write(f,buff,a);
      
      }

      close(f);
   }
    else
    {
           write(1,"Erabilera: ./idatzi_fitx [fichero] [posicion]\n",50);
    }
}

El problema es que en la terminal hay que darle al enter para que lo escriba, es decir esta hecho de manera canónica, y coge tambien el intro como todo lo que queremos escribir. Como podría hacer para que no tuviera en cuenta el enter?

Y como podría hacerlo de forma no canónica? Es decir, que todo lo que vaya escribiendo en la terminal se vaya escribiendo sin necesidad de darle al enter.


Título: Re: Forma canonica
Publicado por: MAFUS en 24 Abril 2018, 11:00 am
Eso depende del terminal, no hay una forma estándar para todo el mundo. Si tienes *nix se hace de una forma, en Windows de otra...


Título: Re: Forma canonica
Publicado por: txiki481 en 24 Abril 2018, 11:45 am
de la forma de unix como seria


Título: Re: Forma canonica
Publicado por: MAFUS en 24 Abril 2018, 17:15 pm
Repasa este par de stackoverflow. Lo explica.
https://stackoverflow.com/questions/7469139/what-is-equivalent-to-getch-getche-in-linux


Título: Re: Forma canonica
Publicado por: txiki481 en 25 Abril 2018, 18:39 pm
Solo me coge un caracter, le doy a cualquier letra y se acaba el programa guardando la letra en la posición introducida. Como hago para escribir todo lo que quiera?

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <termios.h>


#define BUFFER_TAMAINA 512

void SetTermNoCanon( struct termios *SavedTM)
{
    struct termios tm;

    tcgetattr(0, &tm);
    tcgetattr(0, SavedTM);
    tm.c_lflag &= ~(ICANON|ECHO);
    tm.c_cc[VMIN]= 1;
    tm.c_cc[VTIME]= 0;
    tcsetattr(0, TCSANOW, &tm);

}

int main(int argc, const char * argv[])
{
   int a;
   int f,k;
   char buff[BUFFER_TAMAINA];
   int p = atoi(buff); //
   FILE *f1;

   struct stat *stat1;
   struct termios saved_tm;

   if (argc==3)
    {
       if (strcmp(argv[2],"0")!=0 && atoi(argv[2])==0)
       {
         write(1, "error, la posicion no es un numero\n", 36);
         exit(1);
       }

      f1=fopen(argv[1], "r+");

      if(errno==ENOENT)
      {
         write(1, "el fichero no existe\n", 28);
         exit(1);
      }
      while(fgetc(f1)!=EOF){k++;}
      fclose(f1);

      if((atoi(argv[2]))>k)
      {
         write(1,"la position es demasiado alta\n",28);
         exit(1);
      }
   
      if(atoi(argv[2])<0){
         write(1, "la position es negativa\n", 31);
         exit(1);
      }

      f = open(argv[1], O_WRONLY,00777);

      if(errno==ENOENT){
         write(1, "el fichero no existe\n", 28);
         exit(1);
      }

      lseek(f, atoi(argv[2]), SEEK_SET);

     SetTermNoCanon( &saved_tm );

      while ((a=read(0,buff,BUFFER_TAMAINA))>0)
      {   
    if(stat(argv[1], &*stat1) != NULL)
    { 

        switch(p)
       {
      case 'q':  tcsetattr(0, TCSANOW, &saved_tm);                                  
                              close(f);
               exit(0);
      case ' ':   break;
      default:   write(f,buff,a);

      printf("Información:\n",argv[1]);
      printf("---------------------------\n");
         printf("Tamaño: \t \t %d bytes\n", stat1->st_size);
      printf("Links: \t%d\n", stat1->st_nlink);
          printf("inode: \t \t %d\n", stat1->st_ino);
           
              }
             }     
       }

   tcsetattr(0, TCSANOW, &saved_tm);
   close(f);
   exit(0);   
     }
    else
    {
           write(1,"Erabilera: ./idatzi_fitx [fichero] [posicion]\n",50);
    }
}


Título: Re: Forma canonica
Publicado por: MAFUS en 25 Abril 2018, 22:01 pm
No tengo linux para probar el código, pero debería ser una cosa así:
Código
  1. #include <unistd.h>
  2. #include <sys/types.h>
  3. #include <sys/stat.h>
  4. #include <fcntl.h>
  5. #include <string.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <errno.h>
  9. #include <termios.h>
  10.  
  11. // Sacado de https://stackoverflow.com/questions/7469139/what-is-equivalent-to-getch-getche-in-linux
  12. static struct termios old, new;
  13.  
  14. /* Initialize new terminal i/o settings */
  15. void initTermios(int echo)  {
  16.    tcgetattr(0, &old); /* grab old terminal i/o settings */
  17.    new = old; /* make new settings same as old settings */
  18.    new.c_lflag &= ~ICANON; /* disable buffered i/o */
  19.    if (echo) {
  20.        new.c_lflag |= ECHO; /* set echo mode */
  21.    } else {
  22.        new.c_lflag &= ~ECHO; /* set no echo mode */
  23.    }
  24.    tcsetattr(0, TCSANOW, &new); /* use these new terminal i/o settings now */
  25. }
  26.  
  27. /* Restore old terminal i/o settings */
  28. void resetTermios(void) {
  29.    tcsetattr(0, TCSANOW, &old);
  30. }
  31.  
  32. /* Read 1 character - echo defines echo mode */
  33. char getch_(int echo) {
  34.    char ch;
  35.    initTermios(echo);
  36.    ch = getchar();
  37.    resetTermios();
  38.    return ch;
  39. }
  40.  
  41. /* Read 1 character without echo */
  42. char getch(void) {
  43.    return getch_(0);
  44. }
  45.  
  46. /* Read 1 character with echo */
  47. char getche(void) {
  48.    return getch_(1);
  49. }
  50.  
  51. void SetTermNoCanon( struct termios *SavedTM) {
  52.    struct termios tm;
  53.  
  54.    tcgetattr(0, &tm);
  55.    tcgetattr(0, SavedTM);
  56.    tm.c_lflag &= ~(ICANON|ECHO);
  57.    tm.c_cc[VMIN]= 1;
  58.    tm.c_cc[VTIME]= 0;
  59.    tcsetattr(0, TCSANOW, &tm);
  60. }
  61.  
  62. int main(int argc, const char * argv[]) {
  63.    char c;
  64.    int f;
  65.    long file_end;
  66.    long file_pos;
  67.    char buff[BUFFER_TAMAINA];
  68.    FILE *f1;
  69.    struct stat stat1;
  70.  
  71.    // Voy a sustituir todos los write a stdout por printf o puts
  72.  
  73.    // Número de argumentos diferente al esperado
  74.    if (argc != 3) {
  75.        printf("Uso: %s [fichero] [posicion]", argv[0]);
  76.        return EXIT_FAILURE;
  77.    }
  78.  
  79.    file_pos = atol(argv[2]);
  80.  
  81.    // No se pueden los metadatos del archivo
  82.    if(stat(argv[1], &statl) == -1) {
  83.        puts("error, no se pueden recuperar datos del archivo");
  84.        return EXIT_FAILURE;
  85.    }
  86.  
  87.    // El argumento posición no es un número o es 0
  88.    if(file_pos < 1) {
  89.        puts("error, posicion debe ser un entero igual o mayor a 1");
  90.        return EXIT_FAILURE;
  91.    }
  92.  
  93.    f1 = fopen(argv[1], "r+");
  94.  
  95.    // El archivo no existe o no se puede abrir
  96.    if(!f1) {
  97.        puts("error, el fichero no existe");
  98.        return EXIT_FAILURE;
  99.    }
  100.  
  101.    //- Sustituyo todo esto
  102.    //   while(fgetc(f1)!=EOF) {
  103.    //       k++;
  104.    //   }
  105.    //   fclose(f1);
  106.    //- Por lo siguiente
  107.  
  108.    fflush(f1);
  109.    fseek(f1, 0, SEEK_END);
  110.    file_end = ftell(f1);
  111.  
  112.    // La posición entregada está fuera del archivo
  113.    if(file_pos>file_end) {
  114.        puts("error, la position es demasiado alta");
  115.        fclose(f1);
  116.        return EXIT_FAILURE;
  117.    }
  118.    fseek(f1, file_pos, SEEK_SET);
  119.  
  120.    SetTermNoCanon( &saved_tm );
  121.  
  122.    while(c=getche()!=27) {
  123.        putc(c, f1);
  124.    }
  125.  
  126.    printf("Información: %s\n", argv[1]);
  127.    printf("---------------------------\n");
  128.    printf("Tamaño: \t \t %d bytes\n", stat1->st_size);
  129.    printf("Links: \t%d\n", stat1->st_nlink);
  130.    printf("inode: \t \t %d\n", stat1->st_ino);
  131.  
  132.    fclose(f1);
  133.  
  134.    return EXIT_SUCCESS;
  135. }
  136.