Inicio do exercicio da Aula 15 #26

Open
opened 2025-06-18 21:37:10 -03:00 by fsilva · 3 comments

Objetivo: Criar um programa que recebe 1 ou 2 argumentos. Sendo um dos argumentos uma opção e o outro o nome de um arquivo.
Opções:
-o = escrever do zero (w)
-a = abrir com modo (a)
padrão vale o w, existente.

Esboço do programa criado em sala:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define F_NEW       0
#define F_OVERWRITE 1
#define F_APPEND    2

int parse_args(char *args[], int size) {

        if (size < 2) {
                fprintf(stderr, "./hdoc [OPÇÕES|-o/-a] [ARQUIVO] \n");
                exit(EXIT_FAILURE);
        } else if (size == 2) {
                return F_NEW;
        } else if (size > 3) {
                fprintf(stderr, "Invalid number of args");
                exit(EXIT_FAILURE);
        }

        for (int i=1;args[i] != NULL;i++) {
                if (strcmp(args[i], "-o") == 0) {
                        return F_OVERWRITE;
                } else if (strcmp(args[i], "-a") == 0) {
                        return F_APPEND;
                } else {
                        fprintf(stderr, "Invalid arg");
                        exit(EXIT_FAILURE);
                }
        }
}

// hdoc arquivo
// hdoc -o arquivo
int main(int argc, char **argv) {


        switch (parse_args(argv, argc)) {
                case F_NEW:

                case F_OVERWRITE:
                case F_APPEND:
                default:
        }

        char line [BUFSIZ];
        char *file = argv[1];


        if (access(file, F_OK) == 0) {
                fprintf(stderr, "File exists!\n");
                return EXIT_FAILURE;
        }

        FILE *fstr = fopen(file, "w");

        if (!fstr) {
                perror("fopen");
                return EXIT_FAILURE;
        }

        while (fgets(line, BUFSIZ, stdin) != NULL) {
                fprintf(fstr ,"%s", line);
        }

        fclose(fstr);

        return EXIT_SUCCESS;
} 

**Objetivo**: Criar um programa que recebe 1 ou 2 argumentos. Sendo um dos argumentos uma opção e o outro o nome de um arquivo. Opções: -o = escrever do zero (w) -a = abrir com modo (a) padrão vale o w, existente. Esboço do programa criado em sala: ```c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #define F_NEW 0 #define F_OVERWRITE 1 #define F_APPEND 2 int parse_args(char *args[], int size) { if (size < 2) { fprintf(stderr, "./hdoc [OPÇÕES|-o/-a] [ARQUIVO] \n"); exit(EXIT_FAILURE); } else if (size == 2) { return F_NEW; } else if (size > 3) { fprintf(stderr, "Invalid number of args"); exit(EXIT_FAILURE); } for (int i=1;args[i] != NULL;i++) { if (strcmp(args[i], "-o") == 0) { return F_OVERWRITE; } else if (strcmp(args[i], "-a") == 0) { return F_APPEND; } else { fprintf(stderr, "Invalid arg"); exit(EXIT_FAILURE); } } } // hdoc arquivo // hdoc -o arquivo int main(int argc, char **argv) { switch (parse_args(argv, argc)) { case F_NEW: case F_OVERWRITE: case F_APPEND: default: } char line [BUFSIZ]; char *file = argv[1]; if (access(file, F_OK) == 0) { fprintf(stderr, "File exists!\n"); return EXIT_FAILURE; } FILE *fstr = fopen(file, "w"); if (!fstr) { perror("fopen"); return EXIT_FAILURE; } while (fgets(line, BUFSIZ, stdin) != NULL) { fprintf(fstr ,"%s", line); } fclose(fstr); return EXIT_SUCCESS; } ```
Owner

Minha solução...

Não mudei quase nada da ideia de vocês na aula, só apliquei as minhas sugestões:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

typedef enum {
    OPT_ERROR = -1,
    OPT_NAME,
    OPT_OVERWRITE,
    OPT_APPEND,
    OPT_HELP
} Option;

int print_usage(int status, char *prog_name) {
    FILE *stream = stderr;
    if (status == EXIT_SUCCESS) stream = stdout;
    fprintf(stream, "Uso: %s [-a|-o|-h] arquivo\n", prog_name);
    return status;
}

int parse_arg(char *arg) {
    // Argumento iniciado com '-'...
    if (arg[0] == '-') {
        if (strcmp(arg, "-a") == 0) {
            return OPT_APPEND;
        } else if (strcmp(arg, "-o") == 0) {
            return OPT_OVERWRITE;
        } else if (strcmp(arg, "-h") == 0) {
            return OPT_HELP;
        } else {
            // Argumento inválido!
            return OPT_ERROR;
        }
    }
    // Sem traço é nome de arquivo...
    return OPT_NAME;
}

int main(int argc, char **argv) {
    
    char *file = NULL;
    char *mode = NULL;

    // Verificação do número de argumentos...
    if (argc == 1 || argc > 3) {
        // Só pode haver 2 ou 3 argumentos...
        fprintf(stderr, "Número incorreto de argumentos!\n");
        return print_usage(EXIT_FAILURE, argv[0]);
    } else if (argc == 2) {
        // Invocação com 2 argumentos...
        switch (parse_arg(argv[1])) {
            case OPT_HELP:
                // Imprime ajuda e termina...
                return print_usage(EXIT_SUCCESS, argv[0]);
            case OPT_NAME:
                // Arquivo existe?
                if (access(argv[1], F_OK) == 0) {
                    // Sem opções, só arquivos novos!
                    fprintf(stderr, "Arquivo já existe!\n");
                    return print_usage(EXIT_FAILURE, argv[0]);
                }
                // Nome do novo arquivo...
                file = argv[1];
                mode = "w";
                break;
            default:
                // Nome do arquivo não pode começar com '-'!
                fprintf(stderr, "Argumento inválido!\n");
                return print_usage(EXIT_FAILURE, argv[0]);
        }
    } else {
        // Invocação com 3 argumentos...
        for (int i = 1; argv[i] != NULL; i++) {
            switch (parse_arg(argv[i])) {
                case OPT_NAME:
                    // Só pode haver uma definição de nome...
                    if (file == NULL) file = argv[i];
                    break;
                case OPT_OVERWRITE:
                    // Só pode haver uma definição de modo...
                    if (mode == NULL) mode = "w";
                    break;
                case OPT_APPEND:
                    // Só pode haver uma definição de modo...
                    if (mode == NULL) mode = "a";
                    break;
                case OPT_HELP:
                    // Exibe ajuda e termina com sucesso...
                    return print_usage(EXIT_SUCCESS, argv[0]);
                case OPT_ERROR:
                    // Algum dos argumentos é inválido...
                    fprintf(stderr, "Argumento inválido (%s)!\n", argv[i]);
                    return print_usage(EXIT_FAILURE, argv[0]);
            }
        }
        // Tem que haver um nome e um modo depois do loop...
        if (file == NULL || mode == NULL) {
            fprintf(stderr, "Argumentos incorretos: %s - %s!\n", mode, file);
            return print_usage(EXIT_FAILURE, argv[0]);
        }
    }
    
    FILE *fstr = fopen(file, mode);
    if (!fstr) {
        perror("fopen");
        return EXIT_FAILURE;
    }
    
    char line[BUFSIZ];
    while (fgets(line, BUFSIZ, stdin) != NULL) {
        fprintf(fstr, "%s", line);
    }

    fclose(fstr);

    return EXIT_SUCCESS;
}

Compilação e testes:

:~$ gcc -Wall hdoc.c -o hdoc
:~$ ./hdoc
Número incorreto de argumentos!
Uso: ./hdoc [-a|-o|-h] arquivo
:~$ ./hdoc -h
Uso: ./hdoc [-a|-o|-h] arquivo
:~$ ./hdoc -a
Argumento inválido!
Uso: ./hdoc [-a|-o|-h] arquivo
:~$ ./hdoc teste.txt
banana
laranja
abacate
:~$ cat teste.txt
banana
laranja
abacate
:~$ ./hdoc teste.txt -a
salada mista
:~$ cat teste.txt
banana
laranja
abacate
salada mista
:~$ ./hdoc teste.txt -o
zebra
leão
tigre
:~$ cat teste.txt
zebra
leão
tigre
:~$ ./hdoc teste.txt -h
Uso: ./hdoc [-a|-o|-h] arquivo
:~$ ./hdoc -h teste.txt
Uso: ./hdoc [-a|-o|-h] arquivo
:~$ ./hdoc -a teste.txt
arg antes do nome
:~$ cat teste.txt
zebra
leão
tigre
arg antes do nome
:~$ ./hdoc teste.txt
Arquivo já existe!
Uso: ./hdoc [-a|-o|-h] arquivo

O ponto principal que eu observo é a falta de método. Veja, eu só começo a escrever quando tenho um esboço decidido, mesmo que tenha que mudar ao longo da implementação, por exemplo...

Função parse_arg:

  • Recebe apenas a string do argumento testado;
  • Retorna o que determinar sobre o argumento (enum Option);
  • Retorno será usado em um switch-case e comparado com as constantes da enum.
  • Argumento iniciado com traço só pode ser -a, -q ou -h;
  • Qualquer coisa diferente depois de '-' é erro;
  • Sem traço, é nome de arquivo.

Implementação:

#include <string.h>

/* ... */

typedef enum {
    OPT_ERROR = -1,
    OPT_NAME,
    OPT_OVERWRITE,
    OPT_APPEND,
    OPT_HELP
} Option;

/* ... */

int parse_arg(char *arg) {
    // Argumento iniciado com '-'...
    if (arg[0] == '-') {
        if (strcmp(arg, "-a") == 0) {
            return OPT_APPEND;
        } else if (strcmp(arg, "-o") == 0) {
            return OPT_OVERWRITE;
        } else if (strcmp(arg, "-h") == 0) {
            return OPT_HELP;
        } else {
            // Argumento inválido!
            return OPT_ERROR;
        }
    }
    // Sem traço é nome de arquivo...
    return OPT_NAME;
}

Ações dependentes da quantidade de argumentos...

  • Se argc for igual a 1 ou maior que 3: termina com erro.

  • Se argc for igual a 2, o argumento só pode ser -h ou o nome do arquivo.

    • Testar com parse_arg e switch:
      • Se for -h, imprime ajuda e sai com sucesso;
      • Se iniciar com -, sai com erro;
      • Se for o nome do arquivo, testar se já existe:
        • Se existir, sai com erro;
        • Se não existir, define char *file e char *mode ("w").

Implementação:

    if (argc == 1 || argc > 3) {
        // Só pode haver 2 ou 3 argumentos...
        fprintf(stderr, "Número incorreto de argumentos!\n");
        return print_usage(EXIT_FAILURE, argv[0]);
    } else if (argc == 2) {
        // Invocação com 2 argumentos...
        switch (parse_arg(argv[1])) {
            case OPT_HELP:
                // Imprime ajuda e termina...
                return print_usage(EXIT_SUCCESS, argv[0]);
            case OPT_NAME:
                // Arquivo existe?
                if (access(argv[1], F_OK) == 0) {
                    // Sem opções, só arquivos novos!
                    fprintf(stderr, "Arquivo já existe!\n");
                    return print_usage(EXIT_FAILURE, argv[0]);
                }
                // Nome do novo arquivo...
                file = argv[1];
                mode = "w";
                break;
            default:
                // Nome do arquivo não pode começar com '-'!
                fprintf(stderr, "Argumento inválido!\n");
                return print_usage(EXIT_FAILURE, argv[0]);
        }
    } else {
        // 3 argumentos...
    }
  • Se argc for igual a 3, testar cada opção (em loop).
    • Testar em um switch comparando com o retorno de parse_arg.
    • Requisito: ao final, só pode haver uma definição de nome e modo (quem aparecer primeiro);
      • Se for o nome do arquivo, define char *file se ainda não definido (file = NULL);
      • Se for -o, define o modo como "w", se ainda não definido (mode = NULL);
      • Se for -a, define o modo como "a", se ainda não definido (mode = NULL);
      • Se for -h, imprime ajuda e termina com sucesso;
      • Se for erro (argumento inválido começado com traço), termina com erro.
    • Depois do loop, testar se nome e modo foram definidos:
      • Se ainda forem NULL, termina com erro.

Implementação:

    if (argc == 1 || argc > 3) {
        // Só pode haver 2 ou 3 argumentos...
    } else if (argc == 2) {
        // Invocação com 2 argumentos...
        }
    } else {
        // Invocação com 3 argumentos...
        for (int i = 1; argv[i] != NULL; i++) {
            switch (parse_arg(argv[i])) {
                case OPT_NAME:
                    // Só pode haver uma definição de nome...
                    if (file == NULL) file = argv[i];
                    break;
                case OPT_OVERWRITE:
                    // Só pode haver uma definição de modo...
                    if (mode == NULL) mode = "w";
                    break;
                case OPT_APPEND:
                    // Só pode haver uma definição de modo...
                    if (mode == NULL) mode = "a";
                    break;
                case OPT_HELP:
                    // Exibe ajuda e termina com sucesso...
                    return print_usage(EXIT_SUCCESS, argv[0]);
                case OPT_ERROR:
                    // Algum dos argumentos é inválido...
                    fprintf(stderr, "Argumento inválido (%s)!\n", argv[i]);
                    return print_usage(EXIT_FAILURE, argv[0]);
            }
        }
        // Tem que haver um nome e um modo depois do loop...
        if (file == NULL || mode == NULL) {
            fprintf(stderr, "Argumentos incorretos: %s - %s!\n", mode, file);
            return print_usage(EXIT_FAILURE, argv[0]);
        }
    }

Reparem que os comentários correspondem ao meu plano de ação, pois eles foram escritos antes de qualquer código!

Melhorias interessantes

  • Exibir a mensagem: "Tecle Ctrl+D para terminar...\n";
  • Exibir o prompt "> " no início de cada linha;
  • Talvez, dar a opção de terminar com uma linha contendo apenas ":q".
Minha solução... Não mudei quase nada da ideia de vocês na aula, só apliquei as minhas sugestões: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> typedef enum { OPT_ERROR = -1, OPT_NAME, OPT_OVERWRITE, OPT_APPEND, OPT_HELP } Option; int print_usage(int status, char *prog_name) { FILE *stream = stderr; if (status == EXIT_SUCCESS) stream = stdout; fprintf(stream, "Uso: %s [-a|-o|-h] arquivo\n", prog_name); return status; } int parse_arg(char *arg) { // Argumento iniciado com '-'... if (arg[0] == '-') { if (strcmp(arg, "-a") == 0) { return OPT_APPEND; } else if (strcmp(arg, "-o") == 0) { return OPT_OVERWRITE; } else if (strcmp(arg, "-h") == 0) { return OPT_HELP; } else { // Argumento inválido! return OPT_ERROR; } } // Sem traço é nome de arquivo... return OPT_NAME; } int main(int argc, char **argv) { char *file = NULL; char *mode = NULL; // Verificação do número de argumentos... if (argc == 1 || argc > 3) { // Só pode haver 2 ou 3 argumentos... fprintf(stderr, "Número incorreto de argumentos!\n"); return print_usage(EXIT_FAILURE, argv[0]); } else if (argc == 2) { // Invocação com 2 argumentos... switch (parse_arg(argv[1])) { case OPT_HELP: // Imprime ajuda e termina... return print_usage(EXIT_SUCCESS, argv[0]); case OPT_NAME: // Arquivo existe? if (access(argv[1], F_OK) == 0) { // Sem opções, só arquivos novos! fprintf(stderr, "Arquivo já existe!\n"); return print_usage(EXIT_FAILURE, argv[0]); } // Nome do novo arquivo... file = argv[1]; mode = "w"; break; default: // Nome do arquivo não pode começar com '-'! fprintf(stderr, "Argumento inválido!\n"); return print_usage(EXIT_FAILURE, argv[0]); } } else { // Invocação com 3 argumentos... for (int i = 1; argv[i] != NULL; i++) { switch (parse_arg(argv[i])) { case OPT_NAME: // Só pode haver uma definição de nome... if (file == NULL) file = argv[i]; break; case OPT_OVERWRITE: // Só pode haver uma definição de modo... if (mode == NULL) mode = "w"; break; case OPT_APPEND: // Só pode haver uma definição de modo... if (mode == NULL) mode = "a"; break; case OPT_HELP: // Exibe ajuda e termina com sucesso... return print_usage(EXIT_SUCCESS, argv[0]); case OPT_ERROR: // Algum dos argumentos é inválido... fprintf(stderr, "Argumento inválido (%s)!\n", argv[i]); return print_usage(EXIT_FAILURE, argv[0]); } } // Tem que haver um nome e um modo depois do loop... if (file == NULL || mode == NULL) { fprintf(stderr, "Argumentos incorretos: %s - %s!\n", mode, file); return print_usage(EXIT_FAILURE, argv[0]); } } FILE *fstr = fopen(file, mode); if (!fstr) { perror("fopen"); return EXIT_FAILURE; } char line[BUFSIZ]; while (fgets(line, BUFSIZ, stdin) != NULL) { fprintf(fstr, "%s", line); } fclose(fstr); return EXIT_SUCCESS; } ``` Compilação e testes: ``` :~$ gcc -Wall hdoc.c -o hdoc :~$ ./hdoc Número incorreto de argumentos! Uso: ./hdoc [-a|-o|-h] arquivo :~$ ./hdoc -h Uso: ./hdoc [-a|-o|-h] arquivo :~$ ./hdoc -a Argumento inválido! Uso: ./hdoc [-a|-o|-h] arquivo :~$ ./hdoc teste.txt banana laranja abacate :~$ cat teste.txt banana laranja abacate :~$ ./hdoc teste.txt -a salada mista :~$ cat teste.txt banana laranja abacate salada mista :~$ ./hdoc teste.txt -o zebra leão tigre :~$ cat teste.txt zebra leão tigre :~$ ./hdoc teste.txt -h Uso: ./hdoc [-a|-o|-h] arquivo :~$ ./hdoc -h teste.txt Uso: ./hdoc [-a|-o|-h] arquivo :~$ ./hdoc -a teste.txt arg antes do nome :~$ cat teste.txt zebra leão tigre arg antes do nome :~$ ./hdoc teste.txt Arquivo já existe! Uso: ./hdoc [-a|-o|-h] arquivo ``` O ponto principal que eu observo é a falta de método. Veja, eu só começo a escrever quando tenho um esboço decidido, mesmo que tenha que mudar ao longo da implementação, por exemplo... Função `parse_arg`: - Recebe apenas a string do argumento testado; - Retorna o que determinar sobre o argumento (`enum Option`); - Retorno será usado em um `switch-case` e comparado com as constantes da `enum`. - Argumento iniciado com traço só pode ser `-a`, `-q` ou `-h`; - Qualquer coisa diferente depois de `'-'` é erro; - Sem traço, é nome de arquivo. Implementação: ```c #include <string.h> /* ... */ typedef enum { OPT_ERROR = -1, OPT_NAME, OPT_OVERWRITE, OPT_APPEND, OPT_HELP } Option; /* ... */ int parse_arg(char *arg) { // Argumento iniciado com '-'... if (arg[0] == '-') { if (strcmp(arg, "-a") == 0) { return OPT_APPEND; } else if (strcmp(arg, "-o") == 0) { return OPT_OVERWRITE; } else if (strcmp(arg, "-h") == 0) { return OPT_HELP; } else { // Argumento inválido! return OPT_ERROR; } } // Sem traço é nome de arquivo... return OPT_NAME; } ``` Ações dependentes da quantidade de argumentos... - Se `argc` for igual a 1 ou maior que 3: termina com erro. - Se `argc` for igual a 2, o argumento só pode ser `-h` ou o nome do arquivo. - Testar com `parse_arg` e `switch`: - Se for `-h`, imprime ajuda e sai com sucesso; - Se iniciar com `-`, sai com erro; - Se for o nome do arquivo, testar se já existe: - Se existir, sai com erro; - Se não existir, define `char *file` e `char *mode` (`"w"`). Implementação: ```c if (argc == 1 || argc > 3) { // Só pode haver 2 ou 3 argumentos... fprintf(stderr, "Número incorreto de argumentos!\n"); return print_usage(EXIT_FAILURE, argv[0]); } else if (argc == 2) { // Invocação com 2 argumentos... switch (parse_arg(argv[1])) { case OPT_HELP: // Imprime ajuda e termina... return print_usage(EXIT_SUCCESS, argv[0]); case OPT_NAME: // Arquivo existe? if (access(argv[1], F_OK) == 0) { // Sem opções, só arquivos novos! fprintf(stderr, "Arquivo já existe!\n"); return print_usage(EXIT_FAILURE, argv[0]); } // Nome do novo arquivo... file = argv[1]; mode = "w"; break; default: // Nome do arquivo não pode começar com '-'! fprintf(stderr, "Argumento inválido!\n"); return print_usage(EXIT_FAILURE, argv[0]); } } else { // 3 argumentos... } ``` - Se `argc` for igual a 3, testar cada opção (em loop). - Testar em um `switch` comparando com o retorno de `parse_arg`. - Requisito: ao final, só pode haver uma definição de nome e modo (quem aparecer primeiro); - Se for o nome do arquivo, define `char *file` se ainda não definido (`file = NULL`); - Se for `-o`, define o modo como `"w"`, se ainda não definido (`mode = NULL`); - Se for `-a`, define o modo como `"a"`, se ainda não definido (`mode = NULL`); - Se for `-h`, imprime ajuda e termina com sucesso; - Se for erro (argumento inválido começado com traço), termina com erro. - Depois do loop, testar se nome e modo foram definidos: - Se ainda forem `NULL`, termina com erro. Implementação: ```c if (argc == 1 || argc > 3) { // Só pode haver 2 ou 3 argumentos... } else if (argc == 2) { // Invocação com 2 argumentos... } } else { // Invocação com 3 argumentos... for (int i = 1; argv[i] != NULL; i++) { switch (parse_arg(argv[i])) { case OPT_NAME: // Só pode haver uma definição de nome... if (file == NULL) file = argv[i]; break; case OPT_OVERWRITE: // Só pode haver uma definição de modo... if (mode == NULL) mode = "w"; break; case OPT_APPEND: // Só pode haver uma definição de modo... if (mode == NULL) mode = "a"; break; case OPT_HELP: // Exibe ajuda e termina com sucesso... return print_usage(EXIT_SUCCESS, argv[0]); case OPT_ERROR: // Algum dos argumentos é inválido... fprintf(stderr, "Argumento inválido (%s)!\n", argv[i]); return print_usage(EXIT_FAILURE, argv[0]); } } // Tem que haver um nome e um modo depois do loop... if (file == NULL || mode == NULL) { fprintf(stderr, "Argumentos incorretos: %s - %s!\n", mode, file); return print_usage(EXIT_FAILURE, argv[0]); } } ``` > Reparem que os comentários correspondem ao meu plano de ação, pois eles foram escritos antes de qualquer código! ## Melhorias interessantes - Exibir a mensagem: `"Tecle Ctrl+D para terminar...\n"`; - Exibir o prompt `"> "` no início de cada linha; - Talvez, dar a opção de terminar com uma linha contendo apenas `":q"`.

Resolvi o exercício mas não segui todos os requisitos.

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

#define ARGS_MIN 2
#define ARGS_MAX 3

#define F_NEW       "w+"
#define F_OVERWRITE "w"
#define F_APPEND    "a"

char *parse_args(char *args[], int *size_args){
  int size = *size_args;
  int index = 1;
 
  if(size == ARGS_MIN)
  {
   /* Caso tenha dois argumentos, o segundo não pode começar com a opção '-' */
    if(args[index][0] == '-')
    {
      fprintf(stderr, "./hdoc [OPÇÕES|-o/-a] [ARQUIVO] \n");
      return NULL;
    }

     /* Atribui o posição que contém o nome para o arquivo de saída */
    *size_args -= 1;
    return F_NEW;
  }
  else if(size > ARGS_MAX)
  {
    fprintf(stderr, "Invalid number of args\n");
    return NULL;
  }

  /* O program aceita '-o' ou '-a' no primeiro ou último parâmetro */
  for(int i = 1; i < size; i++)
  {
    if (strcmp(args[i], "-o") == 0)
    { 
      *size_args = ++index;
      return F_OVERWRITE;  
    }
    else if(strcmp(args[i], "-a") == 0)
    {
      *size_args = ++index;
      return F_APPEND;
    }
    --index;
  }

  fprintf(stderr, "Invalid arg\n");
  return NULL;
}

int write_file(char **argv, int size, char *mode){
  char line [BUFSIZ];
  char *file = argv[size];

 /* Verifica se o arquivo existe, mas caso tenha a opção '-o' ou '-a' ele pode acessar */
  if ((access(file, F_OK) == 0 && strcmp(mode, "w")) && strcmp(mode, "a")) {
          fprintf(stderr, "File exists!\n");
          return EXIT_FAILURE;
  }  

  FILE *fstr = fopen(file, mode);
  
  if (!fstr)
  {
    perror("fopen");
    return EXIT_FAILURE;
  }

  while(fgets(line, BUFSIZ, stdin) != NULL) 
  {
    fprintf(fstr ,"%s", line);
  }

  fclose(fstr);
  return EXIT_SUCCESS;
}

int main(int argc, char *argv[]){
  
  char *mode = parse_args(argv, &argc);

  if(mode == NULL)
    exit(EXIT_FAILURE);
  
  return write_file(argv, argc, mode);
}

Saídas:

$ gcc -Wall cblc2_hdoc.c -o hdoc 
$ ./hdoc 
Invalid arg

$ ./hdoc -a
./hdoc [OPÇÕES|-o/-a] [ARQUIVO] 

$ ./hdoc teste.txt
banana
laranja
$ cat teste.txt
banana
laranja

$ ./hdoc teste.txt -a
salada mista
$ cat teste.txt
banana
laranja
salada mista

$  ./hdoc teste.txt -o
zebra
leão
$ cat teste.txt
zebra
leão

$ ./hdoc -a teste.txt
banana e laranja
$ cat teste.txt
zebra
leão
banana e laranja

$ ./hdoc -o teste.txt
tudo limpo!
42
$ cat teste.txt
tudo limpo!
42
Resolvi o exercício mas não segui todos os requisitos. ```c #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #define ARGS_MIN 2 #define ARGS_MAX 3 #define F_NEW "w+" #define F_OVERWRITE "w" #define F_APPEND "a" char *parse_args(char *args[], int *size_args){ int size = *size_args; int index = 1; if(size == ARGS_MIN) { /* Caso tenha dois argumentos, o segundo não pode começar com a opção '-' */ if(args[index][0] == '-') { fprintf(stderr, "./hdoc [OPÇÕES|-o/-a] [ARQUIVO] \n"); return NULL; } /* Atribui o posição que contém o nome para o arquivo de saída */ *size_args -= 1; return F_NEW; } else if(size > ARGS_MAX) { fprintf(stderr, "Invalid number of args\n"); return NULL; } /* O program aceita '-o' ou '-a' no primeiro ou último parâmetro */ for(int i = 1; i < size; i++) { if (strcmp(args[i], "-o") == 0) { *size_args = ++index; return F_OVERWRITE; } else if(strcmp(args[i], "-a") == 0) { *size_args = ++index; return F_APPEND; } --index; } fprintf(stderr, "Invalid arg\n"); return NULL; } int write_file(char **argv, int size, char *mode){ char line [BUFSIZ]; char *file = argv[size]; /* Verifica se o arquivo existe, mas caso tenha a opção '-o' ou '-a' ele pode acessar */ if ((access(file, F_OK) == 0 && strcmp(mode, "w")) && strcmp(mode, "a")) { fprintf(stderr, "File exists!\n"); return EXIT_FAILURE; } FILE *fstr = fopen(file, mode); if (!fstr) { perror("fopen"); return EXIT_FAILURE; } while(fgets(line, BUFSIZ, stdin) != NULL) { fprintf(fstr ,"%s", line); } fclose(fstr); return EXIT_SUCCESS; } int main(int argc, char *argv[]){ char *mode = parse_args(argv, &argc); if(mode == NULL) exit(EXIT_FAILURE); return write_file(argv, argc, mode); } ``` **Saídas:** ```c $ gcc -Wall cblc2_hdoc.c -o hdoc $ ./hdoc Invalid arg $ ./hdoc -a ./hdoc [OPÇÕES|-o/-a] [ARQUIVO] $ ./hdoc teste.txt banana laranja $ cat teste.txt banana laranja $ ./hdoc teste.txt -a salada mista $ cat teste.txt banana laranja salada mista $ ./hdoc teste.txt -o zebra leão $ cat teste.txt zebra leão $ ./hdoc -a teste.txt banana e laranja $ cat teste.txt zebra leão banana e laranja $ ./hdoc -o teste.txt tudo limpo! 42 $ cat teste.txt tudo limpo! 42 ```
Author

Acabei refazendo tbm e decidi usar uma abordagem diferente:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

// hdoc arquivo
// hdoc -o arquivo
int main(int argc, char **argv) {

	char *file = NULL;
	char *mode = NULL;

	switch (argc) {
		case 2:
			file = argv[1];
			if (access(file, F_OK) == 0) {
				fprintf(stderr, "File exists!\n");
				exit(EXIT_FAILURE);
			}

			mode = "w";
			break;
		case 3:

			int flag = 0;

			for (int i=1;args[i] != NULL;i++) {
				if (strcmp(args[i], "-o") == 0) {
					*mode = "w";
					flag = 1;
				} else if (strcmp(args[i], "-a") == 0) {
					*mode = "a";
					flag = 1;
				} else {
					*file = args[i];
				}
			}

			if (flag == 0) {
				fprintf(stderr, "./hdoc [OPÇÕES|-o/-a] [ARQUIVO] \n");
				exit(EXIT_FAILURE);
			}

			break;
		default:
			fprintf(stderr, "./hdoc [OPÇÕES|-o/-a] [ARQUIVO] \n");
			exit(EXIT_FAILURE);
	}

	char line [BUFSIZ];
	FILE *fstr = fopen(file, mode);

	if (!fstr) {
		fprintf(stderr, "File does not open \n");
		exit(EXIT_FAILURE);
	}

	while (fgets(line, BUFSIZ, stdin) != NULL) {
		fprintf(fstr ,"%s", line);
	}

	fclose(fstr);

	return EXIT_SUCCESS;
} 
Acabei refazendo tbm e decidi usar uma abordagem diferente: ```c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> // hdoc arquivo // hdoc -o arquivo int main(int argc, char **argv) { char *file = NULL; char *mode = NULL; switch (argc) { case 2: file = argv[1]; if (access(file, F_OK) == 0) { fprintf(stderr, "File exists!\n"); exit(EXIT_FAILURE); } mode = "w"; break; case 3: int flag = 0; for (int i=1;args[i] != NULL;i++) { if (strcmp(args[i], "-o") == 0) { *mode = "w"; flag = 1; } else if (strcmp(args[i], "-a") == 0) { *mode = "a"; flag = 1; } else { *file = args[i]; } } if (flag == 0) { fprintf(stderr, "./hdoc [OPÇÕES|-o/-a] [ARQUIVO] \n"); exit(EXIT_FAILURE); } break; default: fprintf(stderr, "./hdoc [OPÇÕES|-o/-a] [ARQUIVO] \n"); exit(EXIT_FAILURE); } char line [BUFSIZ]; FILE *fstr = fopen(file, mode); if (!fstr) { fprintf(stderr, "File does not open \n"); exit(EXIT_FAILURE); } while (fgets(line, BUFSIZ, stdin) != NULL) { fprintf(fstr ,"%s", line); } fclose(fstr); return EXIT_SUCCESS; } ```
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
3 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: blau_araujo/cblc#26
No description provided.