Forma canonica

Iniciado por txiki481, 23 Abril 2018, 21:40 PM

0 Miembros y 1 Visitante están viendo este tema.

txiki481

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.

MAFUS

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...

txiki481

de la forma de unix como seria

MAFUS


txiki481

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);
    }
}

MAFUS

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;
}