Test Foro de elhacker.net SMF 2.1

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í:
#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>

// Sacado de https://stackoverflow.com/questions/7469139/what-is-equivalent-to-getch-getche-in-linux
static struct termios old, new;

/* Initialize new terminal i/o settings */
void initTermios(int echo)  {
    tcgetattr(0, &old); /* grab old terminal i/o settings */
    new = old; /* make new settings same as old settings */
    new.c_lflag &= ~ICANON; /* disable buffered i/o */
    if (echo) {
        new.c_lflag |= ECHO; /* set echo mode */
    } else {
        new.c_lflag &= ~ECHO; /* set no echo mode */
    }
    tcsetattr(0, TCSANOW, &new); /* use these new terminal i/o settings now */
}

/* Restore old terminal i/o settings */
void resetTermios(void) {
    tcsetattr(0, TCSANOW, &old);
}

/* Read 1 character - echo defines echo mode */
char getch_(int echo) {
    char ch;
    initTermios(echo);
    ch = getchar();
    resetTermios();
    return ch;
}

/* Read 1 character without echo */
char getch(void) {
    return getch_(0);
}

/* Read 1 character with echo */
char getche(void) {
    return getch_(1);
}

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[]) {
    char c;
    int f;
    long file_end;
    long file_pos;
    char buff[BUFFER_TAMAINA];
    FILE *f1;
    struct stat stat1;

    // Voy a sustituir todos los write a stdout por printf o puts

    // Número de argumentos diferente al esperado
    if (argc != 3) {
        printf("Uso: %s [fichero] [posicion]", argv[0]);
        return EXIT_FAILURE;
    }

    file_pos = atol(argv[2]);

    // No se pueden los metadatos del archivo
    if(stat(argv[1], &statl) == -1) {
        puts("error, no se pueden recuperar datos del archivo");
        return EXIT_FAILURE;
    }

    // El argumento posición no es un número o es 0
    if(file_pos < 1) {
        puts("error, posicion debe ser un entero igual o mayor a 1");
        return EXIT_FAILURE;
    }

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

    // El archivo no existe o no se puede abrir
    if(!f1) {
        puts("error, el fichero no existe");
        return EXIT_FAILURE;
    }

    //- Sustituyo todo esto
    //   while(fgetc(f1)!=EOF) {
    //       k++;
    //   }
    //   fclose(f1);
    //- Por lo siguiente

    fflush(f1);
    fseek(f1, 0, SEEK_END);
    file_end = ftell(f1);

    // La posición entregada está fuera del archivo
    if(file_pos>file_end) {
        puts("error, la position es demasiado alta");
        fclose(f1);
        return EXIT_FAILURE;
    }
    fseek(f1, file_pos, SEEK_SET);

    SetTermNoCanon( &saved_tm );

    while(c=getche()!=27) {
        putc(c, f1);
    }

    printf("Información: %s\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);

    fclose(f1);
   
    return EXIT_SUCCESS;
}